Memory Forensics: Network and Registry - Malware Analyst’s Cookbook and DVD: Tools and Techniques for Fighting Malicious Code (2011)

Malware Analyst’s Cookbook and DVD: Tools and Techniques for Fighting Malicious Code (2011)

Chapter 17. Memory Forensics: Network and Registry

Almost all malware has some sort of networking capability, whether the purpose is to contact a command and control server, spread to other machines, or create a remote backdoor on the system. Because the Windows OS must be able to maintain state and pass packets to the correct process, it is no surprise that the API functions involved create all sorts of artifacts in memory. Likewise, most malware makes changes to the Registry for the purposes of surviving reboots, changing system settings, storing encryption keys, or storing command and control server addresses. This chapter discusses how you can analyze a memory dump to learn about malicious network and Registry-related activity that occurred on the system.

Recipe 18-1: Exploring Socket and Connection Objects

Sockets define endpoints for communications. Applications create sockets to initiate connections to remote servers and to listen on an interface for incoming connections. There are a few ways to create sockets:

· Direct from user mode: Applications can call the socket function from the Winsock21 API (ws2_32.dll).

· Indirect from user mode: Applications can call functions in libraries such as WinINet (wininet.dll), which provide wrappers around the Winsock2 functions.

· Direct from kernel mode: Kernel drivers can create sockets through the use of TDI (Transport Driver Interface), which is the primary interface to the transport stack used by higher-level components such as Winsock2.

This recipe gives you an introduction to the artifacts that are created in memory when an application uses sockets. It will lay the framework for investigating malware in the recipes that follow.

Socket and Connection Artifacts

When an application calls socket, it passes the following information:

· An address family (AF_INET for IPv4, AF_INET6 for IPv6)

· A type (SOCK_STREAM, SOCK_DGRAM, SOCK_RAW)

· A protocol (IPPROTO_TCP, IPPROTO_UDP, IPPROTO_IP, IPPROTO_ICMP)

After an application calls socket, the socket isn’t ready for use until the application calls bind (if the socket is for server use) or connect (if the socket is for client use). When an application calls bind or connect, it specifies the IP and port for the endpoint. A socket cannot work until it knows the IP and port. Therefore, it makes sense that the _ADDRESS_OBJECT (i.e., socket object) is allocated after the call to bind or connect rather than after the call to socket.

Figure 18-1 shows the sequence of API calls required to create a simple TCP server, and the relationship between those APIs and the artifacts in memory. Figure 18-2 shows the same relationship for a TCP client. For the entire source code, see the Windows sockets 2 reference on MSDN.

The diagrams show the following:

1. The server and client both start out with a call to socket, which causes the calling process to open a handle to \Device\Afd\Endpoint. This handle allows the user mode process to communicate with Afd.sys in kernel mode, which is the Auxiliary Function Driver for Winsock2. As you’ll learn in Recipe 18-3, this is not an optional handle—it must remain open for the duration of the socket’s lifetime, or the socket will become invalid.

2. The server calls bind (this is optional for the client), which results in the following artifacts:

· The calling process opens a handle to \Device\Tcp, \Device\Udp, or \Device\Ip depending on the protocol specified in the call to socket.

· Memory is allocated in the kernel for an _ADDRESS_OBJECT structure, and its members are filled in according to the parameters sent to socket and bind.

3. The client calls connect, which results in the same artifacts as discussed previously, in addition to the allocation of a _TCPT_OBJECT (i.e., connection object). For every connection established with a client, the server process will also become associated with a _TCPT_OBJECT and a new set of handles. These artifacts exist until the client and server applications call closesocket, at which time the handles are closed and the objects are released. The act of releasing an object does not mean the memory for the objects is immediately overwritten. Thus, you can expect to find traces of prior objects in memory long after the sockets have been used.

Figure 18-1: The relationship between socket APIs and the artifacts they create in memory (server side)

f1801.eps

Figure 18-2: The relationship between socket APIs and the artifacts they create in memory (client side)

f1802.eps

Socket and Connection Objects

The _ADDRESS_OBJECT and _TCPT_OBJECT are undocumented by Microsoft, but many people have reverse-engineered them in the past. Here is the variation used within the Volatility framework for Windows XP systems.

'_ADDRESS_OBJECT' : [ 0x68, { \

'Next' : [ 0x0, ['pointer', ['_ADDRESS_OBJECT']]], \

'LocalIpAddress' : [ 0x0c, ['unsigned long']], \

'LocalPort' : [ 0x30, ['unsigned short']], \

'Protocol' : [ 0x32, ['unsigned short']], \

'Pid' : [ 0x148, ['unsigned long']], \

'CreateTime' : [ 0x158, ['_LARGE_INTEGER']], \

} ], \

'_TCPT_OBJECT' : [ 0x20, { \

'Next' : [ 0x0, ['pointer', ['_TCPT_OBJECT']]], \

'RemoteIpAddress' : [ 0xc, ['unsigned long']], \

'LocalIpAddress' : [ 0x10, ['unsigned long']], \

'RemotePort' : [ 0x14, ['unsigned short']], \

'LocalPort' : [ 0x16, ['unsigned short']], \

'Pid' : [ 0x18, ['unsigned long']], \

} ], \

The first member of each object (named Next) is a pointer to the next object, thus creating a singly linked list of entries. The terminating entry has a Next value of zero. Therefore, one way to enumerate the existing sockets on the system is to find the start of the _ADDRESS_OBJECT list and follow the Next pointers until reaching one that is zero. Likewise, you could do the same thing with the _TCPT_OBJECT list in order to enumerate the open connections on a system.

In fact, this is how the sockets and connections commands in Volatility work. For either command, Volatility finds tcpip.sys in kernel memory and locates a global variable in the module’s .data section. For sockets, the variable that Volatility finds is named _AddrObjTable, which stores a pointer to the first _ADDRESS_OBJECT entry. For connections, it finds a variable named _TCBTable, which stores a pointer to the first _TCPT_OBJECT entry. Figure 18-3 shows a diagram of the enumeration procedure; you can find the corresponding source code in the volatility/win32/network.py file.

Figure 18-3: Diagram of locating the socket and connection objects in memory

f1803.eps

The next few recipes cover some practical investigations based on socket and connection objects, and discuss ways that malware can hide their network communications.

1 http://msdn.microsoft.com/en-us/library/ms740673%28VS.85%29.aspx

Recipe 18-2: Analyzing Network Artifacts Left by Zeus

The following command shows an example of using Volatility to print the sockets of a memory dump infected with Zeus malware.

$ python volatility.py sockets -f zeus.bin

Pid Port Proto Create Time

892 19705 6 Thu Feb 12 03:38:14 2009

740 500 17 Thu Sep 18 05:33:19 2008

4 139 6 Thu Dec 11 20:51:51 2008

4 445 6 Thu Sep 18 05:32:51 2008

972 135 6 Thu Sep 18 05:32:59 2008

4 137 17 Thu Dec 11 20:51:51 2008

1320 1029 6 Thu Sep 18 05:33:29 2008

1064 123 17 Thu Dec 11 20:51:52 2008

740 0 255 Thu Sep 18 05:33:19 2008

1112 1025 17 Thu Sep 18 05:33:28 2008

1112 1033 17 Thu Sep 18 05:42:19 2008

4 138 17 Thu Dec 11 20:51:51 2008

892 35335 6 Thu Feb 12 03:38:14 2009

1112 1115 17 Thu Dec 11 18:54:24 2008

1064 123 17 Thu Dec 11 20:51:52 2008

892 1277 6 Thu Feb 12 03:38:15 2009

1156 1900 17 Thu Dec 11 20:51:52 2008

740 4500 17 Thu Sep 18 05:33:19 2008

1064 1276 17 Thu Feb 12 03:38:12 2009

1064 1275 17 Thu Feb 12 03:38:12 2009

4 445 17 Thu Sep 18 05:32:51 2008

In the output, you can see the process ID of the owning process, the port, protocol, and creation time. To convert the numerical protocol into a more readable form like IPPROTO_TCP, see the Assigned Internet Protocol Numbers.2 Let’s begin the analysis by looking at the first entry (in bold at the top), showing that a process with Pid 892 is using TCP port 19705. Because an_ADDRESS_OBJECT is allocated for client and server sockets, you cannot tell if the process is listening for incoming connections on TCP port 19705 or if the process just established a TCP connection with a remote endpoint (for example, google.com:80) using 19705 as the source port.

One thing you know, however, is that ports below 1025 are typically reserved for servers. Ports above 1025 could be either ephemeral client ports or server ports for applications that do not have the required privileges to bind to ports in the lower ranges. Of course, there are always exceptions (such as RDP, which binds to TCP 3389 even if it has the privileges to bind to lower ports). Thus, you’ll need more information to distinguish the purpose of TCP 19705.

Let’s continue with what you know about ephemeral client ports—they increase by one until reaching the maximum (the actual ranges vary between operating system versions), at which point they wrap back around to 1025. If TCP19705 happens to be a client socket, then other processes on the system that created client sockets within a few seconds would be assigned a value close to 19705. Let’s place all the sockets created within the same time period in order based on the creation time and see if any evidence supports our theory.

Pid Port Proto Create Time

1064 1275 17 Thu Feb 12 03:38:12 2009

1064 1276 17 Thu Feb 12 03:38:12 2009

892 19705 6 Thu Feb 12 03:38:14 2009

892 35335 6 Thu Feb 12 03:38:14 2009

892 1277 6 Thu Feb 12 03:38:15 2009

You can see that at 03:38:12, the system assigned ports 1275 and 1276 to a process with Pid 1064. Three seconds later at 03:38:15, the system assigned port 1277 to a process with Pid 892. In between these events, at 03:38:14, you see sockets created with the extremely far-off numbers 19705 and 35335. This pattern indicates that the sockets with ports 1275, 1276, and 1277 are probably ephemeral client sockets, and sockets with ports 19705 and 35335 are server sockets. Furthermore, because the first two client sockets are using protocol 17 (UDP), they may be involved in making DNS requests.

You can investigate further by determining which processes are using these sockets and if there are any active connections. The following output shows that the sockets in question were created by two different instances of svchost.exe and that TCP1277 is, in fact, a client socket that is connected to port 80 of 91.207.117.254—an address in the Ukraine.

$ python volatility.py pslist -f zeus.vmem | grep 892

svchost.exe 892 728 26 294 Thu Sep 18 05:32:58 2008

$ python volatility.py pslist -f zeus.vmem | grep 1064

svchost.exe 1064 728 62 1235 Thu Sep 18 05:32:59 2008

$ python volatility.py connections -f zeus.vmem

Local Address Remote Address Pid

192.168.128.128:1277 91.207.117.254:80 892

As you learned in Recipe 9-6 (when you used HandleDiff.exe) and Recipe 16-6 (when you used the malfind Volatility plug-in), Zeus injects code into other processes to remain stealthy. Now you can see the effect of the code injection and how it makes svchost.exe appear responsible for Zeus’s network-related activities. Although there are no active connections for the TCP 19705 and TCP 35335 sockets, it’s probably just because the attackers had not yet initiated an incoming connection or the infected system happened to be behind a firewall and unreachable from the Internet. Although we’ve solved many pieces of the puzzle at this point, some questions remain unanswered. For example, what is the purpose of the listening TCP sockets? Do they provide a remote command shell (i.e. cmd.exe) or a SOCKS proxy that the attackers can use to route connections through the infected machine? These are questions that you must answer by extracting the malicious code from the memory dump and analyzing it statically in IDA Pro (see Chapter 17).

2 http://www.iana.org/assignments/protocol-numbers/protocol-numbers.xml

Recipe 18-3: Detecting Attempts to Hide TCP/IP Activity

There are a variety of ways to hide listening ports and active connections on a system. Table 18-1 summarizes a few possibilities and discusses how you can detect them in memory dumps using Volatility.

Table 18-1: Detecting Network Rootkits in Memory

Rootkit Technique

Memory Detection

Hook user mode APIs used by programs such as netstat.exe and TCPView.exe. Examples include DeviceIoControl, ZwDeviceIoControlFile, GetTcpTable, and GetExtendedTcpTable. The AFX3 rootkit works in this manner.

Use the apihooks plug-in for Volatility (see Chapter 17) to detect the hooks. Or, you can also just use the sockets or connections commands, since the rootkit’s API hooks aren’t effective when the system is not active.

Install a kernel driver that hooks the IRP_MJ_DEVICE_CONTROL function of \Device\Tcp (owned by tcpip.sys) and filter attempts to gather information using the IOCTL_TCP_QUERY_INFORMATION_EX code. Jamie Butler wrote a proof-of-concept rootkit4 that uses this method.

Use the driverirp plug-in for Volatility (see Recipe 17-5) or the sockets or connections commands.

Create your NDIS driver, which operates at a much lower level than Winsock2, thus bypassing the creation of common artifacts such as the socket and connection objects.

Focus on finding the loaded driver by scanning for driver objects or hidden kernel threads.

Scanning for Sockets and Connection Objects

Instead of walking the linked lists of socket and connection objects (as the sockets and connections commands do), the sockscan and connscan commands scan the memory dump looking for pools with the appropriate tag, size, and type (paged versus non-paged) and then apply a series of sanity checks, which you can explore by viewing code in the plugins/internal/connscan2.py and plugins/internal/sockscan.py source files. Thus, by using connscan and sockscan, you can potentially identify sockets and connections that were used by malware in the past.

DKOM attacks are not as much of a threat against socket and connection objects as they are for process objects (as discussed in Recipe 15-6). In other words, you probably won’t see malware trying to unlink or overwrite an _ADDRESS_OBJECT (to hide a listening socket) or a _TCPT_OBJECT (to hide an active connection). During our testing, we found that these objects must not be overwritten, or else the process’s ability to communicate over the network will fail. For example, we followed these steps to test:

1. Started two server instances of netcat for Windows, each listening on a different port:

C:\> nc.exe –l –p 9090

C:\> nc.exe –l –p 8080

2. Using a kernel debugger, we found the _AddrObjTable symbol on the machine running the netcat processes. As previously described, _AddrObjTable stores a pointer to the first _ADDRESS_OBJECT structure in the list.

kd> x *!_AddrObjTable

b2f3ba60 tcpip!AddrObjTable = <no type information>

kd> dd /c1 b2f3ba60

b2f3ba60 823342c8 ; Start of the _ADDRESS_OBJECT list

b2f3ba64 0000001f ; Size of the _ADDRESS_OBJECT list

3. Printed the values at the start of the _ADDRESS_OBJECT list.

kd> dd /c1 823342c8

823342c8 00000000 ; Invalid

823342cc 00000000 ; Invalid

823342d0 820bd4e8 ; _ADDRESS_OBJECT for the port 8080 nc.exe

823342d4 8213d5f0 ; _ADDRESS_OBJECT for the port 9090 nc.exe

4. Overwrote the _ADDRESS_OBJECT entry for the netcat process listening on port 8080. In the command that follows, ed replaces the 4 bytes at address 823342d0 with 0x00000000. Then we listed the values at the same addresses, shown in Step 3, to verify that the change took effect.

kd> ed 823342d0 0x00000000

kd> dd /c1 823342c8

823342c8 00000000 ; Invalid

823342cc 00000000 ; Invalid

823342d0 00000000 ; Invalid

823342d4 8213d5f0 ; _ADDRESS_OBJECT for the port 9090 nc.exe

5. Attempted to connect to the netcat listener on port 8080 (the attempt failed with no response).

6. Attempted to connect to the netcat listener on port 9090 (the attempt succeeded).

As a result of our testing, we know that it’s possible to perform DKOM on socket and connection objects without causing a full system crash or even disrupting the state of other networking applications. However, the target of the DKOM (in this case the nc.exe process listening on port 8080) will no longer be able to receive incoming connections.

Additional Artifacts

Most malware uses the Winsock2 API to avoid the complexities of writing a custom NDIS driver. As described in Figures 18-1 and 18-2, any use of this library to create sockets or connections results in various open handles to devices such as \Device\Afd\Endpoint and \Device\Tcp. These handles must remain open or the malware cannot send or receive data. If malware tries to close its handles to the devices for the purposes of covering its tracks, the next networking operation will result in exception C0000008 (invalid handle).

Therefore, another discrepancy that you can look for is any process with open handles to \Device\Afd\Endpoint and \Device\Tcp (using the files command in Volatility) but without any reported sockets or connections. Here are a few other artifacts that can help you identify processes with networking functionality:

· Open handles to the Internet Explorer history file index.dat (using the files command)

· Loaded DLLs such as wininet.dll, ws2_32.dll, and winsock.dll (using the dlllist command)

· Open handles to a mutex such as WininetConnectionMutex (using the mutantscan command)

3 http://www.rootkit.com/vault/therealaphex/AFXRootkit2005.zip

4 http://www.rootkit.com/vault/fuzen_op/TCPIRPHook.zip

Recipe 18-4: Detecting Raw Sockets and Promiscuous NICs

If a process is running with administrator privileges, it can enable raw sockets5 from user mode with the Winsock2 API. Raw sockets allow programs to access the underlying transport layer data (such as IP or TCP headers), which can allow malware to forge or spoof packets. Additionally, malware can use raw sockets in promiscuous mode to capture passwords transmitted by the infected machine or other hosts on the same subnet. Two factors mitigate the risk presented by raw sockets. First, starting with XP Service Pack 2, Windows prevents processes from sending TCP data over raw sockets and does not allow UDP datagrams to be sent using an invalid source address. Second, in order to capture packets sent to or from other hosts on the subnet, the network must be using a hub (which broadcasts frames/packets) or an unencrypted wireless connection.

Promiscious Mode Sockets

You can create a promiscuous mode socket with Winsock2 using the following steps:

1. Create a raw socket by specifying the SOCK_RAW and IPPROTO_IP flags to socket.

SOCKET s = socket(AF_INET, SOCK_RAW, IPPROTO_IP);

2. Set the port to 0 when initializing the sockaddr_in structure that you pass to bind.

struct sockaddr_in sa;

struct hostent *host = gethostbyname(the_hostname);

memset(&sa, 0, sizeof(sa));

memcpy(&sa.sin_addr.s_addr,

host->h_addr_list[in],

sizeof(sa.sin_addr.s_addr));

sa.sin_family = AF_INET;

sa.sin_port = 0;

bind(s, (struct sockaddr *)&sa, sizeof(sa));

3. Use the WSAIoctl or ioctlsocket functions with the SIO_RCVALL flag to enable promiscuous mode (i.e., “sniffing mode”) for the NIC associated with the socket.

int buf;

WSAIoctl(s, SIO_RCVALL, &buf, sizeof(buf),

0, 0, &in, 0, 0);

Detecting Promiscuous Mode

On a live Windows machine, you can use a tool called promiscdetect6 to detect the presence of a network card in promiscuous mode. To detect them in a memory dump, you can use the Volatility sockets or files commands. You don’t even need a plug-in! The artifacts left in memory, as shown in the previous three steps we described, create a certain set of artifacts that stand out like a sore thumb. See if you can spot the process with the raw socket in this memory dump of a system infected with the Ordergun/Gozi/UrSniff trojan.7

$ python volatility.py sockets -f ursniff.vmem

Pid Port Proto Create Time

1052 123 17 Wed Nov 18 01:23:24 2009

716 500 17 Wed Nov 18 01:23:20 2009

1824 0 0 Thu Jan 07 20:29:10 2010

4 445 6 Wed Nov 18 01:23:03 2009

[...]

$ python volatility.py files -p 1824 -f ursniff.vmem

Pid: 1824

File \Device\HarddiskVolume1\WINDOWS\system32

File \Device\KsecDD

File \Device\Afd\Endpoint

File \Device\RawIp\0

File \Device\Afd\Endpoint

[...]

That was easy! In summary, processes that open raw sockets, with or without promiscuous mode, will have a socket bound to port 0 of protocol 0 and an open handle to \Device\RawIp\0.

5 http://msdn.microsoft.com/en-us/library/ms740548%28VS.85%29.aspx

6 http://ntsecurity.nu/toolbox/promiscdetect/

7 http://www.secureworks.com/research/threats/gozi/

Registry Analysis

If you weren’t familiar with the Registry as a source of forensic evidence when you started reading this book, you should be familiar with it now (it was discussed in Chapters 9 and 10). The following section shows a different perspective on the Registry. In particular, it describes how to determine which Registry keys a process was accessing at the time a memory sample was acquired and how to determine the values and data for those Registry keys. There are several reasons why extracting Registry contents from memory is important:

· No disk access: Sometimes, you simply don’t have access to an infected system’s disk in order to recover the Registry hive files.

· Volatile hives and keys: Some hives, such as HKEY_LOCAL_MACHINE\HARDWARE, do not have an associated file—they only exist in memory. Another example is HKEY_CURRENT_USER\Volatile Environment, which contains a temporary set of per-user environment variables. Additionally, malware can create volatile keys by specifying the REG_OPTION_VOLATILE flag to RegCreateKeyEx. In any of these cases, recovering the data from a memory sample with Volatility is your only option.

· Registry cache attacks: Brendan Dolan-Gavitt showed that it was possible for an adversary to modify the cached version of Registry keys in kernel memory (similar to a DKOM technique) and not write those changes to disk. In particular, an attacker can change the Administrator user’s password hashes in memory, thus enabling the attacker to log in from a remote location. See “Forensic analysis of the Windows registry in memory,” which is available at http://dfrws.org/2008/proceedings/p26-dolan-gavitt.pdf.

Recipe 18-5: Analyzing Registry Artifacts with Memory Registry Tools

In order to read or write to the Registry, processes must first open a handle to the key they wish to access using an API function such as RegOpenKeyExA or RegCreateKeyExA. If the request succeeds, then the process will receive a handle value that it must then pass to functions such as RegQueryValueExA or RegSetValueExA in order to perform the desired read/write operation. The handle will remain valid for the process until it calls RegCloseKey or until the process terminates.

You can use the regobjkeys command in Volatility to list the open Registry keys in a process. This will give you an idea of how the process was using the Registry at the time the memory dump was acquired. If you happen to encounter poorly coded malware that opens a key and then forgets to call RegCloseKey, then you can also gather some evidence leading to what the malware did several hours or days before.

The Case of Clampi/Illomo

The following example is based on a memory dump infected with the Clampi/Illomo trojan.8 This family of malware uses the Registry to not only store its command and control server information, but also to store encrypted DLLs that it queries for and loads at run-time. By storing DLLs in the Registry instead of on disk (not to mention in an encrypted form), Clampi successfully evades many antivirus programs.

$ python volatility.py pslist -f clampi.vmem

Name Pid PPid Thds Hnds Time

System 4 0 64 263 Thu Jan 01 00:00:00 1970

smss.exe 588 4 3 21 Thu Sep 18 05:32:54 2008

csrss.exe 660 588 12 330 Thu Sep 18 05:32:56 2008

winlogon.exe 684 588 19 567 Thu Sep 18 05:32:56 2008

services.exe 728 684 16 256 Thu Sep 18 05:32:57 2008

lsass.exe 740 684 19 328 Thu Sep 18 05:32:57 2008

svchost.exe 892 728 17 193 Thu Sep 18 05:32:58 2008

svchost.exe 972 728 10 248 Thu Sep 18 05:32:58 2008

svchost.exe 1064 728 51 1165 Thu Sep 18 05:32:59 2008

svchost.exe 1112 728 6 85 Thu Sep 18 05:32:59 2008

svchost.exe 1156 728 15 206 Thu Sep 18 05:32:59 2008

spoolsv.exe 1488 728 10 119 Thu Sep 18 05:33:00 2008

explorer.exe 1624 1592 20 651 Thu Sep 18 05:33:01 2008

jusched.exe 1788 1624 1 26 Thu Sep 18 05:33:02 2008

alg.exe 1320 728 6 106 Thu Sep 18 05:33:29 2008

wscntfy.exe 1740 1064 1 28 Thu Sep 18 05:33:30 2008

helper.exe 640 868 1 44 Sat Feb 14 18:23:02 2009

IEXPLORE.EXE 940 640 2 59 Sat Feb 14 18:23:13 2009

In the process listing, you can see helper.exe and IEXPLORE.EXE—neither of which is immediately suspicious. However, when you consider the fact that IEXPLORE.EXE’s parent process ID (640) is the process ID of helper.exe, then it begins to raise some flags. In most cases, if a user opens Internet Explorer, then IEXPLORE.EXE’s parent process will be explorer.exe. Look at the open Registry keys for helper.exe:

$ python volatility.py regobjkeys –p 640 –f clampi.vmem

****************************************************************

Pid: 640

\REGISTRY\MACHINE

\REGISTRY\USER\S-1-5-21-606747145-842925246-839522115-

1003\SOFTWARE\MICROSOFT\WINDOWS\CURRENTVERSION

\INTERNET SETTINGS

\REGISTRY\USER\S-1-5-21-606747145-842925246-839522115-1003

\REGISTRY\MACHINE\SOFTWARE\CLASSES\CLSID\

{0002DF01-0000-0000-C000-000000000046}

\REGISTRY\MACHINE\SYSTEM\CONTROLSET001\SERVICES\WINSOCK2\

PARAMETERS\PROTOCOL_CATALOG9

\REGISTRY\MACHINE\SYSTEM\CONTROLSET001\SERVICES\WINSOCK2\

PARAMETERS\NAMESPACE_CATALOG5

\REGISTRY\USER\S-1-5-21-606747145-842925246-839522115-1003\

SOFTWARE\MICROSOFT\INTERNET EXPLORER\SETTINGS

Now you can tell which Registry keys helper.exe was using. The \REGISTRY\MACHINE prefix corresponds to HKEY_LOCAL_MACHINE. Likewise, \REGISTRY\USER corresponds to HKEY_CURRENT_USER. The outstanding issue at this point is why was helper.exe using these Registry keys? Most of them seem related to Winsock2 or Internet Explorer settings, based on the name of the key. However, just as you can’t trust that a process named csrss.exe is the real csrss.exe, you also cannot trust that a Registry key named INTERNET EXPLORER\SETTINGS contains settings for the browser. Continue reading to figure out what Clampi really stores in these locations.

Querying Registry Contents from Memory

The following steps show you how to access Registry content in memory dumps using Brendan Dolan-Gavitt’s Memory Registry Tools9 (some of the plug-ins have been built into the Volatility core in 1.4). You can’t extract the entire contents of the Registry from memory; however, you can usually find large portions, especially for recently accessed keys.

1. Use the hivescan command to locate the physical addresses of CMHIVE structures.

$ python volatility.py hivescan -f clampi.vmem

Offset (hex)

44662792 0x2a98008

44690272 0x2a9eb60

48503648 0x2e41b60

127261064 0x795d988

130992992 0x7cecb60

131992416 0x7de0b60

132059144 0x7df1008

166725448 0x9f00748

169601888 0xa1beb60

170135560 0xa241008

170140696 0xa242418

197207896 0xbc12758

200421384 0xbf23008

2. Use hivelist to determine the virtual addresses of all of the hives. When calling this command, use the –o parameter and identify one of the physical addresses from the output of Step 1. It does not matter which value you choose from the hivescan output, and you can supply it as decimal or hex.

$ python volatility.py hivelist -o 0x2a98008 -f clampi.vmem

Address Name

0xe1bce008 \Documents and Settings\Joseph\Local Settings\

Application Data\Microsoft\Windows\UsrClass.dat

0xe1982758 \Documents and Settings\Joseph\NTUSER.DAT

0xe1855b60 \Documents and Settings\LocalService\Local

Settings\Application Data\Microsoft\Windows\UsrClass.dat

0xe17da748 \Documents and Settings\LocalService\NTUSER.DAT

0xe1861008 \Documents and Settings\NetworkService\Local

Settings\Application Data\Microsoft\Windows\UsrClass.dat

0xe1862418 \Documents and Settings\NetworkService\NTUSER.DAT

0xe1674988 \WINDOWS\system32\config\software

0xe1477b60 \WINDOWS\system32\config\default

0xe1485008 \WINDOWS\system32\config\SAM

0xe16a6b60 \WINDOWS\system32\config\SECURITY

0xe1395b60 [no name]

0xe1035b60 \WINDOWS\system32\config\system

0xe102e008 [no name]

3. Once you have located the virtual addresses for the individual hives in memory, you can begin to query for particular keys, subkeys, or values using the printkey command. In the example, we chose the value that corresponds to the NTUSER.DAT because that is where the \REGISTRY\USER\[REMOVED]\INTERNET EXPLORER\SETTINGS key is located.

$ python volatility.py printkey -o 0xe1982758 -f clampi.vmem

'Software\Microsoft\Internet Explorer\Settings'

Key name: Settings (Stable)

Last updated: Sat Feb 14 13:23:02 2009

Subkeys:

Values:

REG_SZ Anchor Color Visited : 128,0,128 (Stable)

REG_SZ Anchor Color : 0,0,255 (Stable)

REG_SZ Background Color : 192,192,192 (Stable)

REG_SZ Text Color : 0,0,0 (Stable)

REG_SZ Use Anchor Hover Color : No (Stable)

REG_BINARY GID :

0000 00000098 ....

(Stable)

REG_BINARY GatesList :

0000 637269746963616C666163746F722E63 criticalfactor.c

0010 63002F6367692D62696E2F636974792E c./cgi-bin/city.

0020 63676900 cgi.

(Stable)

REG_BINARY KeyM :

0000 946BEEBCFFA5BB8B5E682AA58FBF24F5 .k......^h*...$.

0010 7A63B79CBBDB14D51FAEB0573402596F zc.........W4.Yo

0020 C6389C7EBD8F82029F36AB3F0C6CB94C .8.~.....6.?.l.L

0030 C3987EE6770ACC53206F6B5BEC83A89E ..~.w..Sok[....

0040 34C19E9C73930501F33DD2DA79ED6300 4...s....=..y.c.

0050 0425CB82FC873D89E18679798C67A843 .%....=...yy.g.C

0060 5CBC6526665EB18AC55195E024B87FF5 ..e&f^...Q..$...

0070 1A1C2083DDB744E6E766B35D88A785C8 .....D..f.]....

0080 2BA4584E1885A29DD316D589E6514B70 +.XN.........QKp

0090 90C9F3826913F109ED7C30862A164A4C ....i....|0.*.JL

00A0 A406FAF978C47D7293FC64D748C5FB83 ....x.}r..d.H...

00B0 A2440A9877BECD4BFEA869A216F273C5 .D..w..K..i...s.

00C0 F144FF11383EAF5F3F87056161FCFF22 .D..8>._?..aa.."

00D0 BE00D54667A0BACE65A5C73203931196 ...Fg...e..2....

00E0 627EEB0B5D9D9A921B41108C2C9B09A5 b~..]....A..,...

00F0 1184EB91CA34180E922D85C76B02B0EF .....4...-..k...

(Stable)

REG_BINARY KeyE :

0000 00010001 ....

(Stable)

Based on the output, you can see that one of the open Registry keys in the helper.exe process stores the malware’s command and control server (criticalfactor.cc) in the GatesList value and a 256-byte binary blob (probably related to the network encryption) in the KeyM value. As you can see, detecting a process’s open Registry keys is useful, but determining what keys and values the malware may have introduced into the Registry is even better!

8 http://www.symantec.com/security_response/writeup.jsp?docid=2008-011616-5036-99&tabid=2

9 http://moyix.blogspot.com/2009/01/memory-registry-tools.html

Recipe 18-6: Sorting Keys by Last Written Timestamp

The printkey command is great if you have an idea of what you are looking for. However, it can become overwhelming and time-consuming if you do not know the names of the keys or even in which hives to look. In this case, you can leverage the LastWrite timestamp that Windows stores for each key in the Registry. If you know the general time frame when a compromise occurred, you can use hivedump to extract all of the keys and their corresponding timestamps from a given hive (or all hives, depending on the parameters you send to hivedump) into a sortable CSV file. Table 18-2 shows the syntax for this command.

Table 18-2: Hivedump Syntax

Syntax

Req/Opt

Description

-f FILENAME, --file=FILENAME

Required

Path to memory dump file

-o OFFSET, --offset=OFFSET

Optional

The physical offset of the first hive that hivescan locates. Specify this parameter if you want to dump all hives in memory.

-i HIVE, --hive=HIVE

Optional

Virtual address of one hive to dump. Specify this parameter if you only want to dump a single hive.

-v, --values

Optional

Include values in the CSV file (otherwise only keys and timestamps are included)

The –o and –i flags are shown as optional; however, you must supply one or the other. If you want to dump data from all hives, then call hivescan (Step 1 of Recipe 18-5) and use the first address that it returns with the –o flag. If you only want to dump data from a single hive, then use hivelist (Step 2 of Recipe 18-5) to get the virtual address of the desired hive, and use it with the –i flag.

The following example is based on a memory dump infected with the Virut trojan.10 Note how hivedump extracts each hive to a separate file based on its virtual address. After obtaining all of the individual CSV files, you can combine them into one with the cat command.

$ python volatility.py hivescan -f virut.vmem | head -n 2

Offset (hex)

33979232 0x2067b60

$ python volatility.py hivedump -o 0x2067b60 -f virut.vmem

Dumping \Documents and Settings\<User>\Local Settings\

Application Data\Microsoft\Windows\UsrClass.dat

=> e1b65a28.csv

Dumping \Documents and Settings\<User>\NTUSER.DAT => e1b0c9c8.csv

Dumping \Documents and Settings\LocalService\Local Settings\

Application Data\Microsoft\Windows\UsrClass.dat => e1849860.csv

Dumping \Documents and Settings\LocalService\NTUSER.DAT =>

e1845008.csv

Dumping \Documents and Settings\NetworkService\Local Settings\

Application Data\Microsoft\Windows\UsrClass.dat => e1825b60.csv

Dumping \Documents and Settings\NetworkService\NTUSER.DAT =>

e181c5a8.csv

Dumping \WINDOWS\system32\config\software => e14f3008.csv

Dumping \WINDOWS\system32\config\default => e14f37e8.csv

Dumping \WINDOWS\system32\config\SECURITY => e14f13c8.csv

Dumping \WINDOWS\system32\config\SAM => e14ff008.csv

Dumping => e1367b60.csv

Dumping \WINDOWS\system32\config\system => e1018388.csv

Dumping => e1008b60.csv

$ cat *.csv > combined.csv

You can open the combined CSV file in a spreadsheet application and sort the timestamp column from largest to smallest in order to see the most recent changes. After viewing changes to the Registry from various systems, you can familiarize yourself with the keys that Windows updates regularly and figure out which ones you can ignore. If we chose the –v flag to hivedump, the CSV file would include the values in each key.

In Figure 18-4, you can see that a run key (Microsoft\Windows\CurrentVersion\Run) was last updated at 13:27:01. A few seconds earlier at 13:26:58, a change was made to a Registry key that stores firewall configurations. In particular, the AuthorizedApplications\List subkey stores names of processes that Windows excludes from normal firewall rulesets.

Figure 18-4: Registry keys sorted by last modified time

f1804.tif

By combining all of the CSV files into one, a little bit of context was lost. Now it is hard to tell if the run key is under HKEY_LOCAL_MACHINE or HKEY_CURRENT_USER. That’s okay, however, because it’s easy enough to modify the hivedump Python script to print an extra column indicating which hive the data came from. Using the printkey command (Step 3 of Recipe 18-5), you can investigate the values in the run key:

$ python volatility.py printkey -o 0xe14f3008 -f virut.vmem

'Microsoft\Windows\CurrentVersion\Run'

Key name: Run (Stable)

Last updated: Sat Nov 21 13:27:01 2009

Subkeys:

OptionalComponents (Stable)

Values:

REG_SZ Adobe Reader Speed Launcher : "C:\Program Files\Adobe

\Reader 8.0\Reader\Reader_sl.exe"

REG_SZ Windows Explorer : C:\WINDOWS\system32\explorer.exe

The final line of output shows a Registry value that causes Windows to start C:\WINDOWS\system32\explorer.exe every time the computer boots. The entry may look benign at first, but it is actually a file dropped by Virut. The real Windows Explorer exists in C:\WINDOWS\explorer.exe and it does not need an entry in this location of the Registry to start because userinit.exe starts it automatically.

Now look at the value in the firewall key:

$ python volatility.py printkey -o 0xe1018388 -f virut.vmem

'ControlSet001\Services\SharedAccess\Parameters\FirewallPolicy

\StandardProfile\AuthorizedApplications\List'

Key name: List (Stable)

Last updated: Sat Nov 21 13:26:58 2009

Subkeys:

Values:

REG_SZ %windir%\system32\sessmgr.exe :

%windir%\system32\sessmgr.exe:*:enabled:@xpsp2res.dll,-22019

REG_SZ \??\C:\WINDOWS\system32\winlogon.exe :

\??\C:\WINDOWS\system32\winlogon.exe:*:enabled:@shell32.dll,-1

Two applications can bypass the firewall settings—sessmgr.exe and winlogon.exe. These are both valid applications and the Registry only stores a LastWrite time for keys, not individual values in a key. Therefore, you cannot tell if Virut added the value for sessmgr.exe or the value for winlogon.exe. In fact, you cannot tell if Virut added either value—maybe both values existed and Virut just modified one slightly. However, MSDN explains that sessmgr.exe provides Remote Assistance, which happens to be the only program enabled to bypass the local firewall by default on XPSP2. Winlogon.exe, although it is an important process, should not have unrestricted access to the Internet. The reason you see it here is that Virut initiates outbound connections from winlogon.exe by first injecting code into it!

10 http://www.threatexpert.com/reports.aspx?find=virut&x=0&y=0

Recipe 18-7: Using Volatility with RegRipper

In Recipe 10-8, you learned how to use RegRipper to extract information from Registry hive files. Brendan Dolan-Gavitt came up with a creative use for RegRipper called Volrip11 that lets you use it on memory dumps instead of hive files. Volrip is essentially a wrapper, or interface, that makes RegRipper believe it’s working off hive files, when really the data is being carved out of the memory dump with the Memory Registry Tools for Volatility. The initial release of Volatility 1.4 will not support Volrip, so you must use Volatility version 1.3.2.

To use Volrip, extract the archive into the base Volatility directory. Then make sure you can run rip.pl.

$ tar –xzf volrip-0.1.tar.gz

$ perl rip.pl

Rip v.20080419 - CLI RegRipper tool

Rip [-r Reg hive file] [-f plugin file] [-p plugin module] [-l] [-h]

Parse Windows Registry files, using either a single module, or a plugins file.

All plugins must be located in the "plugins" directory; default plugins file

used if no other filename given is "plugins\plugins".

-r Reg hive file...Registry hive file to parse

-g ................Guess the hive file (experimental)

-f [plugin file]...use the plugin file (default: plugins\plugins)

-p plugin module...use only this module

-l ................list all plugins

-c ................Output list in CSV format (use with -l)

-h.................Help (print this information)

Ex: C:\>rr -r c:\case\system -f system

C:\>rr -r c:\case\ntuser.dat -p userassist

C:\>rr -l -c

All output goes to STDOUT; use redirection (ie, > or >>) to output to a file.

copyright 2008 H. Carvey

The syntax displayed by rip.pl is a little different from what you will actually type—in this case, because you are using it against a memory dump instead of a hive file. In particular, instead of using the –r parameter to identify the hive file, you use the –r parameter to identify the memory dump and the virtual address in the memory dump where the particular hive is loaded. To get the virtual address, follow Steps 1 and 2 of Recipe 18-5. You can use –f to run a collection of plug-ins against a hive, or use –p to run a single plug-in. The example that follows shows you how to detect BHOs in the software hive. Notice how the @ symbol separates the name of the memory dump from the virtual address.

$ python volatility.py hivescan -f silentbanker.vmem | head -n 2

Offset (hex)

44662792 0x2a98008

$ python volatility.py hivelist -o 0x2a98008 -f silentbanker.vmem | grep software

0xe1674988 \WINDOWS\system32\config\software

$ perl rip.pl -r silentbanker.vmem@0xe1674988 -p bho

Launching bho v.20080418

Browser Helper Objects

Microsoft\Windows\CurrentVersion\Explorer\Browser Helper Objects

LastWrite Time Wed Feb 18 06:53:33 2009 (UTC)

{00009E9F-DDD7-AA59-AA7D-AA4B7D6BE000}

Class => mscorews

Module => C:\WINDOWS\system32\mscorews.dll

LastWrite => Wed Feb 18 06:53:33 2009

{761497BB-D6F0-462C-B6EB-D4DAF1D92D43}

Class => SSVHelper Class

Module => C:\Program Files\Java\jre1.6.0_07\bin\ssv.dll

LastWrite => Wed Aug 27 20:04:14 2008

The output shows that there are two BHOs installed on the system from which the memory dump was acquired. One of the BHOs appears to be the Java helper class. The other, mscorews.dll, is the malicious BHO installed by Silent Banker.

11 http://moyix.blogspot.com/2009/03/regripper-and-volatility-prototype.html