Poison Ivy RAT. Configuration & Communications

Poison Ivy RAT Configuration & Communications [email protected] [email protected] 10-21-2013 1 Poison Ivy RAT: Configuration & C...
Author: Cassandra Cole
4 downloads 0 Views 2MB Size
Poison Ivy RAT Configuration & Communications [email protected] [email protected] 10-21-2013

1

Poison Ivy RAT: Configuration & Communications

CONTENTS INTRODUCTION

2

I. RAT CONFIGURATION

3

X. Code injection

3

A. STAGE1

3

B. STAGE2/STAGE3

5

II. COMMUNICATIONS

7

A. Startup process

7

B. Standard communication

8

III. FINDING POISON IVY

18

A. On the machine

18

B. In the network

19

CONCLUSION

20

REFERENCES

21

APPENDIX

22

A. Structs / enums

22

B. Scanning running processes memory

25

C. Key-dependent snort rules generation script

32

2

Poison Ivy RAT: Configuration & Communications

INTRODUCTION Actually, there are many papers dealing with the Poison Ivy rat. We won’t describe the whole Poison Ivy stuff, FireEye labs released a great one [1] (really worth the reading). This paper is just a documentation we made after an analysis and we wanted to share. It is mainly focused on how it is possible to:  Locate and parse the Poison Ivy configuration  Decrypt and parse Poison Ivy communications We did not perform the whole reverse-engineering process of Poison Ivy, and we just put here what we found useful*: for instance, several commands and configuration values are not documented. However, it may be useful for some people**. *ok, this is just an excuse: I’m lazy. ** other lazy people :]

3

Poison Ivy RAT: Configuration & Communications

I. RAT CONFIGURATION X. Code injection Poison Ivy can perform various code injections in its process. Depending on the injection stage, the configuration can be stored in different formats. We will use the STAGEX descriptor to identify the injection step: 

STAGE1: Poison Ivy is not started (binary file), or has just been launched (1st process)



STAGE2: Poison Ivy has injected machine code (persistence) into the explorer.exe process



STAGE3: Poison Ivy has injected machine code (main payload) into a running process (default browser, etc.)

These injections are performed using WriteProcessMemory/CreateRemoteThread technique. Depending on the rat configuration, Poison Ivy may also not perform any kind of injection and run in its startup process. The STAGE1 configuration differs with the STAGE2 and STAGE3 configurations. A. STAGE1 1. Location The configuration is directly hardcoded on the binary file itself: it is possible to extract it from this file or from its memory. If it is packed, this process can be paused after unpacking (i.e. placing a breakpoint on the CreateMutexA function, which is used at startup to assess the system infection status). The configuration can be found 0x1FB bytes after this pattern: 5E81C6FB0100008DBD84F0FFFF0FB7060FB74E0283C60403C751515650FF952DF1FFFF5903F1 66833E0075E183C6028975F866833E0074110FB7060FB74E0283

5e 81c6 fb010000 [...]

POP ESI ADD ESI, 0x1FB

; loads config addr

2. Parsing The configuration is a list of options which describe parameters. Any configuration option follows this structure: typedef struct _config_option{ WORD parameter_id; WORD parameter_length; BYTE parameter[]; } config_option;

//option unique identifier

4

Poison Ivy RAT: Configuration & Communications

Relevant configuration options are: ID 0x0f04

TYPE ANSI string

DESCRIPTION Active Setup value name (always « Stubpath »)

0x1804

ANSI string

Default browser path registry key

0x5604

ANSI string

Active Setup registry key

0xFA0A

ANSI string

RAT identifier

0xF90B

ANSI string

GROUP identifier

0x9001

c2_server_struct Connection information (proxy or C&C servers: if no proxy is set, the C&C servers will be indicated with this flag. If both are set, the 0xC502 id will be used for C&C information)

0xC502

c2_server_struct Connection information (C&C servers)

0x8C01

DWORD

C&C servers count -1

0xC102

DWORD

Proxy servers count -1

0x4501

ANSI string

Encryption key

0xFB03

ANSI string

Mutex name

0xF40A

BYTE

Hijack proxy flag

0xF50A

BYTE

Persistant proxy hijack flag

0x2D01

ANSI string

RAT filename

0xF703

BYTE

Installation folder identifier 0x01: %systemroot% 0x02: %systemroot%\system32

0xF903

BYTE

Persistance flag

0x4204

ANSI string

Custom injection process name

0x4104

BYTE

Custom injection process name flag

0x120E

ANSI string

HKLM/HKCU registry value name

0x090D

BYTE

HKLM/HKCU registry key persistance flag

0x120D

BYTE

ADS feature flag

0x080D

BYTE

Default browser injection flag

0xFA03

BYTE

Keylogger feature flag

0xF603

BYTE

ActiveX key flag

0x6501

ASCII STRING

ActiveX key name

0xF803

BYTE

Auto-remove dropper flag

0x0000

N/A

Config end

5

Poison Ivy RAT: Configuration & Communications

B. STAGE2/STAGE3 1. Location In the STAGE2 and STAGE3 states, the configuration is copied into a new memory region, along with a custom import address table. This pattern can be identified with the following information: Stage

Pattern

STAGE2

RWE memory zone starting with : • 33 null bytes • kernel32.dll:VirtualAlloc virtual address • kernel32.dll:VirtualFree virtual address • kernel32.dll:CreateThread virtual address

STAGE3

RWE memory zone starting with : • 1 null byte • ws2_32.dll:socket virtual address • ws2_32.dll:connect virtual address • ws2_32.dll:closesocket virtual address • ws2_32.dll:send virtual address • ws2_32.dll:recv virtual address

NB: thanks to Windows ASLR, these virtual addresses can be calculated in a separate process to generate a pattern to scan for. I think static values (such as the ActiveSetup registry key path) can also be used to locate the configuration, but they can be modified quite easily if they are not used.

6

Poison Ivy RAT: Configuration & Communications

2. Parsing The STAGE2/STAGE3 processes in-memory configuration is mapped into a 0x1000 RWE memory region and the information is located at fixed offsets from the start. Relevant configuration information is (offsets starting at the end of import table): OFFSET

TYPE

DESCRIPTION

0x012D 0x0144

→ char[]

RAT filename

0x0145 0x0164

→ char[]

Encryption key

0x0165 0x018A

→ char[]

Active Setup registry key name

0x0190 0x02BF

→ n* c2_server_struct

Connexion information (proxy servers)

0x02C5 0x03EF

→ n* c2_server_struct

Connexion information (C&C servers)

0x03FB 0x0403

→ char[]

Mutex name

0x0442 0x0455

→ char[]

Custom injection process name

0x04B3

Null-terminated ANSI string

Active Setup registry key complete path

0x05B2

Null-terminated ANSI string

RAT dropper file path (only if first time launched)

0x06B1

Null-terminated ANSI string

RAT file path

0x0AfA

Null-terminated ANSI string

RAT identifier

0x0BF9

Null-terminated ANSI string

GROUP identifier

0x0E12

Null-terminated ANSI string

HKLM/HKCU registry value name

There is other stuff in these memory regions; I just focused on most important configuration values (and easily recognizable ones ;]). The c2_server_struct structure is described in appendix A.

7

Poison Ivy RAT: Configuration & Communications

II. COMMUNICATIONS The communication process can be divided into 2 parts: startup process and standard communications. First of all, keep in mind that the cryptographic algorithm used is Camellia ECB. It is a symmetric encryption algorithm which works on 128 bits blobs (0x10 bytes) with a 256 bits key (0x00-padded). A. Startup process Basically, the handshake process follows this scheme: 1) 2) 3) 4)

Handshake Receive and execute PAYLOAD#1 Receive and execute PAYLOAD#2 in a new thread Communication start

1. Handshake The RAT generates 0x100 pseudo-random bytes and sends them to the C&C. Both of them encrypt the blob with their Camellia key, and the C&C sends back the encrypted blob to the RAT. The RAT verifies the response is valid and begins communication. 2. Startup payloads After the handshake step is validated, the C&C sends 2 payloads to the RAT. Both of them follow this structure: typedef struct _startup_payload { DWORD encrypted_payload_length ; BYTE encrypted_payload[] ; } startup_payload;

For instance, payload#1 length is always 0x15D4 bytes: it begins with the 0x000015D0 value. Once the payload is received, it is decrypted and stored into a RWE memory zone, and executed as follows: •

payload( config_address, payload_address )

Payload#2 is loaded by payload#1 into memory and executed into a new thread. Payload#1 resolves payload#2 dependencies before executing it. Finally, payload#1 is then dedicated to the communications handling: it receives and executes the C&C commands.

8

Poison Ivy RAT: Configuration & Communications

B. Standard communication 1. Basic structuration Any command received is encrypted and can be compressed. To allow the RAT interpreting the data, the commands comports an encrypted not compressed 0x20 bytes header. typedef struct _payload { BYTE header[0x20] ; BYTE data[] ; // can be compressed... or not }payload;

Depending on header information, data can be compressed. The compression is performed using the RtlCompressBuffer & RtlDecompressBuffer functions using the COMPRESSION_FORMAT_LZNT1 algorithm identifier. The rat uses the same formalism to send back responses to the C&C. Headers comports command/stream identifiers, which allows the C&C to link responses to past commands. 2. Header parsing The header struct is: typedef struct _header { DWORD command_id; DWORD stream_id; DWORD dwDataLen; DWORD dwRealDataLen; DWORD dwUncompressedDataLen; DWORD dwTotalStreamSize; DWORD padding1; DWORD padding2; }header;

// // // // // //

command identifier stream identifier (thanx FE) data length (to be received) data length (to be received) uncompressed data length total command stream length

If dwUncompressedDataLen >= dwRealDataLen, data is compressed and must be decompressed before execution. Remark: [2] reports a stack overflow on this implementation: the allocated memory for the data is a 0x8000 bytes buffer. If the data (and dwDataLen parameter) is bigger, the overflow is triggered. The source of this vulnerability can either be a mistake from the rat creator or a backdoor…

9

Poison Ivy RAT: Configuration & Communications

3. Command parsing Enumerating the different values of command_id allows guessing which command is performed in the data field. Once decrypted (and decompressed), the data can follow 2 schemes: • If the command has never been issued before, the C&C will send a shellcode + parameters. The shellcode will be executed in a dedicated thread. In this case, data 1st DWORD is not 0x00000000 (in fact, it is the shellcode length in most cases). • If the command has been issued at least one time before, the C&C will just send the parameters. In that case, data 1st DWORD value is 0x00000000. NB: in several cases, the Shellcode command is never issued as the command is natively supported by the RAT/payload#1. You will find in the following tables each command details (id, parameters, etc.). We just documented most important commands and responses (=> few :]) for DFIR purpose. If anyone wants to complete these tables without reverse-engineering the whole client, this can be done in at least 2 ways (we used both of them): 

Placing an inline hook on the encryption (or decryption) routine, and log input (or output)



Writing a basic Poison Ivy parser, getting in a MITM position (2 VMs), giving it the traffic and displaying the data

10

Poison Ivy RAT: Configuration & Communications

4. Commands

ID (header) Hex value

Functionalities Description

Parameters(data) Offset

type

Shellcode + command data

Offset

type

Command data (without shellcode)

Offset

type

Response data

The following word indicates that other parameters immediately follow the previous one. Structs & enum are descripted in appendix A.

Filesystem features ID (header) 0x02

0x04

Functionalities Change directory + list directory

File download

Parameters(data) 0xFD3

char[]

path

0x0B

char[]

path

0x00

N * resp_0x2

Files information

0x12

char[]

Filename

0x00 0x30 0x34

char[] DWORD BYTE

Filename File length File content

0x03

Refresh

N/A

0x05

Search file

N/A

0x2A

Stop searching file

N/A

0x06

Upload file command

0x08

char[]

File path

File upload

0x00

BYTE[]

File content

(immediately following the upload file command)

0x07

Create directory

0x0A

char[]

Directory path / name

0x09

Rename file or directory

0x105 following

pi_string char[]

Filename New name

0x0A following

pi_string char[]

filename new name

0xC7

pi_string

filename

0x0A

pi_string

filename

char[]

path

0x0B

char[]

path

0x337

char[]

path

0x0A

0x0B 0x0C

Delete file (immediately followed by a refresh command)

Refresh current directory 0xFD3 Delete directory

11

Poison Ivy RAT: Configuration & Communications

0x3E 0x42

Wipe file Download directory (followed by 0x42 and 0x04 commands)

0x0A

char[]

path

0x328

pi_string

filename

0x0B

pi_string

filename

0x686

pi_string

dirname

0x0A

pi_string

dirname

Running processes features ID (header)

Functionalities

Parameters(data)

0x14

List running processes

N/A

0x15

Kill process (followed by a 0xC0 0x14 command) 0x0a

WORD

Process ID

WORD

Process ID

0x48

List running processes (without modules information)

N/A

0x54

Suspend/resume process 0x133 WORD

Process ID

0x0B

WORD

Process ID

Command prompt features ID (header)

Functionalities

0x16

Start command prompt

0x17

Send command

0x18

Close command prompt

Parameters(data) N/A 0x0A

char[]

Command (DOS) N/A

Taking screenshots ID (header)

Functionalities

0x19

Take screenshot

0x0F

Keystroke injection

Parameters(data) N/A 0x206 0x20A

DWORD BYTE[]

Window HANDLE Injected data (keystroke)

0x0A 0x0E

DWORD BYTE[]

Window HANDLE Injected data (keystroke)

12

Poison Ivy RAT: Configuration & Communications

Registry features: registry keys ID (header) 0x1E

0x1F

Functionalities List registry key subkeys

List registry key values

Parameters(data) 0x30D 0x311

registry_hive char[]

Registry hive Key path

0x0A 0x0E

registry_hive char[]

Registry hive Key path

0x30D 0x311

registry_hive char[]

Registry hive Key path

0x0A 0x0E

registry_hive char[]

Registry hive Key path

0x20

Delete registry key

0x0A 0x0E

registry_hive char[]

Registry hive Key path

0x21

Rename registry key

0xA9F 0xAA3 following following

registry_hive pi_string pi_string char[]

Registry hive Key path Key name New name

0x0A 0x0E following following

registry_hive pi_string pi_string char[]

Registry hive Key path Key name New name

0x0A 0x0E

registry_hive pi_string

Registry hive Key path

0x25

Create registry key

Registry features: registry values ID (header) 0x22

0x23

Functionalities Create registry value

Rename registry value

Parameters(data) 0x16C 0x170 0x174 following following

registry_hive registry_value_type pi_string pi_string BYTE[]

Registry hive Value type Key name Value name Value

0x0A 0x0E 0x12 following following

registry_hive registry_value_type pi_string pi_string BYTE[]

Registry hive Value type Key name Value name Value

0x1FD following following following

registry_hive pi_string pi_string pi_string

Registry hive Key name Value name New name

0x0A following following

registry_hive pi_string pi_string

Registry hive Key name Value name

13

Poison Ivy RAT: Configuration & Communications

following 0x24

Delete registry value

pi_string

New name

0x155 0x159 following following

registry_hive pi_string pi_string

Registry hive Key name Value name

0x0A 0x0E following

registry_hive pi_string pi_string

Registry hive Key name Value name

0x36

Search registry

N/A

0x37

Stop registry search

N/A

Services features ID (header)

Functionalities

Parameters(data)

0x2B

List installed services

0x2C

start / stop / uninstall 0x15F service 0x160

0x2E

0x30

install service

edit service

N/A service_action pi_string

Command service name

0x0A 0x0B

service_action pi_string

Command service name

0x2B3 following following following following following following following

pi_string pi_string pi_string pi_string pi_string service_type service_start service_start_now

service name display name file path run as description type start mode start now

0x0A following following following following following following following

pi_string pi_string pi_string pi_string pi_string service_type service_start service_start_now

service name display name file path run as description type start mode start now

0x248 following following following following following following following

pi_string pi_string pi_string pi_string pi_string service_type service_start service_start_now

service name display name file path run as description type start mode start now

0x0A

pi_string

service name

14

Poison Ivy RAT: Configuration & Communications

following following following following following following following

pi_string pi_string pi_string pi_string service_type service_start service_start_now

display name file path run as description type start mode start now

Network connections features ID (header)

Functionalities

Parameters(data)

0x38

List network connections

N/A

0x3D

Kill network connection

0x61 0x69

ip_struct ip_struct

Source IP + port Destination IP + port

0x0E 0x16

ip_struct ip_struct

Source IP + port Destination IP + port

Credentials dump features ID (header)

Functionalities

Parameters(data)

0x3C

Dump standard credentials

N/A

0x5A

Dump WiFi credentials

N/A

0x5B

Dump NT/NTLM hashes

0x00

N* hash_struct

Usernames + hashes

Installed software features ID (header) 0x58 0x59

Functionalities

Parameters(data)

List software Uninstall software or uninstall information retrieval (data length is shorter)

N/A 0x3D6

pi_string

Application name

0x0E

pi_string

Application name

Windows features ID (header)

Functionalities

0x0D

List windows

0x0E

Window screenshot

0x0F

Parameters(data) N/A 0x1CC

DWORD

Handle

0x0A

DWORD

Handle

DWORD BYTE[]

Handle Keystrokes

Single-window keystrokes 0x206 0x20A → end

15

Poison Ivy RAT: Configuration & Communications

0x10

0x11

Window operation

Close window

0x0A 0x0E → end

DWORD BYTE[]

Handle Keystrokes

0x67 0x68

window_action DWORD

Operation Handle

0x0A 0x0B

window_action DWORD

Operation Handle

0x54

DWORD

Handle

0x0A

DWORD

Handle

Miscellaneous features ID (header)

Functionalities

Parameters(data)

0x27

Keep-alive

N/A

0x4E

Payload #1

N/A

0x00

RAT information collection (startup)

N/A

0x29

Query system information

0x49

Download keylogger dump

N/A

0x53

Query system information (startup)

N/A

0x08

Execute file

0x55 0x61

Change RAT id Resources monitoring

0x00 following following following following following following following following following

pi_string pi_string pi_string c2_server_struct[5] pi_string pi_string pi_string pi_string pi_string pi_string

Machine name Domain CPU servers Peristance key Key value name Malware filename Malware running undefined Mutex name

0x14B pi_string following pi_string following BYTE

File path Command-line arguments Hidden (0x01 = Yes)

0x0A pi_string following pi_string following BYTE

File path Command-line arguments Hidden (0x01 = Yes)

0x18A

pi_string

New Identifier

0x0B

pi_string

New Identifier N/A

16

Poison Ivy RAT: Configuration & Communications

Proxies & gateways features ID (header) 0x43

Functionalities Create SOCKS4 proxy

Parameters(data) 0xE3D following following following following

WORD pi_string pi_string pi_string WORD

Listening port username Src IP Dst IP Dst port

0x0A following following following following

WORD pi_string pi_string pi_string WORD

Listening port username Src IP Dst IP Dst port

0x44

Get proxy list

0x45

Get GW information

0x00

DWORD

Identifier

0x46

Stop proxy

0xDF

DWORD

Identifier

0x0A

DWORD

Identifier

0xA29 following following following following following following

WORD BYTE pi_string pi_string pi_string pi_string WORD

Listening port Auth ? (1=Yes) username password (if auth) Src IP Dst IP port

0x0A following following following following following following

WORD BYTE pi_string pi_string pi_string pi_string WORD

Listening port Auth ? (1=Yes) username password (if auth) Src IP Dst IP port

0x47

Create SOCKS5 proxy

N/A

0x60

Get SOCKS4 proxy information

0x00

DWORD

Identifier

0x4C

Create gateway

0x377 following following following

WORD pi_string WORD pi_string

Listening port Dst IP Dst port Src filter

0x0A following following following

WORD pi_string WORD pi_string

Listening port Dst IP Dst port Src filter

17

Poison Ivy RAT: Configuration & Communications

Microphone & webcam features ID (header)

Functionalities

Parameters(data)

0x5C

Start recording

N/A

0x5D

Stop recording

N/A

0x34

Start webcam capture

N/A

18

Poison Ivy RAT: Configuration & Communications

III. FINDING POISON IVY With all this information, we tried to identify how generic Poison Ivy malwares can be found on a system or on the network.

A. On the machine 1. System There are various ways to find a Poison Ivy rat on a Windows system. As Poison Ivy may use Alternate Data Streams to hide itself, this behavior can be used against it, by searching: •

ADS attached to the %systemroot% or %systemroot%\system32 folders

• ADS in the startup keys (HKLM/HKU Run keys, Active Setup keys), easily identified by the “:” character •

ADS in the prefetch folder: the prefetcher will create SYSTEM32 or WINDOWS prefetch files.

Also, Poison Ivy stores its identifier in a separate file, in its own folder, which has the same name without extension. This can also be used to spot suspicious files. As Poison Ivy may inject itself in the default browser, a running browser process without any window may reveal an infection. Finally, one of these Poison Ivy default configuration values in a file may also reveal a nonpacked Poison Ivy binary: "\x18\x04\x28\x00SOFTWARE\\Classes\\http\\shell\\open\\command" "\x04\x35\x00\x53Software\\Microsoft\\Active Setup\\Installed Components\\" "\x0f\x04\x08\x00StubPath" 5E81C6FB0100008DBD84F0FFFF0FB7060FB74E0283C60403C751515650FF952DF1FFFF5903F1668 33E0075E183C6028975F866833E0074110FB7060FB74E0283

19

Poison Ivy RAT: Configuration & Communications

2. Memory As Poison Ivy injects various data in process memory, several markers can be used to identify this malware (performing a basic memory scan on RWE memory regions, for instance). Signature

Injection stage

"\x18\x04\x28\x00SOFTWARE\\Classes\\http\\shell\\open\\command"

STAGE1 (config.)

"\x04\x35\x00\x53Software\\Microsoft\\Active Setup\\Installed Components\\"

STAGE1 (config.)

"\x0f\x04\x08\x00StubPath"

STAGE1 (config.)

5E81C6FB0100008DBD84F0FFFF0FB7060FB74E0283C60403C751515650FF952D STAGE1 F1FFFF5903F166833E0075E183C6028975F866833E0074110FB7060FB74E0283 (config. loader

payload) 558BEC81C430FAFFFF8B75088D86FB030000506A006A00FF96850000008986C5 STAGE2/STAGE3 080000FF96890000003DB70000007504C9C20400568D866B090000508D864501 (shellcode)

If you ever plan to build your own memory scan tool to search processes memory for signatures, we put a very basic implementation in Appendix B. B. In the network Except using ET signatures (mostly encryption key-based [3], [4]), several behaviors can be used to detect the malware. 1. Handshake-based signatures To detect a successful handshake: •

$HOME_NET  0x100 bytes  $EXTERNAL_NET (challenge)



$EXTERNAL_NET  0x100 bytes  $HOME_NET (response)



$EXTERNAL_NET  0x15D4 bytes beginning with 0x000015D0  $HOME_NET (payload#1)

2. Keep-alive-based signatures The keep-alive is cyphered and its content depends to the encryption key. Thus this is not possible to create content-based signatures key-independent. However, the decrypted keep-alive content never changes and it is possible to detect send/receive couples of identical 0x30 binary data. In addition, as the keep-alive header never changes, encryption key can be bruteforced (just like malware.lu guys [5] did, without sending anything to the C&C server). Knowing the encryption key, it is also possible to create key-dependent signatures (cf. ET signatures). To generate those signatures, you must first find a constant plain text aligned with the camellia block size (0x10). In a spirit of cooperation, we chose the same block as the previous signature writers (i.e the second 0x10 block of the protocol frame header). See Appendix C.

20

Poison Ivy RAT: Configuration & Communications

CONCLUSION Uh… well, we hope this paper will be useful (if so, we love beer) to malware researchers / incident responders who face this malware and will upset Poison Ivy users (who said they will migrate to PlugX?). Thanks for the reading :]

21

Poison Ivy RAT: Configuration & Communications

REFERENCES [1] FireEye analysis (really complete): http://www.fireeye.com/resources/pdfs/fireeye-poison-ivy-report.pdf [2] PoisonIvy stack overflow vulnerability: http://badishi.com/own-and-you-shall-be-owned/ http://badishi.com/poison-ivy-exploit-metasploit-module/ http://badishi.com/decrypting-poison-ivys-communication-using-code-injection-and-dll-proxies/ http://badishi.com/initial-analysis-of-poison-ivy/ [3] PoisonIvy emerging threats rules update (key-based, linked to the FireEye analysis report): http://www.emergingthreats.net/2013/08/21/daily-ruleset-update-summary-08212013/ [4] Emerging threats key-based signature example (“MenuPass” key):

http://doc.emergingthreats.net/bin/view/Main/2013922 [5] Malware.lu PoisonIvy analysis, with the encryption key bruteforcing attack: http://www.malware.lu/Pro/RAP002_APT1_Technical_backstage.1.0.pdf Official website: http://www.poisonivy-rat.com/

22

Poison Ivy RAT: Configuration & Communications

APPENDIX A. Structs / enums typedef struct _pi_string { BYTE byStrLen; // str size, in bytes char str[]; // not null-terminated } pi_string; typedef struct _resp_0x2 { pi_string name[]; BYTE misc_info[0x18]; } resp_0x2; typedef enum _service_action { Uninstall = 0x00, Stop, Start } service_action;

// file/dir name // various information (mactime, type…)

// size : USHORT

typedef enum _service_type // size : ULONG { device_driver = 0x00000001, fs_driver = 0x00000002, std_driver = 0x00000010, shared_driver = 0x00000020 }service_type;

typedef enum _service_start { automatic = 0x00000002, manual = 0x00000003, disabled = 0x00000004 } service_start;

// size : ULONG

typedef enum _service_start_now // size : USHORT { no = 0x00, yes = 0x01 } service_start;

23

Poison Ivy RAT: Configuration & Communications

typedef enum _registry_hive { HKEY_CLASSES_ROOT = 0x00000000, HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE, HKEY_USERS, HKEY_WTF, HKEY_CURRENT_CONFIG } registry_hive;

// size : ULONG

typedef enum _registry_value_type { REG_SZ = 0x01, REG_EXPAND_SZ, REG_BINARY, REG_DWORD, REG_WTF1, REG_WTF2, REG_MULTI_SZ } registry_value_type;

// size : USHORT

typedef struct { BYTE BYTE BYTE BYTE WORD port; } ip_struct;

_ip_struct ip1; ip2; ip3; ip4;

typedef struct _hash_struct { BYTE hash_nt[0x10]; BYTE hash_lm[0x10]; DWORD username_length; // username size in bytes CHAR username[]; // may contain non-printable chars } hash_struct ; typedef enum _window_action { maximize = 0x03, show = 0x05, hide = 0x00, minimize = 0x06 } window_action; typedef struct _header { DWORD command_id; DWORD stream_id; DWORD dwDataLen; DWORD dwRealDataLen; DWORD dwUncompressedDataLen; DWORD dwTotalStreamSize; DWORD padding1; DWORD padding2; }

// size : USHORT

// // // // // //

command identifier stream identifier (thanx FE) data length (to be received) data length (to be received) uncompressed data length total command stream length

24

Poison Ivy RAT: Configuration & Communications typedef struct _payload_startup { DWORD dwDataLen; // data size, in bytes BYTE data[]; // encrypted payload } payload_startup; #define c_and_c_server #define socks4_proxy_server #define http_proxy_server

0x00 0x01 0x02

typedef struct _c2_server_struct { BYTE btFqdnLen; // fqdn size, in bytes CHAR fqdn[]; // C&C fqdn / IP BYTE server_type; // server type WORD port; } c2_server_struct; typedef struct _config_option { WORD parameter_id; WORD parameter_length; BYTE parameter[]; } config_option; typedef struct _payload { BYTE header[0x20] ; BYTE data[] ; // can be compressed... or not } payload;

25

Poison Ivy RAT: Configuration & Communications

B. Scanning running processes memory For anyone wanting to automate scanning running processes memory for patterns, this can be done following these steps: 1. Get the SE_DEBUG_NAME privilege 2. Loop into the running processes list (CreateToolhelp32Snapshot / Process32First /Process32Next) 3. Get memory regions information with VirtualQueryEx 4. For each memory region copy it in your process memory using the ReadProcessMemory function 5. Search for your pattern Poison Ivy p0c: #ifdef UNICODE #undef UNICODE #endif #include #include #include // memory region typedef struct _memoryRegion { ULONG baseAddress; ULONG size; ULONG type; ULONG protect; ULONG state; PVOID blink; }memoryRegion, *pmemoryRegion; // memory pattern typedef struct _mempattern { ULONG protect; WORD patternId; ULONG patternlen; PVOID pattern; PVOID flink; }mempattern, *pmempattern;

// // // // // //

base address size memory type protection (mask!) memory state next region

// memory protection // pattern unique identifier // pattern length // BYTE[pattern length] pattern

DWORD elevate_access_rights(); DWORD __fastcall memscan(_In_ pmempattern mempatterns); DWORD __fastcall processMemScan(_In_ ULONG pid, _In_ pmempattern mempatterns); PVOID __stdcall searchMem(_In_ PVOID needle,_In_ ULONG needleLen,_In_ PVOID memory,_In_ ULONG memoryLen); // main => scan for PIVY :] int main(int argc, char** argv) { pmempattern list, current; BYTE pattern1[]={

26

Poison Ivy RAT: Configuration & Communications 0x5E,0x81,0xC6,0xFB,0x01,0x00,0x00,0x8D, 0xBD,0x84,0xF0,0xFF,0xFF,0x0F,0xB7,0x06, 0x0F,0xB7,0x4E,0x02,0x83,0xC6,0x04,0x03, 0xC7,0x51,0x51,0x56,0x50,0xFF,0x95,0x2D, 0xF1,0xFF,0xFF,0x59,0x03,0xF1,0x66,0x83, 0x3E,0x00,0x75,0xE1,0x83,0xC6,0x02,0x89, 0x75,0xF8,0x66,0x83,0x3E,0x00,0x74,0x11, 0x0F,0xB7,0x06,0x0F,0xB7,0x4E,0x02,0x83 }; BYTE pattern2[]={ 0x55,0x8B,0xEC,0x81,0xC4,0x30,0xFA,0xFF, 0xFF,0x8B,0x75,0x08,0x8D,0x86,0xFB,0x03, 0x00,0x00,0x50,0x6A,0x00,0x6A,0x00,0xFF, 0x96,0x85,0x00,0x00,0x00,0x89,0x86,0xC5, 0x08,0x00,0x00,0xFF,0x96,0x89,0x00,0x00, 0x00,0x3D,0xB7,0x00,0x00,0x00,0x75,0x04, 0xC9,0xC2,0x04,0x00,0x56,0x8D,0x86,0x6B, 0x09,0x00,0x00,0x50,0x8D,0x86,0x45,0x01 }; char pattern3[]="\x18\x04\x28\x00SOFTWARE\\Classes\\http\\shell\\open\\command"; char pattern4[]="\x04\x35\x00\x53Software\\Microsoft\\Active Setup\\Installed Components\\"; char pattern5[]="\x0f\x04\x08\x00StubPath"; current = NULL; list = (pmempattern)malloc(sizeof(mempattern)); list->patternId = 1; list->pattern = pattern1; list->patternlen = sizeof(pattern1); list->protect = PAGE_EXECUTE_READWRITE; list->flink = current; current = list; list = (pmempattern)malloc(sizeof(mempattern)); list->patternId = 2; list->pattern = pattern2; list->patternlen = sizeof(pattern2); list->protect = PAGE_EXECUTE_READWRITE; list->flink = current; current = list; list = (pmempattern)malloc(sizeof(mempattern)); list->patternId = 3; list->pattern = pattern3; list->patternlen = sizeof(pattern3)-1; list->protect = PAGE_EXECUTE_READWRITE; list->flink = current; current = list; list = (pmempattern)malloc(sizeof(mempattern)); list->patternId = 4; list->pattern = pattern4; list->patternlen = sizeof(pattern4)-1; list->protect = PAGE_EXECUTE_READWRITE; list->flink = current; current = list; list = (pmempattern)malloc(sizeof(mempattern)); list->patternId = 5; list->pattern = pattern5; list->patternlen = sizeof(pattern5)-1; list->protect = PAGE_EXECUTE_READWRITE; list->flink = current;

27

Poison Ivy RAT: Configuration & Communications

printf("Find PIVY p0c\n"); elevate_access_rights(); if(memscan(list)==ERROR_VIRUS_INFECTED) printf("PIVY found.\n"); else printf("PIVY not found.\n"); current = list; while(current!=NULL) { list = current; current = (pmempattern)(current->flink); free(list); } return 0; } /******************************** Get SE_DEBUG_NAME. ********************************/ DWORD elevate_access_rights() { TOKEN_PRIVILEGES priv; HANDLE n1; LUID luid; if(!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY, &n1)) { return ERROR_ACCESS_DENIED; } if(!LookupPrivilegeValueA(NULL, "SeDebugPrivilege", &luid)) { return ERROR_ACCESS_DENIED; } priv.PrivilegeCount=1; priv.Privileges[0].Luid=luid; priv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; if(!AdjustTokenPrivileges(n1, FALSE, &priv, sizeof(priv), NULL, NULL)) { return ERROR_ACCESS_DENIED; } CloseHandle(n1); return ERROR_SUCCESS; } /******************************** List running processes and scan 'em all ********************************/ DWORD __fastcall memscan( _In_ pmempattern mempatterns) { HANDLE hThlp; PROCESSENTRY32 pe; DWORD found; DWORD retval; if(mempatterns == NULL) return ERROR_INVALID_PARAMETER;

28

Poison Ivy RAT: Configuration & Communications

found = ERROR_SUCCESS; pe.dwSize=sizeof(PROCESSENTRY32); if(elevate_access_rights() != ERROR_SUCCESS) { printf("[!] Insufficient privileges.\n"); return ERROR_ACCESS_DENIED; } // Enumerates the running process list hThlp=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0); if(hThlp==INVALID_HANDLE_VALUE) { printf("[!] Process enumeration failed.\n"); return ERROR_OPEN_FAILED; } if(!Process32First(hThlp,&pe)) { printf("[!] Process enumeration failed\n"); CloseHandle(hThlp); return ERROR_OPEN_FAILED; } do { if(pe.th32ProcessID!=0 && pe.th32ProcessID!=GetCurrentProcessId()) { printf("\t[-] Scan %s...",pe.szExeFile); retval = processMemScan(pe.th32ProcessID,mempatterns); if(retval == ERROR_VIRUS_INFECTED) { found = ERROR_VIRUS_INFECTED; } else if(retval == ERROR_SUCCESS) { printf(" CLEAN.\n"); } } }while(Process32Next(hThlp,&pe)); CloseHandle(hThlp); return found; } /******************************** Scans a running process for patterns ********************************/ DWORD __fastcall processMemScan( _In_ ULONG pid, _In_ pmempattern mempatterns) { HANDLE hProcess; pmempattern currentPattern = mempatterns; BOOL continueScan; DWORD found = ERROR_SUCCESS; PVOID regionMemory; PVOID match; ULONG i = 0; MEMORY_BASIC_INFORMATION mbi;

29

Poison Ivy RAT: Configuration & Communications pmemoryRegion last, current; DWORD dwRead; last=NULL; if(pid == 0 || mempatterns == NULL) { return ERROR_INVALID_PARAMETER; } // opens the process with minimal required access rights. hProcess = OpenProcess(PROCESS_VM_READ|PROCESS_QUERY_INFORMATION,FALSE,pid); if(hProcess==NULL) { printf("\n\t\t[!] Cannot open process.\n "); #ifdef DEBUG printf("\n\t\t[!] processMemScan :: OpenProcess() failed.\n",pid); #endif return ERROR_ACCESS_DENIED; } // gather the virtual memory regions of the process for(i = 1; VirtualQueryEx(hProcess,(PVOID)i,&mbi,sizeof(MEMORY_BASIC_INFORMATION))==sizeof( mbi) ; i += mbi.RegionSize) { current = (pmemoryRegion)malloc(sizeof(memoryRegion)); current->baseAddress=(ULONG)mbi.BaseAddress; current->size=mbi.RegionSize; current->protect=mbi.Protect; current->state=mbi.State; current->type=mbi.Type; current->blink=last; last=current; } // For each memory region while(current!=NULL) { // Search the pattern currentPattern=mempatterns; while(currentPattern != NULL) { continueScan = TRUE; // Memory access test if(currentPattern->protect!=0) { // tests the memory access rights if((currentPattern->protect & current->protect) == 0) { continueScan=FALSE; } } if(continueScan) { regionMemory = malloc(current->size); // copy the whole memory region if(ReadProcessMemory(hProcess,(PVOID)current>baseAddress,regionMemory,current->size,&dwRead)!=0) { // search match = searchMem(currentPattern-

30

Poison Ivy RAT: Configuration & Communications >pattern,currentPattern->patternlen,regionMemory, current->size); while(match != NULL) { found = ERROR_VIRUS_INFECTED; // match printf("\n\t\t[-] Pattern %d matched at 0x%.8x\n",currentPattern->patternId, ((ULONG)match-(ULONG)regionMemory+current>baseAddress)); // => dump data at "match" if needed match = (PVOID)((ULONG)match+currentPattern>patternlen); match = searchMem(currentPattern>pattern,currentPattern->patternlen,match, ((ULONG)regionMemory + current->size - (ULONG)match)); } } free(regionMemory); } // next currentPattern = (pmempattern)currentPattern->flink; } // next memory region current=(pmemoryRegion)current->blink; } current = last; while(current != NULL) { last = (pmemoryRegion)current->blink; free(current); current = last; } return found; } /******************************** Searchs "needle" in "memory" space. The respective lengths are needleLen and memoryLen. /!\ NO INPUT CHECKS PERFORMED /!\ ********************************/ __declspec(naked) PVOID __stdcall searchMem( _In_ PVOID needle, _In_ ULONG needleLen, _In_ PVOID memory, _In_ ULONG memoryLen) { __asm { push ebp mov ebp, esp push esi push edi push ebx mov mov mov mov

eax, edx, edi, esi,

memory needle needleLen memoryLen

// memory regions pointers // memory regions lengths

31

Poison Ivy RAT: Configuration & Communications loop1: // first loop: reads the memory region add esi, eax xor ecx, ecx loop2:

// second loop: searchs the current memory

pointer for the pattern mov cmp jnz add cmp jnz

bl, byte ptr ds:[edx+ecx] bl, byte ptr ds:[eax+ecx] breakloop2 ecx,1 ecx, edi loop2

jmp epilogFound breakloop2: add eax, 1 sub esi, eax jz epilogNotFound cmp esi, edi jnz loop1 epilogNotFound: xor eax,eax epilogFound: pop ebx pop edi pop esi mov esp, ebp pop ebp ret 0x10 } }

// return NULL // restore registers

32

Poison Ivy RAT: Configuration & Communications

C. Key-dependent snort rules generation script

#!/usr/bin/ruby begin require 'camellia' rescue LoadError puts ':( It seems some dependencies are missing' puts 'gem install camellia-rb' end class CamelliaECB def initialize(pass) #null pad the password to the right length pass = pass+"\x00"*(32-pass.length) unless pass.length >= 32 pass = pass[0...32] #or truncate it, whatever @cypher = Camellia.new(pass) End def encrypt(string) enc='' while string.length > 0 do blob = string[0...16] string = string[16..-1] enc

Suggest Documents