CAPE-parsers 0.1.36__tar.gz → 0.1.38__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/PKG-INFO +1 -1
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/CAPE/community/Lumma.py +117 -30
- cape_parsers-0.1.38/cape_parsers/CAPE/core/AdaptixBeacon.py +102 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/pyproject.toml +1 -1
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/LICENSE +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/README.md +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/CAPE/__init__.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/CAPE/community/AgentTesla.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/CAPE/community/Arkei.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/CAPE/community/AsyncRAT.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/CAPE/community/AuroraStealer.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/CAPE/community/BackOffLoader.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/CAPE/community/BackOffPOS.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/CAPE/community/BlackNix.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/CAPE/community/Carbanak.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/CAPE/community/CobaltStrikeBeacon.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/CAPE/community/CobaltStrikeStager.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/CAPE/community/DCRat.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/CAPE/community/Fareit.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/CAPE/community/Greame.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/CAPE/community/KoiLoader.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/CAPE/community/LokiBot.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/CAPE/community/NanoCore.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/CAPE/community/Nighthawk.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/CAPE/community/Njrat.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/CAPE/community/Pandora.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/CAPE/community/PhemedroneStealer.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/CAPE/community/PoisonIvy.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/CAPE/community/Punisher.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/CAPE/community/QuasarRAT.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/CAPE/community/README.md +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/CAPE/community/REvil.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/CAPE/community/Retefe.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/CAPE/community/Rozena.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/CAPE/community/SmallNet.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/CAPE/community/Snake.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/CAPE/community/SparkRAT.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/CAPE/community/Stealc.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/CAPE/community/TSCookie.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/CAPE/community/TrickBot.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/CAPE/community/VenomRAT.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/CAPE/community/XWorm.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/CAPE/community/XenoRAT.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/CAPE/community/__init__.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/CAPE/core/Azorult.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/CAPE/core/BitPaymer.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/CAPE/core/BlackDropper.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/CAPE/core/Blister.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/CAPE/core/BruteRatel.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/CAPE/core/BuerLoader.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/CAPE/core/BumbleBee.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/CAPE/core/ChChes.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/CAPE/core/DarkGate.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/CAPE/core/DoppelPaymer.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/CAPE/core/DridexLoader.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/CAPE/core/Emotet.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/CAPE/core/Enfal.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/CAPE/core/EvilGrab.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/CAPE/core/Formbook.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/CAPE/core/GuLoader.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/CAPE/core/HttpBrowser.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/CAPE/core/IcedID.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/CAPE/core/IcedIDLoader.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/CAPE/core/Latrodectus.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/CAPE/core/Oyster.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/CAPE/core/PikaBot.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/CAPE/core/PlugX.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/CAPE/core/QakBot.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/CAPE/core/Quickbind.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/CAPE/core/RCSession.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/CAPE/core/README.md +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/CAPE/core/RedLeaf.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/CAPE/core/RedLine.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/CAPE/core/Remcos.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/CAPE/core/Rhadamanthys.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/CAPE/core/SmokeLoader.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/CAPE/core/Socks5Systemz.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/CAPE/core/SquirrelWaffle.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/CAPE/core/Strrat.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/CAPE/core/UrsnifV3.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/CAPE/core/WarzoneRAT.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/CAPE/core/Zloader.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/CAPE/core/__init__.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/CAPE/core/test_cape.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/RATDecoders/README.md +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/RATDecoders/__init__.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/RATDecoders/test_rats.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/__init__.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/deprecated/Hancitor.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/deprecated/JavaDropper.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/deprecated/Nymaim.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/deprecated/PredatorPain.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/deprecated/_ShadowTech.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/deprecated/_VirusRat.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/deprecated/_jRat.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/deprecated/unrecom.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/deprecated/xRAT.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/malduck/LICENSE +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/malduck/README.md +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/malduck/__init__.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/malduck/test_malduck.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/mwcp/README.md +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/mwcp/__init__.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/mwcp/test_mwcp.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/utils/__init__.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/utils/aplib.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/utils/blzpack.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/utils/blzpack_lib.so +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/utils/dotnet_utils.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/utils/lznt1.py +0 -0
- {cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/utils/strings.py +0 -0
|
@@ -3,10 +3,10 @@ import json
|
|
|
3
3
|
import re
|
|
4
4
|
import struct
|
|
5
5
|
from contextlib import suppress
|
|
6
|
-
|
|
7
6
|
import pefile
|
|
8
7
|
import yara
|
|
9
8
|
|
|
9
|
+
|
|
10
10
|
RULE_SOURCE_BUILD_ID = """rule LummaBuildId
|
|
11
11
|
{
|
|
12
12
|
meta:
|
|
@@ -37,6 +37,42 @@ RULE_SOURCE_LUMMA = """rule LummaConfig
|
|
|
37
37
|
$chunk_1
|
|
38
38
|
}"""
|
|
39
39
|
|
|
40
|
+
RULE_SOURCE_LUMMA_NEW_KEYS = """rule LummaConfigNewKeys
|
|
41
|
+
{
|
|
42
|
+
meta:
|
|
43
|
+
author = "YungBinary"
|
|
44
|
+
strings:
|
|
45
|
+
$key_nonce = {
|
|
46
|
+
88 44 24 ??
|
|
47
|
+
B8 ?? ?? ?? ??
|
|
48
|
+
BF ?? ?? ?? ??
|
|
49
|
+
B9 08 00 00 00
|
|
50
|
+
96
|
|
51
|
+
F3 A5
|
|
52
|
+
96
|
|
53
|
+
B8 ?? ?? ?? ??
|
|
54
|
+
}
|
|
55
|
+
condition:
|
|
56
|
+
uint16(0) == 0x5A4D and $key_nonce
|
|
57
|
+
}"""
|
|
58
|
+
|
|
59
|
+
RULE_SOURCE_LUMMA_NEW_ENCRYPTED_C2 = """rule LummaConfigNewEncryptedStrings
|
|
60
|
+
{
|
|
61
|
+
meta:
|
|
62
|
+
author = "YungBinary"
|
|
63
|
+
strings:
|
|
64
|
+
$encrypted_array = {
|
|
65
|
+
0F B6 C?
|
|
66
|
+
C1 E0 07
|
|
67
|
+
8D 80 ?? ?? ?? ??
|
|
68
|
+
8D 74 24 10
|
|
69
|
+
FF
|
|
70
|
+
}
|
|
71
|
+
condition:
|
|
72
|
+
uint16(0) == 0x5A4D and $encrypted_array
|
|
73
|
+
}"""
|
|
74
|
+
|
|
75
|
+
|
|
40
76
|
|
|
41
77
|
def yara_scan_generator(raw_data, rule_source):
|
|
42
78
|
yara_rules = yara.compile(source=rule_source)
|
|
@@ -225,6 +261,15 @@ def get_build_id(pe, data):
|
|
|
225
261
|
continue
|
|
226
262
|
return build_id
|
|
227
263
|
|
|
264
|
+
def get_build_id_new(data):
|
|
265
|
+
build_id = ""
|
|
266
|
+
pattern = b'123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ\x00'
|
|
267
|
+
offset = data.find(pattern)
|
|
268
|
+
if offset != -1:
|
|
269
|
+
build_id = data[offset + len(pattern):].split(b'\x00', 1)[0]
|
|
270
|
+
build_id = build_id.decode()
|
|
271
|
+
|
|
272
|
+
return build_id
|
|
228
273
|
|
|
229
274
|
def extract_config(data):
|
|
230
275
|
config_dict = {"C2": []}
|
|
@@ -236,32 +281,73 @@ def extract_config(data):
|
|
|
236
281
|
pe = pefile.PE(data=data, fast_load=True)
|
|
237
282
|
image_base = pe.OPTIONAL_HEADER.ImageBase
|
|
238
283
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
284
|
+
# Parse the latest version
|
|
285
|
+
key = None
|
|
286
|
+
nonce = None
|
|
287
|
+
for offset in yara_scan_generator(data, RULE_SOURCE_LUMMA_NEW_KEYS):
|
|
288
|
+
key_rva = struct.unpack('i', data[offset + 5 : offset + 9])[0]
|
|
289
|
+
key_offset = pe.get_offset_from_rva(key_rva - image_base)
|
|
290
|
+
key = data[key_offset : key_offset + 32]
|
|
291
|
+
nonce_rva = struct.unpack('i', data[offset + 24 : offset + 28])[0]
|
|
292
|
+
nonce_offset = pe.get_offset_from_rva(nonce_rva - image_base)
|
|
293
|
+
nonce = b'\x00\x00\x00\x00' + data[nonce_offset : nonce_offset + 8]
|
|
294
|
+
|
|
295
|
+
if key and nonce:
|
|
296
|
+
for offset in yara_scan_generator(data, RULE_SOURCE_LUMMA_NEW_ENCRYPTED_C2):
|
|
297
|
+
encrypted_strings_rva = struct.unpack('i', data[offset + 8 : offset + 12])[0]
|
|
298
|
+
encrypted_strings_offset = pe.get_offset_from_rva(encrypted_strings_rva - image_base)
|
|
299
|
+
step_size = 0x80
|
|
300
|
+
counter = 2
|
|
301
|
+
for i in range(12):
|
|
302
|
+
encrypted_string = data[encrypted_strings_offset:encrypted_strings_offset+40]
|
|
303
|
+
decoded_c2 = chacha20_xor(encrypted_string, key, nonce, counter).split(b'\x00', 1)[0]
|
|
304
|
+
if contains_non_printable(decoded_c2):
|
|
305
|
+
break
|
|
306
|
+
config_dict["C2"].append(decoded_c2.decode())
|
|
307
|
+
encrypted_strings_offset = encrypted_strings_offset + step_size
|
|
308
|
+
counter += 2
|
|
309
|
+
|
|
310
|
+
if config_dict["C2"]:
|
|
311
|
+
# If found C2 servers try to find build ID
|
|
312
|
+
build_id = get_build_id_new(data)
|
|
313
|
+
if build_id:
|
|
314
|
+
config_dict["Build ID"] = build_id
|
|
315
|
+
|
|
316
|
+
|
|
317
|
+
# If no C2s try with the version after Jan 21, 2025
|
|
318
|
+
if not config_dict["C2"]:
|
|
319
|
+
offset = yara_scan(data, RULE_SOURCE_LUMMA)
|
|
320
|
+
if offset:
|
|
321
|
+
key = data[offset + 16 : offset + 48]
|
|
322
|
+
nonce = b"\x00\x00\x00\x00" + data[offset + 48 : offset + 56]
|
|
253
323
|
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
if
|
|
260
|
-
|
|
261
|
-
|
|
324
|
+
for i in range(9):
|
|
325
|
+
try:
|
|
326
|
+
start_offset = offset + 56 + (i * 4)
|
|
327
|
+
end_offset = start_offset + 4
|
|
328
|
+
c2_dword_rva = struct.unpack('i', data[start_offset : end_offset])[0]
|
|
329
|
+
if pe:
|
|
330
|
+
c2_dword_offset = pe.get_offset_from_rva(c2_dword_rva - image_base)
|
|
331
|
+
else:
|
|
332
|
+
c2_dword_offset = c2_dword_rva - image_base
|
|
333
|
+
|
|
334
|
+
c2_encrypted = data[c2_dword_offset : c2_dword_offset + 0x80]
|
|
335
|
+
counters = [0, 2, 4, 6, 8, 10, 12, 14, 16]
|
|
336
|
+
for counter in counters:
|
|
337
|
+
decrypted = chacha20_xor(c2_encrypted, key, nonce, counter)
|
|
338
|
+
c2 = extract_c2_domain(decrypted)
|
|
339
|
+
if c2 is not None and len(c2) > 10:
|
|
340
|
+
config_dict["C2"].append(c2.decode())
|
|
341
|
+
break
|
|
262
342
|
|
|
263
|
-
|
|
264
|
-
|
|
343
|
+
except Exception:
|
|
344
|
+
continue
|
|
345
|
+
|
|
346
|
+
if config_dict["C2"] and pe is not None:
|
|
347
|
+
# If found C2 servers try to find build ID
|
|
348
|
+
build_id = get_build_id(pe, data)
|
|
349
|
+
if build_id:
|
|
350
|
+
config_dict["Build ID"] = build_id
|
|
265
351
|
|
|
266
352
|
|
|
267
353
|
# If no C2s try with version prior to Jan 21, 2025
|
|
@@ -293,11 +379,12 @@ def extract_config(data):
|
|
|
293
379
|
except Exception:
|
|
294
380
|
return
|
|
295
381
|
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
382
|
+
if config_dict["C2"] and pe is not None:
|
|
383
|
+
# If found C2 servers try to find build ID
|
|
384
|
+
build_id = get_build_id(pe, data)
|
|
385
|
+
if build_id:
|
|
386
|
+
config_dict["Build ID"] = build_id
|
|
387
|
+
|
|
301
388
|
|
|
302
389
|
return config_dict
|
|
303
390
|
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import struct
|
|
3
|
+
from contextlib import suppress
|
|
4
|
+
|
|
5
|
+
import pefile
|
|
6
|
+
from Cryptodome.Cipher import ARC4
|
|
7
|
+
|
|
8
|
+
log = logging.getLogger(__name__)
|
|
9
|
+
|
|
10
|
+
DESCRIPTION = "Adaptix beacon configuration parser."
|
|
11
|
+
AUTHOR = "enzok"
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def parse_http_config(rc4_key: bytes, data: bytes) -> dict:
|
|
15
|
+
config = {}
|
|
16
|
+
offset = 0
|
|
17
|
+
servers = []
|
|
18
|
+
ports = []
|
|
19
|
+
|
|
20
|
+
def read(fmt: str):
|
|
21
|
+
nonlocal offset
|
|
22
|
+
size = struct.calcsize(fmt)
|
|
23
|
+
value = struct.unpack_from(fmt, data, offset)
|
|
24
|
+
offset += size
|
|
25
|
+
return value if len(value) > 1 else value[0]
|
|
26
|
+
|
|
27
|
+
def read_str(length: int):
|
|
28
|
+
nonlocal offset
|
|
29
|
+
value = data[offset:offset + length].decode("utf-8", errors="replace")
|
|
30
|
+
offset += length
|
|
31
|
+
return value
|
|
32
|
+
|
|
33
|
+
config["config_rc4_key"] = rc4_key.hex()
|
|
34
|
+
config["agent_type"] = f"{read('<I'):8X}"
|
|
35
|
+
config["use_ssl"] = read("<B")
|
|
36
|
+
host_count = read("<I")
|
|
37
|
+
for host in range(host_count):
|
|
38
|
+
host_length = read("<I")
|
|
39
|
+
servers.append(read_str(host_length).strip("\x00"))
|
|
40
|
+
ports.append(read("<I"))
|
|
41
|
+
|
|
42
|
+
config["servers"] = servers
|
|
43
|
+
config["ports"] = ports
|
|
44
|
+
method_length = read("<I")
|
|
45
|
+
config["http_method"] = read_str(method_length).strip("\x00")
|
|
46
|
+
uri_length = read("<I")
|
|
47
|
+
config["uri"] = read_str(uri_length).strip("\x00")
|
|
48
|
+
parameter_length = read("<I")
|
|
49
|
+
config["parameter"] = read_str(parameter_length).strip("\x00")
|
|
50
|
+
useragent_length = read("<I")
|
|
51
|
+
config["user_agent"] = read_str(useragent_length).strip("\x00")
|
|
52
|
+
headers_length = read("<I")
|
|
53
|
+
config["http_headers"] = read_str(headers_length).strip("\x00")
|
|
54
|
+
config["ans_pre_size"] = read("<I")
|
|
55
|
+
config["ans_size"] = read("<I")
|
|
56
|
+
config["kill_date"] = read("<I")
|
|
57
|
+
config["working_time"] = read("<I")
|
|
58
|
+
config["sleep_delay"] = read("<I")
|
|
59
|
+
config["jitter_delay"] = read("<I")
|
|
60
|
+
|
|
61
|
+
return config
|
|
62
|
+
|
|
63
|
+
def extract_config(filebuf: bytes) -> dict:
|
|
64
|
+
pe = pefile.PE(data=filebuf, fast_load=True)
|
|
65
|
+
data_sections = [s for s in pe.sections if b".rdata" in s.Name]
|
|
66
|
+
if not data_sections:
|
|
67
|
+
return
|
|
68
|
+
|
|
69
|
+
data = data_sections[0].get_data()
|
|
70
|
+
data_len = len(data)
|
|
71
|
+
pos = 0
|
|
72
|
+
while pos + 4 <= data_len:
|
|
73
|
+
start_offset = pos
|
|
74
|
+
key_offset = struct.unpack_from("<I", data, pos)[0]
|
|
75
|
+
pos += 4
|
|
76
|
+
|
|
77
|
+
if pos + key_offset + 32 > data_len:
|
|
78
|
+
pos = start_offset + 1
|
|
79
|
+
continue
|
|
80
|
+
|
|
81
|
+
encrypted_data = data[pos:pos + key_offset]
|
|
82
|
+
pos += key_offset
|
|
83
|
+
rc4_key = data[pos:pos + 16]
|
|
84
|
+
|
|
85
|
+
if key_offset == 787:
|
|
86
|
+
pass
|
|
87
|
+
|
|
88
|
+
with suppress(Exception):
|
|
89
|
+
decrypted = ARC4.new(rc4_key).decrypt(encrypted_data)
|
|
90
|
+
if b"User-Agent" in decrypted:
|
|
91
|
+
return parse_http_config(rc4_key, decrypted)
|
|
92
|
+
|
|
93
|
+
pos = start_offset + 1
|
|
94
|
+
|
|
95
|
+
return None
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
if __name__ == "__main__":
|
|
99
|
+
import sys
|
|
100
|
+
|
|
101
|
+
with open(sys.argv[1], "rb") as f:
|
|
102
|
+
print(extract_config(f.read()))
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/CAPE/community/CobaltStrikeBeacon.py
RENAMED
|
File without changes
|
{cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/CAPE/community/CobaltStrikeStager.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{cape_parsers-0.1.36 → cape_parsers-0.1.38}/cape_parsers/CAPE/community/PhemedroneStealer.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|