New Elknot/Billgates Variant with XOR like C2 Configuration Encryption Scheme


Elknot is a notorious DDoS botnet family which runs on both Linux and Windows platforms [1] [2] [3] [4]. Multiple variants have been found since its first appearance, while the most infamous variant is called BillGates by many researchers because of its characteristic use of Bill and Gates modules [5]. Besides that this variant is also highlighted in using the school-book style of RSA encryption to hide its C2 configurations including server, port, campaign name, etc. The plain configuration is made up of one or more C2 lines, with each line having the format of "< C2 ip or domain >:< C2 port >:< Is Listener ?>: < IsService ?>: < Campaign Name >:< Enable Backdoor ?> "[6].

In September 2015, we found a new elknot/BillGates variant which uses a new C2 encryption scheme while keeps the old DDoS attack functions and C&C protocols.

This article will discuss the new elknot/BillGates variant with a focus on the updates from the previous one. The analysis work is mainly based on the following 2 samples:

  • md5: 2579aa65a28c32778790ec1c673abc49, type: ELF32:Intel80386:UNIX-SystemV.
  • md5: 474429d9da170e733213940acc9a2b1c, type: ftype=ELF32:Intel80386:UNIX-SystemV.

New Encryption Scheme

In the previous version of Elknot/BillGates samples RSA cipher text and parameters are stored in hex format string, which can be easily extracted with Linux utility like strings. To get the further plain C2 information what you need to do is just inputting the extracted cipher text to a RSA decryption tool which can be easily obtained on Internet. Since it’s not this article’s emphasis so we skip it. We have developed such a C2 extraction solution which works well on all collected BillGates samples.

Figure 1, RSA cipher text and parameters in sample

From September 2015, however, we began to notice that there were more and more elknot/BillGates samples from which valid C2 configurations could be extracted but the extracted C2 servers could never be successfully contacted. The most frequently extracted C2 servers were and The C2 port for was always 3000, while both 8226 and 13864 were often together used for As the abnormal cases began to accumulate, we felt obliged to have an investigation. After running the questionable samples in sandboxes, we got surprised by the fact that the really contacted C2 servers were neither nor We had to re-check our C2 extraction program but found no problems, which made us to infer that new variant might have appeared.

Our inference was soon confirmed after some Bindiff and dynamic tracing work was done. A new Elknot/BillGates variant did emerge. The fake C2 servers, aka and, will be replaced by the true C2’s hidden by the new encryption scheme after sample runs. This explained why they could not be successfully contacted.

Further analysis shows that the new encryption scheme composes of 2 functions, which are renamed as DecryptC2Cfg and Decrypt. The entry function (aka DecryptC2Cfg) is called by CSysTool::Ikdfu94, which is responsible for decrypting the C2 configuration in old version. The following figure shows the difference between new version (the left code snippet, md5=2579aa65a28c32778790ec1c673abc49) and the old one (the right code snippet, md5=8285f35183f0341b8dfe425b7348411d) in function CSysTool::Ikdfu94.

Figure 2, differences of CSysTool::Ikdfu94 functions

The entry function, as shown in Figure 3, does the following things:
1, locating the cipher text.
2, calling the Decrypt function to decrypt plain C2 information.
3, jumping to CUtility::Split to split the plain C2 information by splitter of “:”.

It is interesting that DecryptC2Cfg will not directly return to the calling place but jump to CUtility::Split, which indicates that the decryption code is inserted by some 3rd builder after the sample is compiled. If you look at the old version code, as shown in the right snippet of Figure 2, CUtility::Split is function that should be called at 0x8077AB4. The jump to CUtility::Split exactly accomplishes the object of replacing the fake C2 information decrypted by RSA while not interrupting the original execution flow. Other evidences for the above speculation are as follows:
1, the common shellcode technique of “call $+5” is used in DecryptC2Cfg for address locating.
2, the 2 decryption functions were both stripped, while it’s not true for all the other functions.

Figure 3, new encryption scheme’s entry function

The Decrypt function is illustrated in Figure 4. It has a fixed cipher text (0x40 here). The core operation is getting each plain byte by XORing current byte with its next neighboring one.

*Figure 4, CFG of Decrypt() function *

There exists another version of DecryptC2Cfg as that found in sample md5=474429d9da170e733213940acc9a2b1c. The difference is that the addresses of cipher text and flag are hardcoded.

*Figure 5, Another version of DecryptC2Cfg() function *

As for the Decrypt function, the same control flow graph was seen shared among all found samples.

When analyzing the new version of samples we found that the decryption functions, aka DecrytpC2Cfg and Decrypt, are usually not inside any valid sections. The following is the code snippet found in the sample with MD5 of 474429d9da170e733213940acc9a2b1c. The code is responsible for calling the called DecryptC2Cfg with address of 0x8130800.

Figure 6, The DecryptC2Cfg() function not inside valid sections

It’s easy to observe the sample sections with Linux utility readelf. The following is the output of “readelf –S” for sample md5=474429d9da170e733213940acc9a2b1c. It’s obvious that the address of 0x813080 is not inside any valid sections, which provides another evidence that the decryption code is inserted by some 3rd builder.

Figure 7, the address of DecryptC2Cfg outside of valid sections


We have written a YARA rule according to the 2 cases of DecryptC2Cfg functions as follows.

rule elknot_xor : ELF PE DDoS XOR BillGates  
    author = ""
    description = "elknot/Billgates variants with XOR like C2 encryption scheme"
    date = "2015-09-12"

   seg000:08130801 68 00 09 13 08                push    offset dword_8130900
   seg000:08130806 83 3D 30 17 13 08 02          cmp     ds:dword_8131730, 2
   seg000:0813080D 75 07                         jnz     short loc_8130816
   seg000:0813080F 81 04 24 00 01 00 00          add     dword ptr [esp], 100h
   seg000:08130816               loc_8130816:                           
   seg000:08130816 50                            push    eax
   seg000:08130817 E8 15 00 00 00                call    sub_8130831
   seg000:0813081C E9 C8 F6 F5 FF                jmp     near ptr 808FEE9h
   $decrypt_c2_func_1 = {08 83 [5] 02 75 07 81 04 24 00 01 00 00 50 e8 [4] e9}

   // md5=2579aa65a28c32778790ec1c673abc49
   .rodata:08104D20 E8 00 00 00 00                call    $+5
   .rodata:08104D25 87 1C 24                      xchg    ebx, [esp+4+var_4] ;
   .rodata:08104D28 83 EB 05                      sub     ebx, 5
   .rodata:08104D2B 8D 83 00 FD FF FF             lea     eax, [ebx-300h]
   .rodata:08104D31 83 BB 10 CA 02 00 02          cmp   dword ptr [ebx+2CA10h], 2
   .rodata:08104D38 75 05                         jnz     short loc_8104D3F
   .rodata:08104D3A 05 00 01 00 00                add     eax, 100h
   .rodata:08104D3F               loc_8104D3F:                           
   .rodata:08104D3F 50                            push    eax
   .rodata:08104D40 FF 74 24 10                   push    [esp+8+strsVector]
   $decrypt_c2_func_2 = {e8 00 00 00 00 87 [2] 83 eb 05 8d 83 [4] 83 bb [4] 02 75 05}

    1 of ($decrypt_c2_func_*)

Figure 8, YARA rule to detect the mentioned variant


After mining the sample database, we found that the first sample of this variant had appeared as early as April 2015. Currently there are about 750 of such samples were collected, with nearly 700 unique C2 servers extracted. We will keep on watching the growth of this notorious DDoS family in the future.

Related work



[3] When ELF.BillGates met Windows,