Saturday, January 16, 2010

Trojan.Hydraq - Part II

Previous post described the installation process of the trojan and its backdoor commands.

Now it's time to inspect its connection details, in particular - where does it retrieve the host name of the remote command-and-control (C&C) server.

The source code of the trojan contains a hard-coded host name 192.168.5.164 that is tried out every 5 seconds, but these values must have been used during testing only - they are replaced with the different ones during the runtime - we must establish which ones.

It is also worth noting that the trojan's code is very fragmented - it is deliberately split into small chunks with the size of a few instructions each, connected with the calls and jumps into a large maze: the code of Trojan.Hydraq contains 1,748 jumps and 922 calls - tracing it requires quite a bit of a patience. Graph image of the disassembled source indeed reminds a serpent-like beast - hence, probably, the name.

Hydraq's call-only graph:



The trojan carries its C&C connection details (server, name, port, retry delay, etc.) inside the internal resource (name is 100, type is 243). The resource is 344 bytes in size, and it is encrypted.

Decryption of the resource is performed in 4 stages:

  • The first 8 bytes of the resource are skipped, the remaining 336 bytes are XOR-ed with 0x99

  • Next, every byte from the 336 input buffer is translated according to the following logics:

    • if the byte is a character from 'A' to 'Z', it is subtracted 'A' value (0x41)

    • if the byte is a character from 'a' to 'z', it is subtracted 'G' value (0x47)

    • if the byte is a character from '0' to '9', it is added 4

    • if the byte is a character '+', its replaced with '>'

    • if the byte is a character '/', its replaced with '?'

    • if the byte is a character '=', its replaced with '\0'

    • otherwise, the byte is left as is

  • The input buffer is then converted into the resulting buffer which is 25% smaller. This is achieved by splitting every byte quartet (bytes 0-3) from the input buffer into 3 pairs (0-1, 1-2, 2-3), performing operations over these three pairs, and writing 3 byte results into the output buffer. This way, the 336 bytes will be converted into 252 bytes (4 -> 3 conversion); in some way, it's similar to unpacking all-ASCII base64 back into binary. The operations performed over the 3 pairs are illustrated below:


  • Finally, the resulting 252 bytes are XOR-ed with 0xAB


The fully decrypted resource is shown below:


Knowing this logics, the decryption can now be reconstructed in a stand-alone tool; a function that retrieves and decrypts the resource from the trojan DLL is provided below (should be run from a virus lab as loading the DLL will invoke its entry point):

#define IDD_RES_NAME   100
#define IDD_RES_TYPE 243

void DecodeHydraqResource()
{
    HMODULE hDll;
    HRSRC hRes;
    HGLOBAL hResLoad;
    BYTE lpBuffer[0x150];
    BYTE lpResult[0x150];
    int iResultOffset;
    int i;
    char szHost[MAX_PATH];
    int dwDelay;
    int dwPort;
    char szAltDnsServer[MAX_PATH];
    char szMessage[MAX_PATH * 4];
    BOOL bOk;

    szHost[0] = '/0';
    dwDelay = 0;
    dwPort = 0;
    szAltDnsServer[0] = '/0';
    bOk = FALSE;
    szMessage[0] = '/0';

    hDll = LoadLibrary(_T("sample.dll"));
    if (hDll)
    {
        hRes = FindResource(hDll, MAKEINTRESOURCE(IDD_RES_NAME), MAKEINTRESOURCE(IDD_RES_TYPE));
        if (hRes)
        {
            hResLoad = LoadResource(hDll, hRes);
            if (hResLoad)
            {
                memset(lpResult, 0, 0x150);
                iResultOffset = 0;

                if (SizeofResource(hDll, hRes) == 0x158)
                {
                    memset(lpBuffer, 0, 0x150);
                    memcpy(lpBuffer, (LPBYTE)hResLoad + 8, 0x150);

                    for (i = 0; i < 0x150; i++)
                    {
                        lpBuffer[i] ^= 0x99;

                        if ((lpBuffer[i] >= 'A') && (lpBuffer[i] <= 'Z'))
                        {
                            lpBuffer[i] -= 'A';
                        }
                        else if ((lpBuffer[i] >= 'a') && (lpBuffer[i] <= 'z'))
                        {
                            lpBuffer[i] -= 'G';
                        }
                        else if ((lpBuffer[i] >= '0') && (lpBuffer[i] <= '9'))
                        {
                            lpBuffer[i] += 4;
                        }
                        else if (lpBuffer[i] == '+')
                        {
                            lpBuffer[i] = '>';
                        }
                        else if (lpBuffer[i] == '/')
                        {
                            lpBuffer[i] = '?';
                        }
                        else if (lpBuffer[i] == '=')
                        {
                            lpBuffer[i] = 0;
                        }
                    }

                    for (i = 0; i < 0x150; i++)
                    {
                        lpResult[iResultOffset++] = (lpBuffer[i] * 4) ^ (lpBuffer[i + 1] / 16);
                        lpResult[iResultOffset++] = (lpBuffer[i + 1] * 16) ^ (lpBuffer[i + 2] / 4);
                        lpResult[iResultOffset++] = (lpBuffer[i + 2] * 64) ^ (lpBuffer[i + 3]);
                        i += 3;
                    }

                    for (i = 0; i < 0x150; i++)
                    {
                        lpResult[i] ^= 0xAB;
                    }

                    i = strlen((LPSTR)lpResult);

                    if ((i > 0) && (i < MAX_PATH))
                    {
                        strcpy(szHost, (LPSTR)lpResult);
                        sprintf(szAltDnsServer,
                                _T("%d.%d.%d.%d"),
                                lpResult[iResultOffset - 4],
                                lpResult[iResultOffset - 3],
                                lpResult[iResultOffset - 2],
                                lpResult[iResultOffset - 1]);
                        dwPort = *(LPDWORD)(lpResult + iResultOffset - 12);
                        dwDelay = *(LPDWORD)(lpResult + iResultOffset - 8);
                        sprintf(szMessage,
                                _T("Remote Host: %s\nAlternative DNS Server: %s\nConnection Port: %d\nDelay between connection attempts: %d sec."),
                                szHost,
                                szAltDnsServer,
                                dwPort,
                                dwDelay);
                        bOk = TRUE;
                    }

                }
            }
        }
        FreeLibrary(hDll);
    }

    if (!bOk)
    {
        MessageBox(NULL, _T("Failed to retrieve any details!"), _T("Error"), MB_OK);
    }
    else
    {
        MessageBox(NULL, szMessage, _T("Success"), MB_OK);
    }

}


Once the trojan knows its C&C server, it attempts to connect to it via the specified port - e.g. server sl1.homelinux.org, port 443.

It starts doing so by trying to resolve its host name first. If this attempt fails, the trojan makes a DNS query by crafting a TCP packet on port 53 of an alternative (legitimate) DNS server, also specified in its resource, in order to resolve the same host name. For example, the analysed sample has alternative DNS server 168.95.1.1 - this is dns.hinet.net server located in Taiwan.

If Hydraq can't connect to the remote server, it falls asleep for the time specified in its resource (2 minutes), then repeats the beaconing again.

If the connection to remote host on port 443 succeeds, the malware prepares a packet to send - it is 20 bytes in size:

00 00 00 00 00 00 FF FF 01 00 00 00 00 00 00 00 00 00 77 00

The packet is encoded by inverting its bytes:

FF FF FF FF FF FF 00 00 FE FF FF FF FF FF FF FF FF FF 88 FF

As soon as the packet is submitted to the live C&C server, it receives the response packet that is also 20 bytes in size. It is encrypted with the XOR 0xCC.

Hydraq decodes the received packet and retrieves the command ID from it - a number from 0 to 18, which is then converted into the backdoor command group - a number from 0 to 10. Conversion rules Command ID -> Backdoor Command Group are shown below:

  • 0 -> 0 (adjust privileges, terminate processes)

  • 1 -> 1 (control services group)

  • 2 -> 2 (remote file execution)

  • 3 -> 3 (registry manipulation group)

  • 4 -> 4 (file system manipulation group)

  • 5 -> 10 (receive more data)

  • 6 -> 5 (system manipulations - power off/reboot/uninstall/clear events)

  • 7 -> 6 (file search)

  • 8 -> 7 (call other components)

  • 9 -> 10

  • 10 -> 8

  • 11 -> 10

  • 12 -> 10

  • 13 -> 10

  • 14 -> 10

  • 15 -> 10

  • 16 -> 10

  • 17 -> 10

  • 18 -> 9 (networks.ics file manipulations)

Next, a specific command from the chosen group is executed. For more details on backdoor groups and commands within them, please check the previous post.

It may be assumed that upon successful connection to the remote C&C server (sl1.homelinux.org), the trojan was designed to be able to update itself. A new copy may have a different C&C server specified in its resource (e.g. yahooo.8866.org, 360.homeunix.com or as in the last seen sample - blog1.servebeer.com) in order to survive the shutdown of the old servers.

The presence of a resource that stores all the connection parameters could potentially indicate an intented cloud-based automation for updating the same template with a newly generated resource without the need to recompile the sample, with the obfuscation step added on top of it to evade existing detections. With the relatively high update frequency of such server-side polymorphism, the C&C server shutdown may always fall behind; given the fact the firewalls let the traffic on port 443 through (HTTPS traffic), a heuristic detection of Trojan.Hydraq (added as Trojan.Hydraq!gen1) is a viable option that reliably breaks this vicious circle.

Wednesday, January 13, 2010

Trojan.Hydraq Exposed

The post describes functionality (static analysis) of the trojan that was reported in the recent targeted attacks against some large companies.

Trojan.Hydraq trojan is a DLL that runs as a service within the context of the system process svchost.exe.

In order to be executed within the process svchost.exe at the system startup, the trojan employs no injection techniques - this is achieved with the steps described below.

Firstly, the trojan registers itself as a system service RaS[4 random characters] by creating registry entries under the newly created key:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\RaS[4 random characters]

The "ImagePath" value of its service registry key is set to start svchost.exe, as shown below:

"ImagePath" = %SystemRoot%\system32\svchost.exe -k netsvcs
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\RaS[4 random characters]

This will force the system process svchost.exe to look up its multi-string value "netsvcs", load all services specified in it into its address space, and then call their ServiceMain() exports.

To make svchost.exe aware of its existence and be loaded too, the trojan adds its service name into the list of strings (service names) stored in the value "netsvcs" of the registry key:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SvcHost

To make sure its service name is added to the list of services only once, the trojan queries the contents of the value "netsvcs" to make sure that the multiple strings stored in that value do not contain any string that starts from "RaS" (case-sensitive).

Other parameters of the newly installed service are specified in the values:

ObjectName = LocalSystem
Type = dword:0x20 (a win32 service that can share a process with other win32 services)
Start = 2 (to be loaded automatically for all startups)

of the registry key:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\RaS[4 random characters]

Finally, to let svchost.exe process know where to load the DLL from, the image path of the trojan's service DLL is saved by setting the value:

ServiceDll = [path to trojan DLL]

of the registry key:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\RaS[4 random characters]\Parameters

The file name of the trojan DLL is retrieved by calling GetModuleFileNameA() API, as the trojan knows its name may vary.

For instance, the trojan can create a copy of itself under a random filename in the %TEMP% directory; if it locates a file %TEMP%\c_1758.nls, it may rename that file under a different file name.

NOTE: %TEMP% is a variable that refers to the temporary folder in the short path form. By default, this is C:\Documents and Settings\[UserName]\Local Settings\Temp\ (Windows NT/2000/XP), or C:\User\[UserName]\AppData\Local\Temp (Windows Vista, Windows 7).

The Hydraq trojan installs a backdoor trojan that listens for incoming commands. The commands allow the trojan to perform multiple actions - the trojan organizes them into groups - these commands are enlisted below with the [group number].[internal command number] prefixes:



  • [0.0] adjust token privileges

  • [0.1] terminate processes


  • [1.0] enumerate name and status for all system services

  • [1.1] control arbitrary services

  • [1.2] query status for arbitrary services


  • [2.0] receive remote file and save it as %TEMP%\mdm.exe, then launch it by using command control program %SYSTEM%\cmd.exe


  • [3.0] enumerate registry keys under the specified key

  • [3.1] enumerate registry values for the specified key

  • [3.3] query registry values

  • [3.4] set registry values conditionally

  • [3.5] set registry values unconditionally

  • [3.6] delete registry keys

  • [3.7] create registry keys conditionally

  • [3.8] create registry keys unconditionally


  • [4.0] retrieve the list of logical drives on a system

  • [4.1] read files from the local file system

  • [4.2] execute arbitrary files

  • [4.3] copy files in the local file system

  • [4.4] delete arbitrary directories

  • [4.5] rename files

  • [4.6] change file attributes


  • [5.1] power off computer

  • [5.2] reboot Windows

  • [5.3] uninstall itself by deleting the registry key HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\RaS[4 random characters]

  • [5.5] clear all system event logs (application, security, and system pools)


  • [6.0] enumerate files in the specified path


  • [7.11] check if %SYSTEM%\acelpvc.dll is present - if it is present, load it and call its EntryMain() export; check the presence of the DLL %SYSTEM%\VedioDriver.dll


  • [9.1] open the file %SYSTEM%\drivers\etc\networks.ics and read 616 bytes from it

  • [9.2] delete the file %SYSTEM%\drivers\etc\networks.ics


In addition to the commands enlisted above, the trojan retrieves CPU speed by querying the "~MHz" value from the registry key:
HKEY_LOCAL_MACHINE\HARDWARE\DESCRIPTION\System\CentralProcessor\0

The stolen details are then delivered to the remote site.

Hydraq trojan is capable to keep inter-process communications with other components via a named pipe - a separate thread is spawned for that purpose.

Internal data or configuration is stored by the trojan in the values "IsoTp" and "AppleTlk" in the dedicated registry key:
HKEY_LOCAL_MACHINE\Software\Sun\1.1.2

Continued in part II.