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.

Thursday, December 17, 2009

We are the champions, my friends

Results of a lengthy real-world malware protection study are published here.

Wednesday, November 25, 2009

Run, Chrome OS! Run!

It seems that the news on Chrome OS release have left no one neutral; some observers are beating the drums of its imminent failure and premature death, by relying on rather oversimplified concepts of cloud computing and insinuating about the reasons why careless moms and dads just can't grasp the concept of strong passwords ("how many times did we tell them to memorize Qp%n#82r$7D, but they keep writing it down on a piece of paper or even worse - keep choosing 12345?").

From the point of view of these observers, the new security model of Chrome OS is not much different from this:



Let's step back for a moment and try to give it a fresh and fair look. Let's also keep in mind that many good projects make their way into our lives by having 3 stages of its public perception: strong criticism (almost always, and that's where many fail), gradual, painful at start, then easier adoption, followed with a final stage that can be characterized as "Well, what's so special about it?". We don't want to fall the victims of the first stage, no matter how natural for humans it is, right?

Well, Google claims that under Chrome OS hood "all apps are web apps". Boo! But hold on a second, isn't it already true for Hotmail, Skype, online banking, and lots of other online web services that we are relying on so much every day?

Now come into a computer store (mentally) and look (again, mentally) at the average mom and dad who want to buy a new computer. Is it really a surprise to learn that most they're going to use it for will be "web apps" anyway, such as web, email, IM/chat/forums, Internet phone, documents editing/printing (bills/taxes/records), personal finance services (online banking, trading stocks), online gaming, etc. ?

Sure enough, with a web-only machine they won't be able to scan documents, but given the market exists, there will be dedicated scanners for the home users that will scan the documents and send the images over to their online accounts. They won't be able to listen or watch CD/DVD, but there are specialized devices that do it better anyway. They won't be able to play games with the powerful graphics, but there are plenty of gaming consoles for that purpose too.

Somehow it comes to a point – would you prefer to have a TV, a DVD/BD player, and a sound system as dedicated stand-alone devices, maybe from the different brands, or have all of them combined in one (cheaper) device? Would you prefer to have a printer, a scanner, and a telephone as separate devices, or a combined (cheaper) unit?

If you choose the second option, then you must really adore your phone's camera! If you choose first, even if it's a pricier option, doesn't it sound reasonable to have a dedicated device to handle web-only services?

For start, let's stick to just one such service – Internet Banking. Imagine having a dedicated 100% secure tiny netbook that allows you to bank online. It boots in 10 seconds and it can't run malware by design. Sure enough, hackers will try hacking a device like that to run Windows on it, but that won't be YOUR DEVICE. If your device gets stolen, it's useless – it stores nothing and you can't be impersonated with it. If you spill hot coffee on it and it shuts down instead of running faster, you'll buy another one (not coffee, netbook). Will it give you an extra hour of a good night sleep by knowing that no hacker can compromise your online banking account?

Now try to imagine how many threat families (keyloggers, banking Trojans, rootkits) instantly become irrelevant for you. Even if your other computer gets compromised with them, the only valuable thing the hackers might eventually steal from you will be a serial number of your antivirus product.

If you love your netbook, you might extend its application to online shopping or online trading. Then to anything that's online and is asking you for a password from that little soiled notes book from the middle section of your wallet. Extending its application further becomes a dangerous business as a flaw in one web service may affect your other services (e.g. a phishing email may affects your online banking account if you do both on one machine), just like it's not wise to put all your eggs in one basket.

The security overview of Chrome OS is an interesting read.

By openly discussing the security challenges and suggested approaches to circumvent them the Chrome guys talk to us this way:

"Look, in our bank there is a vault with so much gold in it. The system is secure, but we're not sure about that air con duct – we think it's a weak point and the intruders may potentially crawl through it".

Given the source code is open, the potential intruders will get access to the internals' scheme immediately. But the moment they start studying it, the highly qualified white-hat professionals will start doing that as well. The idea is that any bugs, flaws or weaknesses will be revealed and fixed instantly, without leaving the intruders any chance to plan an attack.

Compare it with an alternative approach: "Look, in our bank there is a vault with so much gold in it. The system is secure." After the robbery: "The system is secure." After another one: "Ok, we fixed it, the system is secure", and so on.

With the security being the main cornerstone of Chrome, it's a step away from the "traditional" development philosophy that we all are used to: "make it usable and release it first, think about security later, when the bugs/flaws are discovered". Usability being priority #1 creates a cash flow that allows investing into security and fine-tune usability at a later stage. The problem with this approach is that when under-invested security fails, usability falls with it. Not just declines, but crashes spectacularly.

The only company that can afford to have security in the first place, in the blueprints, even before the developed software becomes available for users, will likely have a "cash cow" in a different product or solution. Otherwise, it will be trapped in a vicious circle when the product is not released because its model is not secure enough, thus there are no sales and therefore, no funding to make it secure enough to be released. Google's "cash cow" is in its ads program, giving it all the required conditions to build a truly secure OS.

Not an OS that replaces all other OS (this will never happen), but at least an OS that can safely and narrowly be used for those critical web-only applications that create so much headache for the customers in terms of stolen identity and money.

Will Google blow this chance or not, time will tell.

Saturday, November 21, 2009

Dissecting Limbo Dropper [old]

A routine laptop clean-up revealed a few month old video of unpacking the Limbo trojan dropper. Before it gets deleted, posting it here just in case some folks might find it useful [link to video].

PS The sample was received from Michael Hale Ligh. Thanks, Michael.

Sunday, November 1, 2009

The New Moon Trojan

While the sentence of the Pinch Trojan authors is about to expire within the following few months, the code of their Trojan is still being morphed by others into other nasty forms.

Apart from its known ability to gather system information and steal confidential information such as user names and passwords, the Pinch is now capable of delivering the stolen details to the remote website by utilizing a powerful news management system called "Cute News".

What's not cute in this case however is that the name of the website established by the remote attackers to collect stolen credentials is disguised under the name of the forecoming movie blockbuster New Moon.

The infection starts from an image displayed with the purpose of distracting user attention while the Trojan gets activated. While the user stares at the picture, the Trojan starts harvesting user details, passwords, email addresses and other contents from the configuration files of the installed email clients Eudora, Thunderbird, Outlook, The Bat!, FTP clients FileZilla, WS_FTP, CuteFTP, and several other applications.

The Trojan then collects system information that includes installed application names and their versions, serial numbers, user and computer names, the names of the running applications, user’s email account settings, and some other system details.

The collected information is then encoded into Base64 format and posted into the remote Cute News service hosted by the attackers at http://www.newmoon-movie.net.



The post takes place via HTTP protocol allowing attackers to use the power of the Cute News system to accept, collect and use the stolen information without setting up any databases as all information is stored in flat files.




Automated analysis is available here.

Wednesday, September 16, 2009

Time to Revisit Zeus Almighty

Zeus/Zbot is an annoying threat. Its persistence is explained with a fact that it's generated by a large army of attackers who use Zeus builder.

Those attackers who are high in the food chain pay thousands of dollars for the latest Zeus builder to make sure they distribute the most up-to-date undetectable bot builds. But many are still happy to use obsolete versions of the builder - these are available for free on various file sharing web sites.

One way or another, the wave if new Zeus/Zbot samples being distributed every day is alarming. It's kind of an "attack of the clones" when multiple modifications of the bot are being produced in-the-wild, packed and encrypted on top with all sorts of packers, including modified, hacked, or private packer builds. Before being released, every newly generated and protected bot is uploaded into popular multi-AV scanner services to make sure it is not detected by any antivirus vendor. Hence, quite a bit of a problem in terms of its distribution scale.

The nasty thing about Zeus/Zbot is that it evolves. The latest generation bot uses rootkit techniques to hide its presence on a customer machine. The bot uses covert methods of injecting additional fields into online Internet banking websites, asking users to answer questions that the authentic website would not ask. The collected details are then silently delivered to remote websites, and added into remote databases. The databases are then sold to other criminal elements down the chain who specialize in withdrawing the funds. The money laundering groups anonymously hire physical people to withdraw money from their personal accounts - in the criminal world these people are called "drops", and their accounts are called "drop accounts".

Without going too much into detail about the whole economy that operates behind Zeus/Zbot, let's rather concentrate on some of its technical aspects.

An important fact to mention is that the bot itself is like a framework with no "brains". It is merely a program that hooks itself into the system and hides there effectively. The logics that drives behaviour of the bot is contained in its configuration file.

The configuration file of Zeus/Zbot is like a definitions database for an antivirus product. Without it, it's pretty much useless. The logics contained in the configuration contains the list of banking institutions that the bot targets, URLs of the additional components that the bots relies on to download commands and updates, the lists of questions and the list of the fields that the bot injects into Internet banking websites to steal personal details/credentials, etc.

For instance, if the attacker only wanted to target local customers in Brazil, the bot's configuration file would enlist Brazilian banks and the list of questions/fields would be in Brazilian Portuguese language only. This way, the bot could transparently allow Internet banking transactions for non-Brazilian customers because the attacker would not be interested in those transactions, attacking domestic customers and their transactions only.

The configuration of Zeus/Zbot is never stored in open text. It is encrypted. Previous generation of Zeus/Zbot used a hard-coded encryption mechanism for its configuration. It was possible to reverse engineer the encryption algorithm and build a decryptor for any configuration file that belonged to any bot of the same generation.

The game has changed. The latest generation of Zeus/Zbot encrypts configuration file with a key that is unique for and is stored inside the bot executable for which this configuration file exists. This way, configuration file of one bot sample will not work for another bot sample, even if both samples are generated with the same builder. As the decryption key is stored inside the bot executable, the configuration cannot be decrypted without the executable. However, the executable that contains the key is also packed on top so that the key cannot easily be retrieved from it. Brute-forcing the key is not a viable option as the key is 256 bytes long.

In other words, it's practically "a riddle wrapped in a mystery inside an enigma, but perhaps there is a key", as Winston Churchill once said about the homeland of Zeus author(s).

In order to reveal the key for Zeus/Zbot configuration and study the decryption mechanism, a few things need to be done first.

Firstly, Zeus/Zbot could be run on a virtual machine under OllyDbg debugger and dumped with the OllyDump plugin installed:



The created dump can be loaded into IDA disassembler - the variables that store dynamically retrieved addresses of APIs should be renamed into the API names to ease the code reading, as shown below:



The analysed dump does not reveal the code that downloads and decrypts the configuration file. It is because the dump was created for the first stage of the execution workflow - when it drops other files, installs hooks and injects its own code into the system process services.exe.

In spite of the decryption key being present in the dump (as it becomes known later), revealing it now along with the decryption mechanism by analysing the dump statically is not easy as the code did not branch that execution path yet.

Ok, so what do we do now?

Let's run RootkitUnhooker to check the system integrity. According to its hook revealer, two installed IAT hooks can be seen:




According to ThreatExpert report, the bot creates the following files:

  • %System%\lowsec\local.ds

  • %System%\lowsec\user.ds

  • %System%\sdra64.exe



Because of the hooks, these files are not visible in Explorer, but trying to create a directory %System%\lowsec invokes the following message box:



The hook in the system process services.exe gives a good reason to dump it and analyse what's in its memory. Dumping main module is not enough as a typical injection mechanism allocates memory on the heap of the process and writes the code there. Thus, the process needs to be dumped entirely, all of its heap pages.

From all the dumped pages of the system process services.exe, two allocations belong to the bot:



These two allocations may span over the address range 0x00040000 - 0x00057000 or 0x00980000 - 0x00997000 after reboot, and can be joined together to be loaded into the disassembler again.

Once reloaded into disassembler, the variables that store dynamically retrieved addresses of APIs should be renamed again into the API names. As the names of the APIs are not visible in this dump anymore, the APIs can either be retrieved by looking up the virtual addresses contained in the function pointers, or by matching the disassembled code with the previously disassembled dump (obtained from OllyDbg/OllyDump) and assigning the same names as in the former dump to the same pointer variables, as shown in the screen grab below:



With the properly named API function pointers, it's much easier to read the code.

The bot contains a special section in its code that contains several important fields:



The URL fields in that section are encoded by using an older encryption mechanism that was used by older Zeus/Zbot generations. Here is a C equivalent of the decryptor - it's straightforward:


   BYTE b;

   for (int i = 0; i < iBufferSize; i++) 
   {
      b = lpSourceBuffer[i];
      if ((i % 2) == 0) 
      {
         b += 2 * i + 10;
      }
      else 
      {
         b += 0xF9 - 2 * i;
      }
      lpDestinationBuffer[i] += b;
   }


One of the URLs points to an encrypted configuration file. The bot downloads that file and saves it into a hidden file %System%\lowsec\local.ds.

Next, the bot reads the 256-byte long encryption key stored in its section and uses it to decrypt the downloaded configuration file:



The decryption routine is not very easy to follow during static analysis. One way of building a configuration file decryptor is to blindly rip the assembler code out of the bot source, only taking care of interfacing it properly - that is passing it the same parameters. However, in order to understand the code and build its C equivalent, the code is better to be traced.

But here comes the question - how to trace the code that is running inside the services.exe process?

An easy way of doing that so it attach a debugger of your choice to the system process services.exe, break its execution, point EIP (the instruction pointer) into the first instruction of the decryption routine, patch memory contents to instruct the routine to unpack a file that is different from %System%\lowsec\local.ds (before you're doing that, make sure the configuration file is downloaded from the earlier discovered URL and is saved under a different filename), suspend all other threads of services.exe process, and debug step-by-step its decryption routine.

The image below shows how the filename %System%\lowsec\local.ds is patched with c:\c



Stepping through the decryption routine reveals how the configuration file is fully decrypted:



Decryption routine itself is represented below:



During decryption, the values of its 256-byte key are constantly shuffled. The C equivalent of this routine is:


   byCounter = 0;
   byMask = 0;
   iSectionOffset = 0x2a;

   for (int i = 0; i < iConfigSize; i++)
   {
      byCounter++;
      byMask += byResource[iSectionStart + iSectionOffset + byCounter];
      byTemp = byResource[iSectionStart + iSectionOffset + byMask];
      byResource[iSectionStart + iSectionOffset + byMask] = byResource[iSectionStart + iSectionOffset + byCounter];
      byResource[iSectionStart + iSectionOffset + byCounter] = byTemp;
      byTemp += byResource[iSectionStart + iSectionOffset + byMask];
      byConfig[i] ^= byResource[iSectionStart + iSectionOffset + byTemp];
   }


Once the configuration file is decrypted, its internal structure reveals that it consists of data blocks. Every data block has a header that describes the length of the block, its type, and whether it's compressed or not.

As shown in the image below, some fields' meaning is not clear. But it seems that the 5th byte of the data block indicates if the data it contains is encrypted or not. Two DWORD values that follow are showing the size of compressed and uncompressed data. Next, the block contains the data itself.



For example, the first block has the size values equal 4 bytes, and the data block itself is 0B 07 02 01. Next two blocks are not compressed - the data size for both blocks is 0x28 bytes. The last block contains a flag that shows it's compressed. The size of compressed data is 0x85 bytes; the size of uncompressed data is 0xA1 bytes, with the 0x85 bytes of data followed.

Analysis of the decompression routine reveals that it's unrv2b algorithm. The decompression source code is available here.

By knowing the decryption/decompression mechanism and the data format, it is possible now to build a tool that will inspect full memory contents of the process services.exe, locate a page which contains Zeus/Zbot code in it, then locate a section in it with the 256-byte key, retrieve that key and use it to decrypt the provided configuration file. As the address of the section within the bot page is not known in advance, it can still easily be detected by probing the size of the structure, probing the bytes within the 256-byte encryption key, and trying to decode the URLs, knowing their length (from the structure) and the key-less encoding method (from the older Zeus generations).

Unfortunately, such tool could only be able to decrypt configuration file on a machine infected with Zeus/Zbot. Thus, it must be run on the same virtual machine that is infected with the bot.

The tool is available for download here.

One positive side-effect of the tool is that even if the configuration file is not available, the tool will still reveal if the machine is infected with Zbot.

The limitation of the tool is that it won't be able to decrypt a configuration file for one bot if the virtual machine is infected with another bot, even if both bots are produced with the same Zeus builder. It’s because every bot uses a unique encryption key that will only decrypt configuration file created for the very same bot.

Running the Zeus configuration decryptor over several Zeus/Zbot samples submitted in the last few days reveals quite interesting characteristics. The full list of its capabilities is too big to be presented here, so only a few questions/additional fields that Zbot injects are highlighted below:

  • Due to security measures, please provide the answers to all the security questions listed below:

  • As an additional safeguard, we ask that you provide the last eight digits of your ATM or Check Card number

  • Please enter your Credit Card Number linked to your account, security code (cvv) and expiration date

  • For your Identity verification and Fraud prevention please send us answers that you need to answer when you log in to your account

  • Our behavioral monitoring software has detected a variation in your use pattern. For your protection, we ask that you verify your identity by answering your personal questions below. Once verified, you will be directed to the page.

  • Authorization Required. In order to provide you with extra security, we occasionally need to ask for additional information when you access your accounts online. Please enter the information below to Sign on:

  • Please enter your Personal Access Code (PAC):

  • Your first school

  • Your mother's maiden name

  • Your place of birth

  • Please enter all digits of your PIN

  • What is your favourite meal or restaurant?

  • The name of a memorable place to you?

  • Your favourite film of all time?

  • Your favourite book of all time?

  • Your favourite teacher or subject?

  • Your favourite TV star or show?

  • Please enter a valid Mother's Maiden Name

  • Please enter a valid Driver's License Number

  • Please enter a valid Date of Birth

  • Please enter a valid Social Security Number

  • Please enter a valid Home Telephone Number

  • Your favorite TV show?

  • Your favorite flower?

  • Your favorite leisure time activity?

  • Your favorite type of music?

  • Your favorite professional football team?

  • Your favorite professional baseball team?

  • The color of your first car?

  • Your favorite holiday?

  • Your favorite place to vacation?

  • In which month were your parents married?

  • What is the first letter of the name of your high school?

  • What is the first letter of the name of your pet?

  • In which month was your first child born?

  • What was the last two digits of the year of your high school graduation?

  • Please enter valid ATM/Debit Card # (CIN)

  • Please enter valid PIN

  • Please enter valid Last 4 Digits of Social Security or Tax ID #



The list goes on, but you get an idea of what an identity theft weapon it is.

Update: Thanks to Peter Kosinar and Thorsten Holz for identifying the encryption algorithm above as RC4.