Sunday, September 25, 2011

Abstract Memory Analysis: Zeus Encryption Keys

Community Momentum is Rising!

The amount of research pouring out of the Volatility community recently has been very exciting. Over the past few weeks, we've seen Russ McRee of HolisticInfoSec.org / toolsmith write about Memory Analysis with DumpIt and Volatility. Frank Boldewin published a CSI:Internet article titled A Trip Into RAM that focused on detecting Spyeye. @bradarndt wrote a lengthy Zeus Analysis in Volatility 2.0 just days after releasing a new plugin called Vscan that automatically submits files extracted from memory to online virus scanners. evild3ad also wrote a piece on Zeus just days after providing a nice installation tutorial for Volatility 2.0 on Ubuntu.

Last week, Evilcry (@Blackmond_) updated his Carberp Reverse Engineering post to show some of the many ways to detect Carberp in memory...my favorite being the detection of NT syscall hooks. Several of our primary developers have launched the 64-bit branch of Volatility in preparation for the 2.1 release. @gleeda just published her Timeliner, Registry API, Event log plugins and corresponding documentation (also makes a great tutorial on writing your own Volatility plugins).

To keep the momentum going, I'll discuss one of the more abstract ways that you can leverage Volatility.
We'll take a look at how to locate and extract Zeus's RC4 encryption keys, then use the keys to decrypt other configuration data found in memory. The plugins we'll discuss were written well over a year ago and kept private due to sensitivity of the key recovery methods. It wasn't exactly a secret previously (ThreatExpert disclosed some juicy details back in May) but it also wasn't common sense knowledge. Earlier today, TrustDefender announced their finding of Zeus Trojan Update - new variants based on leaked zeus source code. The new versions reportedly use AES instead of RC4 and intentionally try to clear memory of the encryption keys. That means for certain we're not disclosing anything the attackers don't already know.

Zeus Versions

The earliest variants of Zeus (circa 2006) encrypted configurations using a very simple algorithm that I described in the original report called [Prg] Malware Case Study. We won't discuss these versions anymore - they don't use encryption keys so there's nothing fun to try and recover.

Near the end of 2008 (I'm going to say at approximately version 1.2.0), Zeus started using unique 256-byte RC4 keys embedded in each binary to decrypt configurations. It prevented analysts from using the key from one sample for decrypting the configuration used by another sample. I designed an unpacker-like tool that ran on live VMs and could extract the key without infecting the system (thus you could loop through hundreds of samples without reverting). Then you could decrypt configurations in a brute-force like manner, by cycling through all of the extracted keys until one "unlocked" it.

The sample I'll be using that represents all Zeus versions after 1.2.0 but before 2.x is MD5
b5709cd23d8ad91d79062ad63e8516ed.

The present day Zeus variants (2.x) still use RC4 encryption, but many also have a hardware-locking feature so that a sample recovered from one machine won't run on another machine (such as a sandbox or analysis system). These variants hide data in randomly generated registry keys and directories on the file system. They also use a separate 256-byte RC4 key for the configuration and for the stolen data files.

The sample I'll be using that represents Zeus versions 2.x is MD5
b93fb47257f052f6bc99f0b96b718cd4.

Recovering keys for Zeus versions > 1.20 and < 2.0

These variants of Zeus define a data structure with the 256-byte RC4 key at offset 0x2A. The challenge is finding those exact 256 bytes in a memory dump that is potentially several gigabytes large. Talk about needle in a haystack, right? One of the more obvious solutions is look for patterns among the other structure members and develop a scanner with constraints. For example, if the member at offset 0 was always 0x12345678 and member at offset 4 was always between 0x30 and 0x45, then you have some criteria to start searching. However, that's not the road I took.

While reversing some samples, I noticed a pointer to the base of the structure can be found at one of the most unexpected locations. As shown in the image below, after the Zeus "body" is injected into a process and fully unpacks itself, the pointer is in the Import Address Table (IAT) directly after the ws2_32!closesocket entry.

Whether this was done on purpose by the Zeus authors or accidentally is beyond me. I don't know how things like this happen by accident, nor do I know any reasons to do intentionally. However, since hundreds of thousands of samples were created using the same Zeus builder, they all share the same secret.

Now that we know what we're looking for, let's discuss how to find it. Here is a brief description of the steps:

1. Find Zeus. We'll cycle through the active process list. For each process, we'll traverse the VAD tree. For every memory segment, we'll check if there is injected code (i.e. a private, virtually-allocated region with VadS tag and no file mapping). This is all rather simple, since its exactly how malfind has located Zeus infections for years.

2. Find closesocket in the IAT. This step sounds straight-forward, but its not. Due to Zeus' packing and obfuscation, the names of imported functions are not always available. Thus, we can't parse the IAT looking for "closesocket" as normal PE header tools do. Instead, we leverage Volatility's ImpScan plugin, which scans for calls to imported functions using a "reverse lookup" kind of algorithm (described fully in Malware Analyst's Cookbook Recipe 16-8: Scanning for Imported Functions with Impscan).

3. Find the structure pointer. As previously described, the pointer is the next 4 bytes after the closesocket entry. So we dereference those 4 bytes as a pointer, add 0x2A to reach the RC4 key structure member, and read 256-bytes.

4. Write the plugin. Now we know what we need to do. Let's do it! We'll need to import volatility.obj for access to the Object class, volatility.win32.tasks for access to process enumeration, volatility.utils for access to the Hexdump function, and volatility.plugins.malware for the ability to inherit from the ImpScan plugin.
import volatility.obj as obj
import volatility.utils as utils
import volatility.win32.tasks as tasks
import volatility.plugins.malware as malware
Now we define a class that inherits from malware.ImpScan. The name of our class (ZeusScan1) will automatically become the name of the command that you type, for example "python vol.py zeusscan1"
class ZeusScan1(malware.ImpScan):
"Scan for and dump Zeus RC4 keys"

def __init__(self, config, *args):
malware.ImpScan.__init__(self, config, *args)

A majority of the work happens in the calculate function. As described above, we begin by iterating through active processes. For each process, we acquire an address space (an object referring to the process's private virtual memory) and also enumerate the loaded DLLs which we'll need to locate ws2_32.dll.
    def calculate(self):
addr_space = malware.get_malware_space(self._config)

RC4_KEYSIZE = 0x102

# cycle through the active processes
for p in self.filter_tasks(tasks.pslist(addr_space)):

# get the process address space
ps_ad = p.get_process_address_space()
if ps_ad == None:
continue

# enumerate DLLs (inherited from DllList)
mods = self.list_modules(p
Next we traverse the VAD segments and filter by private allocations with no file mapping and 'MZ' at the base. Any segments that satisfy this criteria are almost certainly injected Zeus binaries.
           # traverse the VAD
for vad in p.VadRoot.traverse():

if vad == None:
continue

# only looking for short VADs (non-memory mapped)
if (vad.Tag != "VadS"):
continue

# only looking for private, virtually-alocated memory
if vad.u.VadFlags.PrivateMemory == 0:
continue

# find the start and end range
start = vad.get_start()
end = vad.get_end()
data = vad.get_data()

# check for PE headers at the base
if data[0:2] != 'MZ':
continue
Now comes Step 2. We need to find where closesocket is located in process memory. This is done by first locating ws2_32.dll and then calling getprocaddress() - an extension to the module that parses its EAT and returns the requested function's virtual address.
               # locate the winsock2 module
winsock = malware.find_module_by_name(mods, "ws2_32.dll")

if winsock == None:
continue

# resolve the address of closesocket export
closesocket = winsock.getprocaddress("closesocket")

if closesocket == None:
continue
The next thing we do is use call_scan which is inherited from malware.ImpScan. It is a generator that yields tuples in the following order: address of the CALL instruction, constant (IAT entry address), and call destination (the API function address). To clear up any confusion around these values, let's go over a quick example. Say you have the following code in a disassembly ".text:00120408 CALL DWORD PTR:[0010022c] ; kernel32.CreateFileW".

In the example, 00120408 is the address of the CALL instruction. 0010022c is the constant. If you dereference the constant, you'll find a DWORD sized value that points to kernel32.CreateFileW. So what we're doing is scanning for CALLs that lead to ws2_32!closesocket. We're taking the constant, adding 4 bytes, and then using the DWORD at that location as a pointer to the structure that contains the RC4 key. Without further ado, here's the rest of the code:
               # scan for calls to imported functions (inherited from ImpScan)
calls = list(self.call_scan(ps_ad, data, start))

for (addr_of_call, const, call_dest) in calls:

if call_dest != closesocket:
continue

# read the DWORD directly after closesocket
struct_base = obj.Object('Pointer', offset = const + 4, vm = ps_ad)

# to be valid, it must point within the vad segment
if (struct_base < start) or (struct_base > (start + end)):
continue

# grab the key data
key = ps_ad.read(struct_base + 0x2a, RC4_KEYSIZE)

# greg's sanity check
if len(key) != RC4_KEYSIZE or key[-2:] != "\x00\x00":
continue

yield p, struct_base, key
We yield 3 values from the calculate function. These 3 values are automatically passed to render_text if you're using text-mode output. Thus we also must define a render_text method in our plugin.
    def render_text(self, outfd, data):

for p, struct_base, key in data:
hex = "\n".join(["{0:#010x} {1:<48} {2}".format(struct_base + 0x2a + o, h, ''.join(c)) for o, h, c in utils.Hexdump(key)])
outfd.write("Process: {0} {1}\n".format(p.UniqueProcessId, p.ImageFileName))
outfd.write(hex)
outfd.write("\n")
5. Test the plugin. When you run zeusscan1 against a memory dump infected with one of the these Zeus samples, you'll see output like this:
$ python vol.py -f XPSP3-0e4e1fd4.vmem zeusscan1
Volatile Systems Volatility Framework 2.1_alpha

Process: 624 winlogon.exe
0x00ac602a 76 e6 ce 65 3e d9 5e 0c 0a 8f 14 81 f6 dc ee 2f v..e>.^......../
0x00ac603a bd 1a 10 0d 98 63 61 34 9d 8e 75 1c b6 b8 b7 56 .....ca4..u....V
0x00ac604a 4a bb d1 99 37 a2 40 4f e0 77 80 52 3f db c4 73 J...7.@O.w.R?..s
0x00ac605a 69 21 96 eb 0b 28 7f 90 d2 e5 46 d0 39 2a 51 43 i!...(....F.9*QC
0x00ac606a ca 1e a0 62 8c fe c8 15 78 8b 9b d4 2d a4 da ef ...b....x...-...
0x00ac607a 47 66 b1 ec 93 c1 87 e3 a9 b9 4c 9f 6a 86 20 d3 Gf........L.j...
0x00ac608a a5 8d df 72 3b 44 e1 cb 85 92 04 74 f2 84 33 a6 ...r;D.....t..3.
0x00ac609a f3 ae 2b c5 94 f5 7c 50 c9 1b de 83 ad cc 68 60 ..+...|P......h`
0x00ac60aa c2 6e 09 c7 a7 16 fa d6 9e bf b2 ab 32 ed 3c 36 .n..........2.<6
0x00ac60ba 2e b3 91 0e 05 08 af f1 c6 49 82 95 dd ac 5f 3d .........I...._=
0x00ac60ca 29 e8 a8 bc 88 9c 24 c3 17 79 6c f9 fc 1d b4 19 ).....$..yl.....
0x00ac60da b5 f0 89 ff c0 03 d8 48 57 d5 e2 67 35 7b f4 a1 .......HW..g5{..
0x00ac60ea 3a 30 02 be 42 cd e4 31 fb 7d 4d 4b 7a 26 5a 45 :0..B..1.}MKz&ZE
0x00ac60fa 38 64 55 13 54 ba 00 8a f8 07 ea 27 71 e9 53 cf 8dU.T......'q.S.
0x00ac610a f7 70 23 58 06 01 5d 6d e7 4e 5b 22 12 6f 97 aa .p#X..]m.N[".o..
0x00ac611a 59 11 5c d7 25 41 18 7e 2c fd b0 a3 0f 6b 9a 1f Y.\.%A.~,....k..
0x00ac612a 00 00 ..

Process: 668 services.exe
0x0075602a 76 e6 ce 65 3e d9 5e 0c 0a 8f 14 81 f6 dc ee 2f v..e>.^......../
0x0075603a bd 1a 10 0d 98 63 61 34 9d 8e 75 1c b6 b8 b7 56 .....ca4..u....V
0x0075604a 4a bb d1 99 37 a2 40 4f e0 77 80 52 3f db c4 73 J...7.@O.w.R?..s
0x0075605a 69 21 96 eb 0b 28 7f 90 d2 e5 46 d0 39 2a 51 43 i!...(....F.9*QC
0x0075606a ca 1e a0 62 8c fe c8 15 78 8b 9b d4 2d a4 da ef ...b....x...-...
0x0075607a 47 66 b1 ec 93 c1 87 e3 a9 b9 4c 9f 6a 86 20 d3 Gf........L.j...
0x0075608a a5 8d df 72 3b 44 e1 cb 85 92 04 74 f2 84 33 a6 ...r;D.....t..3.
0x0075609a f3 ae 2b c5 94 f5 7c 50 c9 1b de 83 ad cc 68 60 ..+...|P......h`
0x007560aa c2 6e 09 c7 a7 16 fa d6 9e bf b2 ab 32 ed 3c 36 .n..........2.<6
0x007560ba 2e b3 91 0e 05 08 af f1 c6 49 82 95 dd ac 5f 3d .........I...._=
0x007560ca 29 e8 a8 bc 88 9c 24 c3 17 79 6c f9 fc 1d b4 19 ).....$..yl.....
0x007560da b5 f0 89 ff c0 03 d8 48 57 d5 e2 67 35 7b f4 a1 .......HW..g5{..
0x007560ea 3a 30 02 be 42 cd e4 31 fb 7d 4d 4b 7a 26 5a 45 :0..B..1.}MKz&ZE
0x007560fa 38 64 55 13 54 ba 00 8a f8 07 ea 27 71 e9 53 cf 8dU.T......'q.S.
0x0075610a f7 70 23 58 06 01 5d 6d e7 4e 5b 22 12 6f 97 aa .p#X..]m.N[".o..
0x0075611a 59 11 5c d7 25 41 18 7e 2c fd b0 a3 0f 6b 9a 1f Y.\.%A.~,....k..
0x0075612a 00 00 ..
And there you have it. The plugin prints a hexdump of the 256-byte RC4 key unique to the Zeus variant that has infected the machine. Since its the same version of Zeus injected into winlogon.exe and services.exe, the keys you see are going to match.

Recovering keys for Zeus versions >= 2.0

Welcome to the real fun. I'm not going to dive deep into the details of recovering RC4 keys from these versions, because Sergei
The function named "signature_function" can be expressed using wildcards like this:
PUSH 102h
LEA EAX, [ESP+????????]
PUSH EAX
LEA EAX, [ESP+??]
PUSH EAX
CALL ???????? ; custom_memcpy
MOV EAX, 1E6h
PUSH EAX
PUSH OFFSET ???????? ; real_rc4_key
There may be variations due to compiler differences, so we also should look for this:
PUSH 102h
LEA EAX, [EBP-????????]
PUSH EAX
LEA EAX, [EBP-????????]
PUSH EAX
CALL ???????? ; custom_memcpy
MOV EAX, 1E6h
PUSH EAX
PUSH OFFSET ???????? ; real_rc4_key
As for the function named "decode_config_data", it can be expressed like this:
PUSH ESI
MOV EDX, ????0000 ; config size (immediate)
PUSH EDX
PUSH OFFSET ???????? ; config_data
PUSH EAX
CALL ???????? ; custom_memcpy
MOV ESI, ???????? ; last_section_rva
MOV ECX, ???????? ; imagebase
There are several variations of these patterns, once again, due to compiler differences and usage of general purpose registers. But its nothing that Yara rules can't handle. By converting the above instructions into opcodes, we have the following signatures:
zeus_key_sigs = {
'namespace1':'rule z1 {strings: $a = {56 BA ?? ?? 00 00 52 68 ?? ?? ?? ?? 50 E8 ?? ?? ?? ?? 8B 35 ?? ?? ?? ?? 8B 0D ?? ?? ?? ??} condition: $a}',
'namespace5':'rule z5 {strings: $a = {56 BA ?? ?? 00 00 52 68 ?? ?? ?? ?? 50 E8 ?? ?? ?? ?? 8B 0D ?? ?? ?? ?? 03 0D ?? ?? ?? ??} condition: $a}',
'namespace2':'rule z2 {strings: $a = {55 8B EC 51 A1 ?? ?? ?? ?? 8B 0D ?? ?? ?? ?? 56 8D 34 01 A1 ?? ?? ?? ?? 8B 0D ?? ?? ?? ??} condition: $a}',
'namespace3':'rule z3 {strings: $a = {68 02 01 00 00 8D 84 24 ?? ?? ?? ?? 50 8D 44 24 ?? 50 E8 ?? ?? ?? ?? B8 E6 01 00 00 50 68 ?? ?? ?? ??} condition: $a}',
'namespace4':'rule z4 {strings: $a = {68 02 01 00 00 8D 85 ?? ?? ?? ?? 50 8D 85 ?? ?? ?? ?? 50 E8 ?? ?? ?? ?? B8 E6 01 00 00 50 68 ?? ?? ?? ??} condition: $a}'
}
For plugin testing purposes, I created a memory dump infected with 4 different 2.x samples. But wait a minute, doesn't Zeus check for mutexes and back off if a system is already infected? Well, yes, it does...but I paused each sample in a debugger after it unpacked and before it could exit (that's easier than creating 4 separate memory dumps).

Let's give her a whirl! You should see the name of the process housing the injected Zeus code, along with the URL that Zeus contacts for an update, the local system's unique identifier (computer name plus some random characters), the XOR keys, the randomly generated registry keys and value names that Zeus uses for storing data, and the randomly generated file paths and file names for Zeus executables and stolen data files. Oh, and the two RC4 keys ;-)
$ python vol.py -f zeus2x4.vmem zeusscan2
--------------------------------------------------
Process: wuauclt.exe
Pid: 940
Address: 0xD80000
URL: http://193.43.134.14/eu2.bin
Identifier: JASONRESACC69_7875768F16073AAF
Mutant key: 0x17703072
XOR key: 0x2006B8FE
Registry: HKEY_CURRENT_USER\SOFTWARE\Microsoft\Izozo
Value 1: Kealtuuxd
Value 2: Yrdii
Value 3: Kebooqu
Executable: Obyt\ihah.exe
Data file: Ebupzu\uzugl.dat

Config RC4 Key:
0x00000000 4a ba 2c 63 eb 7c fc 45 c4 f3 b6 2d 31 29 21 2e J.,c.|.E...-1)!.
0x00000010 53 0f 3f ef 9a 2a f8 82 96 6b e1 a2 3b 5f 34 fd S.?..*...k..;_4.
0x00000020 a6 02 cc 39 0b 16 40 33 1f a1 dc af 93 9b 5b 94 ...9..@3......[.
0x00000030 68 62 84 46 ca 64 8d 43 13 d4 d9 72 00 5c 2b bc hb.F.d.C...r..+.
0x00000040 f6 d7 88 91 24 9f bd 1e 7a 07 c5 6e 1a 4e 90 92 ....$...z..n.N..
0x00000050 c1 42 0c 75 47 3a 9e 1d c2 ec 0d ed b8 71 b4 ab .B.uG:.......q..
0x00000060 e6 5d e3 14 48 b9 e9 e8 b2 10 ee f4 e2 2f a4 09 .]..H......../..
0x00000070 54 b7 95 be 50 99 8b 87 8f 37 9d fa f2 d5 b1 18 T...P....7......
0x00000080 01 db 3c cf aa 70 e5 15 9c 5a 26 27 de da d8 d6 ..<..p...Z&'....
0x00000090 59 a8 1b 30 cd 6c 78 c0 e7 c6 81 22 86 17 38 a7 Y..0.lx...."..8.
0x000000a0 df 41 ad 4d 44 11 76 a3 52 a9 b3 6d 51 05 c9 b5 .A.MD.v.R..mQ...
0x000000b0 85 49 77 c7 23 f7 3e 8a 03 69 ac 3d 4c 89 ff 58 .Iw.#.>..i.=L..X
0x000000c0 dd 57 5e 97 98 f1 65 c3 7d f0 e0 20 e4 25 7e 7b .W^...e.}.. .%~{
0x000000d0 b0 06 4b a5 c8 80 f9 f5 55 1c 7f 83 73 d1 66 fe ..K.....U...s.f.
0x000000e0 8c 28 19 4f 60 36 0a 8e ce ae fb 0e 74 35 79 56 .(.O`6......t5yV
0x000000f0 a0 08 ea bb 67 d3 d0 6a 12 6f 32 bf d2 04 cb 61 ....g..j.o2....a
0x00000100 00 00 ..

Credential RC4 Key:
0x00000000 6f e4 94 f2 f1 5e 5c c1 8c e8 66 c5 13 2a 23 39 o....^....f..*#9
0x00000010 84 36 6a 83 b2 55 6c 11 5a f3 b6 20 07 6d ba de .6j..Ul.Z.. .m..
0x00000020 52 8e 34 bf 8a 05 0f 64 35 29 cb 5f ff 00 87 fc R.4....d5)._....
0x00000030 b5 5b 67 b8 eb 1a 0e 1f 32 ae 54 3a 88 ed c3 51 .[g.....2.T:...Q
0x00000040 40 14 3e 53 dc 7c a7 0b 79 26 e5 45 99 7d 1c d0 @.>S.|..y&.E.}..
0x00000050 90 8f 80 95 71 58 41 5d f9 af 9e a1 6e ef 25 4e ....qXA]....n.%N
0x00000060 48 2d b1 bd 33 ab d3 b7 4d 10 7e 44 65 7b cd 2f H-..3...M.~De{./
0x00000070 ea 3f 2c ce 9a 9d db 31 b0 69 cf f7 e7 a6 82 a4 .?,....1.i......
0x00000080 ad a3 30 9b 76 f0 f5 ac c2 fb 8b 4f fe 8d a8 04 ..0.v......O....
0x00000090 86 a0 50 4c 4b e2 ec 60 e6 dd c6 42 cc 6b 89 57 ..PLK..`...B.k.W
0x000000a0 d1 d8 78 4a 1d d7 9f e0 7a 75 e3 7f a2 77 85 2b ..xJ....zu...w.+
0x000000b0 59 16 d6 d4 f4 93 ee 9c d2 03 be 2e 06 1b 56 70 Y.............Vp
0x000000c0 d5 73 ca f8 fd 12 37 49 98 46 0d bb 96 c9 18 b9 .s....7I.F......
0x000000d0 81 74 a9 3c 21 c4 da 38 0c 1e 27 0a c7 15 47 68 .t.ji--..8..'...G
0x000000e0 bc f6 91 fa 72 3d 01 e9 22 e1 09 c8 19 c0 aa b3 ....r=..".......
0x000000f0 b4 08 17 3b 61 92 02 63 43 62 d9 df 97 24 28 a5 ...;a..cCb...$(.
0x00000100 00 00 ..
I'll show a preview of the other variants installed on zeus2x4.vmem, but withhold the keys for the sake of brevity.
--------------------------------------------------
Process: nifek_locked.ex
Pid: 2204
Address: 0x400000
URL: http://zephehooqu.ru/bin/koethood.bin
Identifier: OREO_7875768FD1A71CE9
Mutant key: 0x895B26B0
XOR key: 0x739A94C5
Registry: HKEY_CURRENT_USER\SOFTWARE\Microsoft\Opiss
Value 1: Ypzoarfu
Value 2: Omviacy
Value 3: Otedhay
Executable: Pese\nifek.exe
Data file: Iqpa\ytzea.dat

--------------------------------------------------
Process: vaelh.exe
Pid: 952
Address: 0x400000
URL: http://nahwgwwergwyt.com/gamer/eqtewttetwq.img
Identifier: ZESRA037219_7875768F7BDEA03C
Mutant key: 0x90B18B41
XOR key: 0x569E6C1F
Registry: HKEY_CURRENT_USER\SOFTWARE\Microsoft\Koti
Value 1: Imwiase
Value 2: Qaofl
Value 3: Izsuuqex
Executable: Ammaax\vaelh.exe
Data file: Xuuf\otsip.dat

--------------------------------------------------
Process: anaxu.exe
Pid: 3508
Address: 0x400000
URL: http://basicasco.ru/otp/zero.doc
Identifier: PENNY_74DEB1E33B0FB384
Mutant key: 0x2CB173C4
XOR key: 0xD60F77DA
Registry: HKEY_CURRENT_USER\SOFTWARE\Microsoft\Otve
Value 1: Puyqo
Value 2: Yhahezf
Value 3: Obivq
Executable: Wuebx\anaxu.exe
Data file: Neme\wuwe.dat
Conclusion

This is just one example of taking memory analysis to the next level and I hope it reminds everyone that Volatility isn't just a tool for carving Windows data structures and finding evidence to correlate with disk, registry, and network artifacts. Volatility is a powerful, flexible tool limited only by your own creativity. Every Friday (or every day, depending on how much trouble you want to get into with your boss) we invite you to stop what you're doing and join the fun of pushing the limits of memory analysis. What do you want to do next?

View the zeusscan1 source code here.
View the zeusscan2 source code here.
To use the plugins, you need Yara, the 2.1 alpha branch of Volatility, and malware.py.

Until the next Volatility Friday....

5 comments:

Anonymous said...

I get the below error whilst attempting this:

def render_text
for p, start, url, config_key, creds_key, decoded_config, decoded_magic in data:
File "C:\Documents and Settings\Administrator\Desktop\volatility\volatility\plugins\zeusscan2.py", line 236, in calculate
sections = list(self.get_sections(ps_ad, nt_header))
AttributeError: 'ZeusScan2' object has no attribute 'get_sections'

bongaumartin said...

Hi MHL,
I've been your avid fan and I do really appreciate your effort and contribution to our community.

I am trying to use the 2 zeusscan python scripts against the memdump you've also provided but I am getting this error.

Volatile Systems Volatility Framework 2.1_alpha
Traceback (most recent call last):
File "vol.py", line 135, in
main()
File "vol.py", line 126, in main
command.execute()
File "/home/fmartinez/Volatility/volatility/commands.py", line 101, in execute
func(outfd, data)
File "/home/fmartinez/Volatility/volatility/plugins/zeusscan2.py", line 319, in render_text
for p, start, url, config_key, creds_key, decoded_config, decoded_magic in data:
File "/home/fmartinez/Volatility/volatility/plugins/zeusscan2.py", line 236, in calculate
sections = list(self.get_sections(ps_ad, nt_header))
AttributeError: 'ZeusScan2' object has no attribute 'get_sections'

My apologies but I am a newbie for python and would be grateful if you could help me out on this.

Thanks again in advance.

Michael Hale Ligh said...

Ah, it sounds like the zeusscan plugin is caught in limbo between Volatility 2.0 and 2.1alpha versions. Its using one function that only exists in 2.0 and one function that exists in 2.1 (making it incompatible with both versions). A while ago before the 2.1 changes, it worked fine, so I'll fix it up this weekend and let you know.

Michael Hale Ligh said...

Alright that should be taken care of:

http://code.google.com/p/malwarecookbook/source/detail?r=132

Let me know if you still have issues (they should now work with 2.0 or 2.1 alpha).

bongaumartin said...

Thank you very much Michael for your time and effort rectifying your scripts. They are perfectly working now.

More power!

Cheers!