COMMAND

    Mantrap

SYSTEMS AFFECTED

    Mantrap prior to and including 1.6.1

PROBLEM

    Following is based on Fate  Advisory.  ManTrap's intent is  to set
    up  a  honeypot  as  a  'cage'  which  can  be  filled  with  fake
    information running on  a system where  the intruder can  be lured
    and studied,  and which  is also  supposed to  prevent erasing  of
    logs etc.

    A great idea - but the implementation is poor.  Instead of running
    as a VMware like virtual machine or such, it just runs as a chroot
    like environment with some kernel patches, and thus it can  easily
    be identified and  subverted.  In  case an intruder  breaks in and
    finds out that it's a cage, he/she will most likely just trash  it
    and move  on instead  of fulfilling  the purpose  of staying  long
    enough to be studied/identified/traced.

    Problem 1:
    ==========
    ManTrap hides processes from the caged intruder (or atleast  tries
    to), by  hiding them  from the  /proc in  the cage (resembles what
    many LKM trojans do), which sounds fine.

    BUT, the cage still runs the SAME kernel as the real box, and also
    has access to all kernel memory etc.  So what we can do is to  use
    a syscall, in  this case kill(),  which gets its  information from
    the kernel  instead of  /proc, and  compare it's  results with the
    information in  /proc.   What we  do is  to simply  send a  signal
    (SIGCONT in this case) which hopefully shouldn't affect  anything,
    to PID 1 to 65535 as a nonroot user, and compare the results  with
    /proc.

    - kill() gives EPERM and /proc/<PID> exists -> Fine
    - kill() gives EPERM and /proc/<PID> does not exist -> Not fine!

    This can  also possibly  be used  to detect  LKM trojanss  and the
    like.  It might give a false alarm though, as some kernel  patches
    designed  to  hide  other  user's  processes  might  give the same
    result.  But  together with the  other tell-tale signs  of ManTrap
    it gives a very good fingerprint.

    Problem 2&3:
    ============
    This  looks  like  a  result  from  the  /proc filtering/emulation
    mentioned above. /proc/.. doesn't show up in any syscalls  wanting
    to get  the directory  listing! (such  as getdents()).   Also, (cd
    /proc/self; cd cwd; pwd) gives an error.  Another interesting note
    is that the whole  box can be made  to lock up and  disconnect all
    users for a couple of minutes by doing:

        # cd /proc && cd self && cd cwd
        # pwd <causes error response>
        # cd ../../../../../
        # cd proc
        # cd self <should receive error response>
        # ls, pwd, etc, <BOOM!>

    Problem 4:
    ==========
    ManTrap accidentally seems  to hide the  first 4 processes  always
    running on a Solaris box (sched, init, fsflush, pageout).

    Problem 5:
    ==========
    Since   /   isn't   the   real   root   of   the  filesystem,  but
    /usr/rti/cage/root, the inode number  is very off, usually  in the
    100000-200000 range instead of the normal 2.  This can be  checked
    by simply doing `ls -id /`.

    Problem 6:
    ==========
    If  the  intruder  got  root  in  the  cage, it's very possible to
    read/write directly to/from /dev/mem, the raw disk device[s], etc.
    The crash(1M) utility can be used to examine /dev/mem and get  the
    real process listing etc, which includes all ManTrap's  processes.
    (Yes, they can be killed...)

    More serious damage  can be caused  using the raw  disk device[s],
    such  as  /dev/rdsk/c0t0d0s0.   ANY  data  on  the  system  can be
    read/modified by the intruder, which can be used to wipe logs  and
    such.   An  utility  such  as  fsdb(1M)  can  be  used to view the
    directory listings etc.

    Fate Research Labs written a small program to demonstrate problems
    1-3.  It's capable of identifying ManTrap using these methods, and
    also list all 'hidden' processes.  It's available from

        http://www.f8labs.com

    This  basically  shows  that  you  can't  rely upon anything but a
    total  instruction-level  emulation  to  make  a  real-looking and
    yet secure cage.  We look forward to such a product as it would be
    a great tool in intrusion detection.  As VMware shows, this can be
    done atleast on x86 CPUs and  it would surprise me if it  wouldn't
    be possible on other platforms (such as Sparc).

    One key thing to take in mind when deploying a honeypot is to take
    special  care  in  the  architecture  of  the  deployment.   Place
    particular attention on where in  the network it is deployed.   It
    is reccomended that if an organization does deploy any  honeypots,
    the systems are firewalled off in a secured, second DMZ.

    The code:

     *  ManTrap detection/testing program by wilson / f8labs - www.f8labs.org
     */
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <strings.h>
    #include <unistd.h>
    #include <sys/signal.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <errno.h>
    #include <dirent.h>
    
    void check_proc_vs_kill(int listpids)
    {
      struct stat st;
      int i, counter;
      char buf[520];
    
      printf("proc-vs-kill() test: \n");
      fflush(0);
    
      if (geteuid() == 0)
      {
        printf("  Error: Running as root. NOT performing /proc-vs-kill() test.\n");
        return;
      }
    
      if (listpids == 1)
      {
        printf("Listing mismatching PIDs:\n");
      }
    
      counter = 0;
      for (i = 1; i < 65535; i ++)
      {
        if ((kill(i, SIGCONT) != 0) && (errno == EPERM)) /* send SIGCONT (which hopefully won't matter) to the process */
        {
          snprintf(buf, 511, "/proc/%d", i);
          if (stat(buf, &st) != 0)
          {
            counter ++;
            if (listpids == 1)
            {
              printf("%.5d ", i);
              if (counter%8 == 0)
              {
                printf("\n");
              }
            }
          }
        }
      }
      if (listpids == 1)
      {
        printf("\n");
      }
      if (counter == 0)
      {
        printf("  Normal: No mismatches found.\n");
      } else
      {
        printf("  ManTrap? %d mismatching PIDs found.\n", counter);
      }
    }
    
    void check_proc_dotdot()
    {
      DIR *procDIR;
      struct dirent *procdirent;
      int found;
    
      printf("dotdot test:\n");
      procDIR = opendir("/proc");
      if (procDIR == NULL)
      {
        printf("  Error: Couldn't open /proc while performing dotdot test.\n");
        return;
      }
      found = 0;
      procdirent = readdir(procDIR);
      while (procdirent != NULL)
      {
        if (strcmp(procdirent->d_name, "..") == 0)
        {
          found = 1;
          break;
        }
        procdirent = readdir(procDIR);
      }
      closedir(procDIR);
      if (found == 0)
      {
        printf("  ManTrap? /proc/.. not found in directory listing!\n");
      } else {
        printf("  Normal: /proc/.. found in directory listing.\n");
      }
    
    }
    
    void check_proc_cwdwalk()
    {
      char savedpwd[2048], newpwd[2048];
    
      printf("cwdwalk test:\n");
      if (getwd(savedpwd) == NULL)
      {
        printf("  Error: Couldn't get working directory while performing cwdwalk test.\n");
        return;
      }
    
      if (chdir("/proc/self") != 0)
      {
        printf("  Error: Couldn't chdir to /proc/self while performing cwdwalk test.\n");
        return;
      }
      if (chdir("cwd") != 0)
      {
        printf(" Error: Couldn't chdir to /proc/self/cwd while performing cwdwalk test.\n");
        return;
      }
      if (getwd(newpwd) == NULL)
      {
        printf("  ManTrap? getwd() failed after chdir to /proc/self/cwd.\n");
      } else {
        printf("  Normal: getwd() succeeded after chdir to /proc/self/cwd.\n");
      }
      chdir(savedpwd);
      return;
    }
    
    void usage(char *myname)
    {
      printf("Usage: %s <-a|-p|-l|-d|-c|-h>\n", myname);
      printf(" -a performs ALL tests\n");
      printf(" -p performs /proc-vs-kill() test\n");
      printf(" -l performs /proc-vs-kill() test and lists mismatching PIDs\n");
      printf(" -d performs /proc/.. test\n");
      printf(" -c performs /proc/self/cwd test\n");
      printf(" -h shows this help\n");
    }
    
    int main(int argc, char *argv[])
    {
      printf("ManTrap detection/testing program by wilson@f8labs.org - www.f8labs.org\n");
      if (argc != 2)
      {
        usage(argv[0]);
        exit(1);
      }
      if (strlen(argv[1]) != 2)
      {
        usage(argv[0]);
        exit(1);
      }
      switch(argv[1][1])
      {
        case 'a':
          check_proc_vs_kill(0);
          check_proc_dotdot();
          check_proc_cwdwalk();
          break;
        case 'p':
          check_proc_vs_kill(0);
          break;
        case 'l':
          check_proc_vs_kill(1);
          break;
        case 'd':
          check_proc_dotdot();
          break;
        case 'c':
          check_proc_cwdwalk();
          break;
        case 'h':
        default:
          usage(argv[0]);
          exit(1);
          break;
      }
      printf("Finished.\n");
    }

SOLUTION

    Vendor  has  addressed  all  issues  in  their  version 2.0 of the
    Mantrap software release,  which they released  last week.   It is
    advised for all users of Mantrap to contact Recourse  technologies
    for an upgrade.