# Peering into spam botnets. ### Jaroslaw Jedynak Maciej Kotowicz ## 1 Intro - Emotet[1] ## 2 Emotet 1its spamming module to be precise, and its newest version ----- very long name with lots of dashes[2] ### 2.1 spam operation 2Dhl_Status_zu_Sendung_340839262847_____ID_S01_DHL__DEM06_MS02_06_2015___A23_21_15.exe ----- ## 3 Kelihos ### 3.1 Peer handshake ----- ----- ### 3.2 Peer list exchange ``` while (it != strc.list.tail) ``` ----- ``` return crypt; if (++strc->offset >= strc->str->length) strc->offset = 0; ``` ----- ## 4 Necurs ----- ### 4.1 High-level overview - First, a couple of domains or raw IP addresses are embedded in the program ----- ----- ### 4.2 Binary resources ``` def get_base(dump): for i in range(len(dump) - 0x10): if (a * 0x48F1398FECF + 12345678901253) & 0xFFFFFFFFFFFFFFFF == b: return i struct resourceList { struct singleResource { def next_key(k): return k def decrypt_resources(dump): for i in range(8): ``` ----- ``` for i in range(base + 0x18, len(dump)): if compressed_size != real_size: while True: if not id: break ### 4.3 DGA and P2P def dga_mix_and_hash(param): ``` ----- ``` for i in range((param & 0x7F) + 21): return param def dga_generate_one(year, month, day, seed, rnd_param): for i in range((mix % 15) + 7): return domain + "." + [ struct outer_layer{ def rolling_xor(outer_layer): for c in msg: ``` ----- ``` assert outer_layer.checksum == check return buff struct inner_layer { struct greeting{ struct response{ ### 4.4 C&C communication def xor_encrypt(outer_layer): for c in outer_layer.data: ``` ----- ``` assert res == outer_layer.checksum return buf struct cc_structure{ struct cc_resource{ ``` ----- ``` struct cc_resource_type_0 { struct cc_resource_type_1 { struct cc_resource_type_2 { struct cc_resource_type_3 { struct cc_resource_type_4 { struct cc_resource_type_5 { ``` ----- ``` struct subresource{ ### 4.5 Spam module - communication struct spam_wrap{ def encrypt(msg, key): for c in msg: ``` ----- ``` return res def send_message(json): return requests.post(dom, data=payload, timeout=30) ``` ----- ### 4.6 Proxy/DDoS module - communication ----- ### 4.7 Tracking ## 5 Send-Safe ----- ### 5.1 Communication **5.1.1** **Configuration** **5.1.2** **Communication - UDP** ----- ``` struct req_s { struct version { int __cdecl COMM::xor(_BYTE *a1, int size) for ( i = 0; i < size; ++i ) return result; ``` ----- **5.1.3** **Communication - HTTPS** - 100 - email details, including subject, message body and how to impersonate ----- ``` class SFile(M): def elem(self): if flag & 0x10000: else: return flag,data def parse(self): for i in range(cnt): yield self.elem() ### 5.2 Email templates 5.3 Curious spamming habits ## 6 Tofsee ``` ----- ----- ### 6.1 Technical analysis ``` def decrypt(s, key, inc): for c in s: return result 6.2 Communication protocol for c in data: return dec, prev struct greeting { ``` ----- ----- ``` def xor_crypt(data, key_data): for c in data: return res struct header { struct botdata { ``` ----- ``` struct resource { ### 6.3 Resources ``` ----- **6.3.1** **Type 5** **6.3.2** **Type 11** **6.3.3** **Type 8** ----- **6.3.4** **Type 23-40** ``` def parse_config(payload): return dict(chunks(payload.split('\x00'), 2)[:-1]) ### 6.4 Tracking ``` ----- ## 7 Closing Words ### 7.1 Acknowledgment ## 8 Hashes (sha256) ``` 0eb2eb8c5c21cfd6b89c1e14b3b66f869148f06fa0611ad3e7aa06e285a7e9c6 ``` ----- ## 9 References ----- ## 10 Appendices ### 10.1 Kelihos encryption algorithms **10.1.1** **bitcrypt1** ``` def bitstuff_enc(b): for i in range(8): if lobit != prevbit: if i: if b & 1 == 0: return out & 0xFF def bit1_enc(string): return map_string(string, bitstuff_enc) ``` **10.1.2** **bitcrypt2** ``` def bitstuff2_enc(chr): for i in range(8): if curbit == prevbit: if mask: return result >> 1 ``` ----- ``` def bit2_enc(string): return map_string(string, bitstuff2_enc) ``` **10.1.3** `mathops crypt` **10.1.4** **Full encryption routine** ``` def decrypt_raw_data(data): ``` ----- ### 10.2 Send-Safe Email Template ----- ### 10.3 Tofsee Type 11 Script ----- ----- -----