viernes, 11 de enero de 2013

Volatility VS Citadel 1.3.4.5

As a forensic and malware analyst, I have always been a big fan of Volatility, the Python coded memory analysis tool that keeps growing day by day. Thus, since I read Michael Ligh's article on his blog about the extraction of the ZeuS' encryption keys, I was willing to try out the same thing with another malware family as well.

I’ve chosen Citadel in this case, that is one of the most widely used ZeuS’s variants since its source code leakage. Specifically the version 1.3.4.5 that, while not the last one, will be the basis for subsequent versions (although it is rumored that 1.3.5.1 could be the last we see) or other families.

When using Volatillity and Yara together, the power available for automatic malware processing increases. "zeusscan2", one of the plugins resulting from the article mentioned above, is based on both things. It makes use of Yara rules against an infected machine’s memory to detect and access those memory regions that most likely contains the information we want to extract from the binary file. This requires a thorough analysis on the family prior to "automate", which in this case, being a variant of the well known and documented Zeus family, the work is limited to detecting differences within it.

As a start point, we know that ZeuS 2.X contains the following information embedded in the binary:
  • Initial config file download URL
  • RC4 key used to decipher the config file
  • Info about the location of the binary and his config on the infected machine
The first two can be found within the binary in a XOR encoded area with the bytes at the beginning of the last PE section, while the latter is an encrypted area using the RC4 key and with a fixed structure (For now on we will refer to it as the "magic object" to follow the convention used in the Volatility’s ZeuS plugin).

Note: In ZeuS’ case there’s a second RC4 encryption key contained in the last commented structure, but since Citadel lacks of it, is not relevant to the purpose of the article.

Thereby, the processing and extraction flow we are searching for should be something like:
  1. Embedded config finding.
  2. XORing with the bytes at the beginning of the last PE section to decode it.
  3. RC4 key and initial config file download URL extraction.
  4. Searching and decoding of the “magic object” with the RC4 key
  5. Rest of data extraction
Now that we know the base which supports Citadel, we can study the differences to adapt the plugin to the new family. The similarities (at binary level at least) are bigger than the differences, so once we understand it, the changes are not complicated.

The main difference comes from the cipher algorithm used to encrypt the downloaded config files (AES instead of RC4), but the “magic object” keeps RC4. The AES key, it’s not within the binary as so, but calculated on runtime in the following way:

RC4(md5(BO_LOGIN_KEY))
The BO_LOGIN_KEY or binary key, is a 16 hexadecimal bytes key that can be found inside the binary and, in addition to compute the AES key, it’s used in the control panel communication, so to the localization of the embedded config and the "magic object", we must add the hardcoded key.

To the workflow above, it should be added:
  1. BO_LOGIN_KEY finding
  2. AES key computing
With all of this, we can choose the following disassembled code to generate the new Yara rules that help us find the commented variables in memory:

8BEC                  MOV EBP,ESP
83EC 0C               SUB ESP,0C
8A82 00010000         MOV AL,BYTE PTR DS:[EDX+100]
8845 FE               MOV BYTE PTR SS:[EBP-2],AL
8A82 01010000         MOV AL,BYTE PTR DS:[EDX+101]
8845 FD               MOV BYTE PTR SS:[EBP-3],AL
8A82 02010000         MOV AL,BYTE PTR DS:[EDX+102]
B9 801A1300           MOV ECX,131A80                      ; BO_LOGIN_KEY
8845 FF               MOV BYTE PTR SS:[EBP-1],AL
E8 BEF2FFFF           CALL 0015BC16
——————————————————————————————————————————————————————
56                    PUSH ESI
BA 54050000           MOV EDX,554                         ; Embedded configuration length
52                    PUSH EDX
68 602A4000           PUSH pyko.00402A60                  ; Embedded configuration
50                    PUSH EAX
E8 47E30100           CALL pyko.004290C1
8B0D B4394300         MOV ECX,DWORD PTR DS:[4339B4]
030D 943D4300         ADD ECX,DWORD PTR DS:[433D94]
8BF2                  MOV ESI,EDX
2BC8                  SUB ECX,EAX
——————————————————————————————————————————————————————
68 03010000           PUSH 103
8D85 10FBFFFF         LEA EAX,[LOCAL.316]
50                    PUSH EAX
8D85 FCFEFFFF         LEA EAX,[LOCAL.65]
50                    PUSH EAX
E8 B4E20100           CALL pyko.004290C1
B8 1C010000           MOV EAX,11C
50                    PUSH EAX
68 283C4300           PUSH pyko.00433C28                  ; Magic object
Once we get to the workflow processing part in which the “magic object” is decoded, we then face to a structure similar to:


This object, like happened with ZeuS 2.X, has a fixed length in most cases and a structure like the following:

{'_ZEUS_MAGIC' : [ 0x11C, {
'struct_size' : [ 0x0, ['unsigned int']], \
'guid' : [ 0x4, ['array', 0x30, ['unsigned short']]], \
'guid2' : [ 0x7C, ['array', 0x10, ['unsigned char']]], \
'exefile' : [ 0x9C, ['array', 0x14, ['unsigned char']]], \
'keyname' : [ 0xEC, ['array', 0xA, ['unsigned char']]], \
'value1' : [ 0xF6, ['array', 0xA, ['unsigned char']]], \
'value2' : [ 0x100, ['array', 0xA, ['unsigned char']]], \
'value3' : [ 0x10A, ['array', 0xA, ['unsigned char']]], \
'guid_xor_key' : [ 0x114, ['unsigned int']], \
'xorkey' : [ 0x118, ['unsigned int']], \
}]}
So we already have everything we wanted:


I hope this example helps to understand a little better all the capabilities Yara and Volatility offers when automating and analyzing malware.

The plugin for the 1.3.4.5 version can be found here. Michael Ligh has also merged it with the previous versions of the ZeuS 1 & 2.X plugins, so from now on it will be shipped with Volatility too, though it won’t be enabled by default; Use the --plugins parameter to access them like this:

$ python vol.py --plugins=contrib/plugins/malware citadelscan1345 -f ....
Regarding 1.3.5.1 version, the process to follow should be similar to the one described, except for a new hardcoded key and the size and structure of the “magic object”, that changes from sample to sample.

Happy analysis!

Note: Originally published on Buguroo's blog

--
Follow me on Twitter: @smvicente