Posts Emotet: signature-based evasion & malleable executable
Post
Cancel

Emotet: signature-based evasion & malleable executable

I recently came across an interesting finding concerning Emotet’s infection kill-chain, which usually starts with the phishing email followed by the download of an excel macro then its execution, which acts as the DLL dropper and finally leads to malware infection.

Signature

I had a look inside the malicious excel document. The dropper had an incorporated list of domains to grab the malware from, in order to increase the download chances if one or more of them were to be eventually unreachable.

Here are the URLs I found inside the document’s xl/sharedStrings.xml file:

S0367-emt-sharedstrings

Almost every one of them was reachable and serving the executable.

Once downloaded the sample I started to look for as many IOCs as possible, so I noticed it had a unique hash signature. I fed it to Virus Total, which took its time to digest the sample (it was a new one!) and then gave me a malicious score of 49 out of 69, so no worries.

S0367-emt-vt

The interesting part was actually the methodology implemented by threat actors to evade the signature-based detection. I double checked every one of them to catch indicators, and I noticed that every time I downloaded the DLL, it had a different hash so I grubbed two more, all of which had the same size (#IOCs).

1
2
3
4
5
6
7
8
9
10
(synth3sis㉿sthsvm)-[~/Emotet]$ sha256sum *.dll
d676b92e998dd3c2dfb6e51f8218019347c8b77d621fbf105fae3f7d7e2cb829  X7Nwjq.dll
7a11140df855a04f149152da55819c4a18ded6eff3eaf09cb80332cf24343b42  FHTz6WZe2JM.dll
d91fa3bfa7ea9265375b4f89100c54900f083daa115f025203121091a950afc6  B5tcHyPEujNbv.dll

(synth3sis㉿sthsvm)-[~/Emotet]$ du -sb *.dll
626688  X7Nwjq.dll
626688  FHTz6WZe2JM.dll
626688  B5tcHyPEujNbv.dll

Then, I analyzed the differences among their HEX dump and here is what I found:

1
2
3
4
5
6
7
8
9
(synth3sis㉿sthsvm)-[~/Emotet]$ diff X7Nwjq.dll.xxd FHTz6WZe2JM.dll.xxd
20799,20801c20799,20801
< 00052430  00 00 00 00 00 00 00 00  31 00 00 00 ee b1 51 09  |........1.....Q.|
< 00052440  04 2b d8 a4 bf cf a8 b7  b0 45 5d 86 a3 60 4a 6b  |.+.......E]..`Jk|
< 00052450  63 54 45 82 cf 33 3e eb  0b ab 0f b8 00 00 00 00  |cTE..3>.........|
---
> 00052430  00 00 00 00 00 00 00 00  31 00 00 00 4e f6 a8 65  |........1...N..e|
> 00052440  69 93 98 3f a7 fc 31 0b  1f c6 7e 58 96 45 78 6c  |i..?..1...~X.Exl|
> 00052450  b7 5a 62 8b da 4b a2 a5  df 56 f0 22 00 00 00 00  |.Zb..K...V."....|
1
2
3
4
# B5tcHyPEujNbv.dll:
> 00052430  00 00 00 00 00 00 00 00  31 00 00 00 48 bb 9a 0f  |........1...H...|
> 00052440  54 44 07 cb f5 4f c6 b1  e6 e8 3c 22 22 37 cd fb  |TD...O....<""7..|
> 00052450  99 8e 6a d4 3a 20 f6 24  c8 bd 12 c8 00 00 00 00  |..j.: .$........|

It appears that at offset 5243C they show variations, more precisely exactly 32 bytes vary (until 5245B included), which at first sight it seemed randomly generated and lacking relevant information.

Analyzing the PE’s entropy, as expected, .text and .rdata sections are packed:

S0367-emt-entropy

Executable’ sequence

I wondered what was the technical mechanism behind this interesting behaviour and how could be implemented, so I started doing some research and I came across the concept of Cobalt Strike Malleable PEs which gave me some insight on C2 agents and malleable PE configurations.

Regardless, my goal was to write a piece of code to give me proof on how I could modify some section of the package in response to a web request and eventually embed configurations in it. In other words, without having to re-compile the source code every time. The thing about this stuff was that potentially this PE, once deployed could have been sent all over the network without being detected by signature-based detection systems, such as basic AVs or NIDS/NIPS of some sort.

At this point I did further research and studies just to be able to reproduce this mechanism by writing the right program and create my basic proof of concept.

So, I wrote a C++ sample which implements a static pre-allocated buffer used to keep track of the sequence to be later editable. I used the same X7Nwjq.dll byte array so I disposed exactly 32 bytes for it.

What it does is:

  1. Allocate a 32 static buffer
  2. Dump the sequence to sequence.bin file
  3. Print out confirmation

Here is seqdumper.cpp code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
#include <fstream>

static unsigned char sequence_buf[32]  = {
    0xEE, 0xB1, 0x51, 0x09, 0x04, 0x2B, 0xD8, 0xA4, 0xBF, 0xCF, 0xA8, 0xB7, 0xB0, 0x45, 0x5D, 0x86,
    0xA3, 0x60, 0x4A, 0x6B, 0x63, 0x54, 0x45, 0x82, 0xCF, 0x33, 0x3E, 0xEB, 0x0B, 0xAB, 0x0F, 0xB8
};

int main() {
    std::ofstream outfile;
    outfile.open("sequence.bin", std::ios_base::binary);
    std::cout << "+ writing down " << sizeof(sequence_buf) << " bytes sequence_buf\n";
    // write down byte by byte to avoid extra ones to be dumped at the end
    for (int i = 0; i < sizeof(sequence_buf); i++) {
        outfile.write((char*)(sequence_buf + i * sizeof(sequence_buf[0])), sizeof(sequence_buf[0]));
    }
    std::cout << "+ \"sequence.bin\" dumped\n";
    outfile.close();
    return 0;
}

Then compiled and ran it.

1
2
3
4
5
6
7
(synth3sis㉿sthsvm)-[~/Emotet]$ g++ seqdumper.cpp -o agent && ./agent
+ writing down 32 bytes sequence
+ "sequence.bin" dumped

(synth3sis㉿sthsvm)-[~/Emotet]$ xxd sequence.bin
00000000: eeb1 5109 042b d8a4 bfcf a8b7 b045 5d86  ..Q..+.......E].
00000010: a360 4a6b 6354 4582 cf33 3eeb 0bab 0fb8  .`JkcTE..3>.....

The same sequence is embedded in agent, more precisely in this case at offset 30a0.

1
2
3
(synth3sis㉿sthsvm)-[~/Emotet]$ xxd agent |grep -A1 "eeb1"
000030a0: eeb1 5109 042b d8a4 bfcf a8b7 b045 5d86  ..Q..+.......E].
000030b0: a360 4a6b 6354 4582 cf33 3eeb 0bab 0fb8  .`JkcTE..3>.....

Malleable executable

Once I got the address, I developed a python script to overwrite, or patch, exactly that sequence.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#!/usr/bin/env python3

import sys
from os.path import exists

def main():
    if len(sys.argv) <= 1:
        sys.exit("Usage: python3 patchbin.py /path/to/binfile")
    if not exists(sys.argv[1]):
        sys.exit("File does not exists")

    execfile = sys.argv[1]
    patch = b"'7h475_7h3_N3w_''53qu3nc_1nj3c7'"

    with open(execfile, 'rb') as ef:
        data = bytearray(ef.read())
    ef.close()

    # Look for the sequence's first 4 bytes
    offset = data.find(b"\xee\xb1\x51\x09")
    print("-> Patching file at offset " + str(offset))

    with open(execfile, 'r+b') as ef:
        ef.seek(offset)
        ef.write(patch)
    ef.close()
    print("-> " + execfile + " patched")

if __name__ == "__main__":
    main()

Finally, I executed agent which dropped its sequence to sequence.bin binary file.

1
2
3
4
5
6
7
8
9
10
(synth3sis㉿sthsvm)-[~/Emotet]$ ./agent
+ writing down 32 bytes sequence
+ "sequence.bin" dumped

(synth3sis㉿sthsvm)-[~/Emotet]$ cat sequence.bin |xxd
00000000: eeb1 5109 042b d8a4 bfcf a8b7 b045 5d86  ..Q..+.......E].
00000010: a360 4a6b 6354 4582 cf33 3eeb 0bab 0fb8  .`JkcTE..3>.....

(synth3sis㉿sthsvm)-[~/Emotet]$ sha256 agent
fd19322c68ba5bbf6ddae23b7a60ad760620d9aafef1f678ca49a7b945e95faf  agent

Then patched the executable.

1
2
3
4
5
6
(synth3sis㉿sthsvm)-[~/Emotet]$ ./patchbin.py agent
-> Patching file at offset 12448
-> agent patched

(synth3sis㉿sthsvm)-[~/Emotet]$ sha256sum agent
82e359b8cf4108b9dfc4367ba46a09be98874b1260406035aa4a84ae0d0d16b4  agent

The executable’s signature has changed. When executed, it dumps the patched byte array we set.

1
2
3
4
5
6
7
(synth3sis㉿sthsvm)-[~/Emotet]$ ./agent
+ writing down 32 bytes sequence
+ "sequence.bin" dumped

(synth3sis㉿sthsvm)-[~/Emotet]$ cat sequence.bin |xxd
00000000: 2737 6834 3735 5f37 6833 5f4e 3377 5f27  '7h475_7h3_N3w_'
00000010: 2735 3371 7533 6e63 5f31 6e6a 3363 3727  '53qu3nc_1nj3c7'





If any other idea about this case of study comes to mind, I will update it so stay tuned! And feel free to contact me if you have any advice regarding my work.

In the next write-up I will further deepen the subject to see if I can manage to embed structured informations useful for configuration with a PoC of client-server communication.

More content coming soon!

This post is licensed under CC BY 4.0 by the author.

-

-