Follow ITProPortal:

RSS Tweet Digg

Owning Kraken Zombies, a Detailed Dissection

This blog contains the deep technical dive of a two-part blog series exploring the Kraken botnet. See "Kraken Botnet Infiltration" for more information regarding general statistics and observations of the botnet.

Disclaimer: I don't normally deal with malicious code analysis. My main focuses are on vulnerability discovery and general reversing so dedicating some time to analyzing Kraken was a new and interesting experience. There are many resources available on malware unpacking, PE import table reconstruction etc. so I'll skip right to the specifics of the sample. The offsets and analysis shown below are from sample 31b68fe29241d172675ca8c59b97d4f4 from Offensive Computing.

When Kraken first starts it enters an infinite loop trying to locate a master (command and control) server on UDP port 447 over a custom encrypted protocol. The contacted hostnames all reside with dynamic DNS providers with a randomly generated sub-domain. Here is a look at the function responsible for algorithmically generating the domains to connect to, keep a close eye on the second argument which is used as the seed in the generation process:

    .text:001AE810  mov     esi, [ebp+seed]
    .text:001AE813  sar     esi, 1
    .text:001AE815  add     esi, 0F424Fh
    .text:001AE81B  push    edi
    .text:001AE81C  lea     ecx, [ebp+var_10]
    .text:001AE81F  mov     [ebp+seed], esi
    ...
    .text:001AE83D  lea     ecx, [esi+7]
    .text:001AE840  lea     eax, [esi+0Ch]
    .text:001AE843  imul    eax, ecx
    .text:001AE846  imul    eax, esi
    .text:001AE849  cdq
    .text:001AE84A  pop     ecx
    .text:001AE84B  idiv    ecx
    .text:001AE84D  lea     ecx, [esi+1]
    .text:001AE850  imul    ecx, esi
    .text:001AE853  lea     ecx, [eax+ecx-0FCFBF88h]
    .text:001AE85A  jmp     short loc_1AE87C
    ...
    .text:001AE87C  imul    ecx, 41C64E6Dh
    .text:001AE882  mov     edi, 3093h
    .text:001AE887  add     ecx, edi
    .text:001AE889  mov     eax, ecx
    .text:001AE88B  imul    ecx, 41C64E6Dh
    .text:001AE891  add     ecx, edi
    .text:001AE893  ror     eax, 8
    .text:001AE896  mov     edx, ecx
    .text:001AE898  imul    ecx, 41C64E6Dh
    .text:001AE89E  mov     esi, 7FFFh
    .text:001AE8A3  and     eax, esi
    .text:001AE8A5  ror     edx, 8
    .text:001AE8A8  and     edx, esi
    .text:001AE8AA  imul    eax, edx
    .text:001AE8AD  add     ecx, edi
    .text:001AE8AF  mov     ebx, ecx
    .text:001AE8B1  ror     ecx, 8
    .text:001AE8B4  and     ecx, esi
    .text:001AE8B6  sub     eax, ecx
    .text:001AE8B8  push    6
    .text:001AE8BA  cdq
    .text:001AE8BB  pop     ecx
    .text:001AE8BC  idiv    ecx
    .text:001AE8BE  add     edx, ecx
    ...

The seed is crucial to the position in the control server list and starts at 0 on reboot. At the end of this function we see an array of domain names being access that are appended to the generated name:

    .text:001AE91D  push    dynamic_host_names[eax*4] ; lpString
    .text:001AE924  lea     ecx, [ebp+var_20]
    .text:001AE927  call    makeNewString
    .text:001AE92C  push    eax
    .text:001AE92D  push    [ebp+hostname]
    .text:001AE930  lea     eax, [ebp+var_18]
    .text:001AE933  push    eax
    .text:001AE934  lea     eax, [ebp+var_8]
    .text:001AE937  push    eax
    .text:001AE938  lea     ecx, [ebp+var_10]
    .text:001AE93B  call    concatenateStrings
    
    .data:001B5064 dynamic_host_names dd offset aDyndns_org
    .data:001B5064                          ; "dyndns.org"
    .data:001B5068  dd offset aYi_org       ; "yi.org"
    .data:001B506C  dd offset aDynserv_com  ; "dynserv.com"
    .data:001B5070  dd offset aMooo_com     ; "mooo.com"

Each generated host is checked twice before moving on to the next one, here are the first 5 hosts that will attempt to be contacted:

    rbqdxflojkj.mooo.com
    bltjhzqp.dyndns.org
    cffxugijxn.yi.org
    etllejr.dynserv.com
    ejfjyd.mooo.com

For those who are interested, here is a list of the first 15,000 hosts. Note that as of the time of this research the first Kraken server that was up and responding was 15th down the list afmbtgyktty.yi.org on IP address 66.29.58.119. Armed with this information we registered the first of the available hosts and immediately began getting requests from live Kraken infections in the wild. See "Kraken Botnet Infiltration" for more information regarding general statistics and observations of the botnet.

Knowing now that it is theoretically possible to overtake the Kraken network the next step is to examine the protocol. Looking through the binary there are several calls on the socket connection it makes over UDP port 447 to the control servers. All of these calls are preceded with a send to the control server with an encrypted header:

    .text:001A83C5  call    getEncryptionKeys
    .text:001A83CA  mov     dword ptr [esp+80h+send_buffer], eax
    .text:001A83CE  lea     eax, [esp+80h+send_buffer]
    .text:001A83D2  mov     [esp+80h+var_2C], edx
    .text:001A83D6  mov     [esp+80h+var_28], ebx
    .text:001A83DA  mov     [esp+80h+var_24], 1
    .text:001A83DF  mov     [esp+80h+var_23], bl
    .text:001A83E3  mov     [esp+80h+var_22], 137h
    .text:001A83EA  mov     [esp+80h+var_20], ebx
    .text:001A83EE  mov     [esp+80h+var_1C], ebx
    .text:001A83F2  call    encryptHeader
    ...
    .text:001A8418  push    10h             ; tolen
    .text:001A841A  lea     eax, [esp+84h+to]
    .text:001A841E  push    eax             ; to
    .text:001A841F  push    ebx             ; flags
    .text:001A8420  push    18h             ; len
    .text:001A8422  lea     eax, [esp+90h+send_buffer]
    .text:001A8426  push    eax             ; buf
    .text:001A8427  push    [esp+94h+s]     ; s
    .text:001A842B  call    ds:sendto

As we can see (note that all of the symbols were manually added through reverse engineering) we get some sort of encryption key, build the header, and encrypt the header before sending. Obviously we have to figure out the encryption so we can get a better look at the command and control protocol.

I have seen some mention and packet dumps of the header on various blogs. They often state the first 8 bytes of kraken traffic is static and there is a simple reason for this. Kraken, when communicating, prepends its encryption keys so the server can properly decrypt/encrypt traffic. We can see this in the getEncryptionKeys function.  It is host specific and computes the 64 bit key from various aspects of the host hardware. Abbreviated pseudo code for the function is below.

    mov     ds:encryption_key_1, 0DCBA2C5Ah
    mov     ds:encryption_key_2, 50E41593h
    GetAdaptersInfo()
    while (*adapter_info != 0) {
        for (i=0; i < adapter_info.AddressLength; i++) {
            ...
        }
        adapter_info = *adapter_info
    }
    encryption_key_uno += cpuid(0x0).max_input_value
    encryption_key_dos += cpuid(0x0).inel
    encryption_key_uno ^= cpuid(0x1).version
    encryption_key_dos ^= cpuid(0x1).features
    encryption_key_uno ^= cpuid(0x3).hi_serial
    encryption_key_dos ^= cpuid(0x3).low_serial
    
    encryption_key_uno -= GetVolumeInformation(GetWindowsDirectoryA()).VolumeSerialNumber


blog comments powered by Disqus

Follow ITProPortal:

RSS Tweet Digg

Owned &
operated by:

Net Communities