dissect.cobaltstrike 1.2.1.dev4__tar.gz → 1.2.1.dev6__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.
- {dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/PKG-INFO +1 -1
- {dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/dissect/cobaltstrike/_version.py +2 -2
- {dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/dissect/cobaltstrike/beacon.py +98 -0
- {dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/dissect/cobaltstrike/c2profile.lark +31 -0
- {dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/dissect/cobaltstrike/c2profile.py +53 -0
- {dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/tests/test_c2profile.py +101 -0
- {dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/.github/workflows/dissect-ci.yml +0 -0
- {dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/.gitignore +0 -0
- {dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/.lfs-assets-id +0 -0
- {dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/.pre-commit-config.yaml +0 -0
- {dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/.readthedocs.yml +0 -0
- {dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/LICENSE +0 -0
- {dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/README.rst +0 -0
- {dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/codecov.yml +0 -0
- {dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/dissect/cobaltstrike/__init__.py +0 -0
- {dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/dissect/cobaltstrike/artifact.py +0 -0
- {dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/dissect/cobaltstrike/c2.py +0 -0
- {dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/dissect/cobaltstrike/c_c2.py +0 -0
- {dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/dissect/cobaltstrike/client.py +0 -0
- {dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/dissect/cobaltstrike/pcap.py +0 -0
- {dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/dissect/cobaltstrike/pe.py +0 -0
- {dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/dissect/cobaltstrike/utils.py +0 -0
- {dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/dissect/cobaltstrike/version.py +0 -0
- {dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/dissect/cobaltstrike/xordecode.py +0 -0
- {dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/docs/Makefile +0 -0
- {dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/docs/c2profile-grammar.rst +0 -0
- {dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/docs/codespell-ignore-words.txt +0 -0
- {dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/docs/conf.py +0 -0
- {dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/docs/examples.rst +0 -0
- {dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/docs/images/beacon-client.png +0 -0
- {dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/docs/images/teamserver-echoclient.png +0 -0
- {dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/docs/images/teamserver_ls.png +0 -0
- {dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/docs/images/vt-cobaltstrike-43-zip.png +0 -0
- {dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/docs/index.rst +0 -0
- {dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/docs/installation.rst +0 -0
- {dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/docs/license.rst +0 -0
- {dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/docs/scripts/checksum8-accesslogs.rst +0 -0
- {dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/docs/scripts/dump_beacon_keys.rst +0 -0
- {dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/docs/scripts/example_client.rst +0 -0
- {dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/docs/scripts/index.rst +0 -0
- {dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/docs/structures/c2_def.rst +0 -0
- {dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/docs/structures/cs_def.rst +0 -0
- {dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/docs/structures/index.rst +0 -0
- {dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/docs/structures/pe_def.rst +0 -0
- {dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/docs/tools/beacon-artifact.rst +0 -0
- {dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/docs/tools/beacon-client.rst +0 -0
- {dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/docs/tools/beacon-dump.rst +0 -0
- {dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/docs/tools/beacon-pcap.rst +0 -0
- {dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/docs/tools/beacon-xordecode.rst +0 -0
- {dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/docs/tools/c2profile-dump.rst +0 -0
- {dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/docs/tutorials/decrypt_cobaltstrike_pcaps.rst +0 -0
- {dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/docs/tutorials/index.rst +0 -0
- {dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/docs/tutorials/minimal_beacon_client.rst +0 -0
- {dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/pyproject.toml +0 -0
- {dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/scripts/checksum8-accesslogs.py +0 -0
- {dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/scripts/dump_beacon_keys.py +0 -0
- {dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/scripts/example_client.py +0 -0
- {dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/tests/conftest.py +0 -0
- {dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/tests/test_beacon.py +0 -0
- {dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/tests/test_c2.py +0 -0
- {dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/tests/test_client.py +0 -0
- {dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/tests/test_pe.py +0 -0
- {dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/tests/test_utils.py +0 -0
- {dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/tests/test_version.py +0 -0
- {dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/tests/test_xordecode.py +0 -0
- {dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/tox.ini +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: dissect.cobaltstrike
|
|
3
|
-
Version: 1.2.1.
|
|
3
|
+
Version: 1.2.1.dev6
|
|
4
4
|
Summary: a Python library for dissecting Cobalt Strike related data
|
|
5
5
|
Project-URL: Homepage, https://github.com/fox-it/dissect.cobaltstrike
|
|
6
6
|
Project-URL: Documentation, https://dissect-cobaltstrike.readthedocs.io/
|
{dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/dissect/cobaltstrike/_version.py
RENAMED
|
@@ -12,5 +12,5 @@ __version__: str
|
|
|
12
12
|
__version_tuple__: VERSION_TUPLE
|
|
13
13
|
version_tuple: VERSION_TUPLE
|
|
14
14
|
|
|
15
|
-
__version__ = version = '1.2.1.
|
|
16
|
-
__version_tuple__ = version_tuple = (1, 2, 1, '
|
|
15
|
+
__version__ = version = '1.2.1.dev6'
|
|
16
|
+
__version_tuple__ = version_tuple = (1, 2, 1, 'dev6')
|
{dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/dissect/cobaltstrike/beacon.py
RENAMED
|
@@ -170,6 +170,12 @@ enum BeaconSetting: uint16 {
|
|
|
170
170
|
|
|
171
171
|
// CobaltStrike version >= 4.7 (Aug 17, 2022)
|
|
172
172
|
SETTING_MASKED_WATERMARK = 74,
|
|
173
|
+
|
|
174
|
+
// CobaltStrike version >= 4.9 (Sep 19, 2023)
|
|
175
|
+
SETTING_DATA_STORE_SIZE = 76,
|
|
176
|
+
|
|
177
|
+
// CobaltStrike version >= 4.10 (Jul 16, 2024)
|
|
178
|
+
SETTING_BEACON_GATE = 78,
|
|
173
179
|
};
|
|
174
180
|
|
|
175
181
|
enum DeprecatedBeaconSetting: uint16 {
|
|
@@ -247,6 +253,39 @@ enum InjectExecutor: uint8 {
|
|
|
247
253
|
CreateRemoteThread_ = 7,
|
|
248
254
|
NtQueueApcThread_s = 8
|
|
249
255
|
};
|
|
256
|
+
|
|
257
|
+
enum BofAllocator: uint16 {
|
|
258
|
+
VirtualAlloc = 0,
|
|
259
|
+
MapViewOfFile = 1,
|
|
260
|
+
HeapAlloc = 2,
|
|
261
|
+
};
|
|
262
|
+
|
|
263
|
+
// https://hstechdocs.helpsystems.com/manuals/cobaltstrike/current/userguide/content/topics/beacon-gate.htm
|
|
264
|
+
struct BeaconGateOptions {
|
|
265
|
+
uint8 InternetOpenA; // commms
|
|
266
|
+
uint8 InternetConnectA;
|
|
267
|
+
uint8 VirtualAlloc; // core
|
|
268
|
+
uint8 VirtualAllocEx;
|
|
269
|
+
uint8 VirtualProtect;
|
|
270
|
+
uint8 VirtualProtectEx;
|
|
271
|
+
uint8 VirtualFree;
|
|
272
|
+
uint8 GetThreadContext;
|
|
273
|
+
uint8 SetThreadContext;
|
|
274
|
+
uint8 ResumeThread;
|
|
275
|
+
uint8 CreateThread;
|
|
276
|
+
uint8 CreateRemoteThread;
|
|
277
|
+
uint8 OpenProcess;
|
|
278
|
+
uint8 OpenThread;
|
|
279
|
+
uint8 CloseHandle;
|
|
280
|
+
uint8 CreateFileMappingA;
|
|
281
|
+
uint8 MapViewOfFile;
|
|
282
|
+
uint8 UnmapViewOfFile;
|
|
283
|
+
uint8 VirtualQuery;
|
|
284
|
+
uint8 DuplicateHandle;
|
|
285
|
+
uint8 ReadProcessMemory;
|
|
286
|
+
uint8 WriteProcessMemory;
|
|
287
|
+
uint8 ExitThread; // cleanup
|
|
288
|
+
};
|
|
250
289
|
"""
|
|
251
290
|
|
|
252
291
|
cs_struct = cstruct.cstruct(endian=">")
|
|
@@ -262,6 +301,8 @@ CryptoScheme = cs_struct.CryptoScheme
|
|
|
262
301
|
ProxyServer = cs_struct.ProxyServer
|
|
263
302
|
InjectAllocator = cs_struct.InjectAllocator
|
|
264
303
|
InjectExecutor = cs_struct.InjectExecutor
|
|
304
|
+
BofAllocator = cs_struct.BofAllocator
|
|
305
|
+
BeaconGateOptions = cs_struct.BeaconGateOptions
|
|
265
306
|
|
|
266
307
|
DEFAULT_XOR_KEYS: List[bytes] = [b"\x69", b"\x2e", b"\x00"]
|
|
267
308
|
""" Default XOR keys used by Cobalt Strike for obfuscating Beacon config bytes """
|
|
@@ -574,6 +615,61 @@ def parse_pivot_frame(data: bytes) -> bytes:
|
|
|
574
615
|
return p.read(length - 4)
|
|
575
616
|
|
|
576
617
|
|
|
618
|
+
def parse_beacon_gate(data: bytes) -> BeaconGateOptions:
|
|
619
|
+
"""Parse ``SETTING_BEACON_GATE`` (`.stage.beacon_gate`) data"""
|
|
620
|
+
return BeaconGateOptions(data)
|
|
621
|
+
|
|
622
|
+
|
|
623
|
+
def beacon_gate_options_string(bgo: BeaconGateOptions) -> list[str]:
|
|
624
|
+
"""Return the enabled BeaconGate WinAPI's as a list of strings"""
|
|
625
|
+
options = {k for k, v in bgo._values.items() if v}
|
|
626
|
+
|
|
627
|
+
comms = {"InternetOpenA", "InternetConnectA"}
|
|
628
|
+
core = {
|
|
629
|
+
"VirtualAlloc",
|
|
630
|
+
"VirtualAllocEx",
|
|
631
|
+
"VirtualProtect",
|
|
632
|
+
"VirtualProtectEx",
|
|
633
|
+
"VirtualFree",
|
|
634
|
+
"GetThreadContext",
|
|
635
|
+
"SetThreadContext",
|
|
636
|
+
"ResumeThread",
|
|
637
|
+
"CreateThread",
|
|
638
|
+
"CreateRemoteThread",
|
|
639
|
+
"OpenProcess",
|
|
640
|
+
"OpenThread",
|
|
641
|
+
"CloseHandle",
|
|
642
|
+
"CreateFileMappingA",
|
|
643
|
+
"MapViewOfFile",
|
|
644
|
+
"UnmapViewOfFile",
|
|
645
|
+
"VirtualQuery",
|
|
646
|
+
"DuplicateHandle",
|
|
647
|
+
"ReadProcessMemory",
|
|
648
|
+
"WriteProcessMemory",
|
|
649
|
+
}
|
|
650
|
+
cleanup = {"ExitThread"}
|
|
651
|
+
|
|
652
|
+
ret = []
|
|
653
|
+
if options.issuperset(comms | core | cleanup):
|
|
654
|
+
ret.append("All")
|
|
655
|
+
options -= comms | core | cleanup
|
|
656
|
+
|
|
657
|
+
if options.issuperset(comms):
|
|
658
|
+
ret.append("Comms")
|
|
659
|
+
options -= comms
|
|
660
|
+
|
|
661
|
+
if options.issuperset(core):
|
|
662
|
+
ret.append("Core")
|
|
663
|
+
options -= core
|
|
664
|
+
|
|
665
|
+
if options.issuperset(cleanup):
|
|
666
|
+
ret.append("Cleanup")
|
|
667
|
+
options -= cleanup
|
|
668
|
+
|
|
669
|
+
ret.extend(options)
|
|
670
|
+
return ret
|
|
671
|
+
|
|
672
|
+
|
|
577
673
|
def sha256sum_pubkey(der_data: bytes) -> str:
|
|
578
674
|
"""Return the SHA-256 digest of `der_data`"""
|
|
579
675
|
return hashlib.sha256(der_data.rstrip(b"\x00")).hexdigest()
|
|
@@ -635,6 +731,8 @@ SETTING_TO_PRETTYFUNC: Dict[BeaconSetting, Callable] = {
|
|
|
635
731
|
BeaconSetting.SETTING_DNS_IDLE: lambda x: str(ipaddress.IPv4Address(x)),
|
|
636
732
|
BeaconSetting.SETTING_WATERMARKHASH: lambda x: null_terminated_bytes(x) if isinstance(x, bytes) else x,
|
|
637
733
|
BeaconSetting.SETTING_MASKED_WATERMARK: lambda x: x.hex(),
|
|
734
|
+
BeaconSetting.SETTING_BOF_ALLOCATOR: lambda x: BofAllocator(x).name,
|
|
735
|
+
BeaconSetting.SETTING_BEACON_GATE: lambda x: beacon_gate_options_string(parse_beacon_gate(x)),
|
|
638
736
|
# BeaconSetting.SETTING_PROTOCOL: lambda x: BeaconProtocol(x).name,
|
|
639
737
|
# BeaconSetting.SETTING_CRYPTO_SCHEME: lambda x: CryptoScheme(x).name,
|
|
640
738
|
# BeaconSetting.SETTING_PROXY_BEHAVIOR: lambda x: ProxyServer(x).name,
|
|
@@ -137,6 +137,8 @@ stage_options: "string" string ";" -> string
|
|
|
137
137
|
| "set" "rich_header" string ";" -> rich_header
|
|
138
138
|
| "set" "checksum" string ";" -> checksum
|
|
139
139
|
| "set" "syscall_method" string ";" -> syscall_method // introduced in Cobalt Strike 4.8
|
|
140
|
+
| "set" "data_store_size" string ";" -> data_store_size // introduced in Cobalt Strike 4.9
|
|
141
|
+
| "beacon_gate" "{" beacon_gate_options* "}" -> beacon_gate // introduced in Cobalt Strike 4.10
|
|
140
142
|
|
|
141
143
|
process_inject_options: "set" "allocator" string ";" -> allocator
|
|
142
144
|
| "set" "min_alloc" string ";" -> min_alloc
|
|
@@ -158,6 +160,35 @@ execute_options: "CreateThread" string ";" -> createthread_special
|
|
|
158
160
|
| "RtlCreateUserThread" ";" -> rtlcreateuserthread
|
|
159
161
|
| "SetThreadContext" ";" -> setthreadcontext
|
|
160
162
|
|
|
163
|
+
beacon_gate_options: "None" ";" -> none
|
|
164
|
+
| "Comms" ";" -> comms
|
|
165
|
+
| "Core" ";" -> core
|
|
166
|
+
| "Cleanup" ";" -> cleanup
|
|
167
|
+
| "All" ";" -> all
|
|
168
|
+
| "InternetOpenA" ";" -> internetopena
|
|
169
|
+
| "InternetConnectA" ";" -> internetconnecta
|
|
170
|
+
| "VirtualAlloc" ";" -> virtualalloc
|
|
171
|
+
| "VirtualAllocEx" ";" -> virtualallocex
|
|
172
|
+
| "VirtualProtect" ";" -> virtualprotect
|
|
173
|
+
| "VirtualProtectEx" ";" -> virtualprotextex
|
|
174
|
+
| "VirtualFree" ";" -> virtualfree
|
|
175
|
+
| "GetThreadContext" ";" -> getthreadcontext
|
|
176
|
+
| "SetThreadContext" ";" -> setthreadcontext
|
|
177
|
+
| "ResumeThread" ";" -> resumethread
|
|
178
|
+
| "CreateThread" ";" -> createthread
|
|
179
|
+
| "CreateRemoteThread" ";" -> createremotethread
|
|
180
|
+
| "OpenProcess" ";" -> openprocess
|
|
181
|
+
| "OpenThread" ";" -> openthread
|
|
182
|
+
| "CloseHandle" ";" -> closehandle
|
|
183
|
+
| "CreateFileMappingA" ";" -> createfilemappinga
|
|
184
|
+
| "MapViewOfFile" ";" -> mapviewoffile
|
|
185
|
+
| "UnmapViewOfFile" ";" -> unmapviewoffile
|
|
186
|
+
| "VirtualQuery" ";" -> virtualquery
|
|
187
|
+
| "DuplicateHandle" ";" -> duplicatehandle
|
|
188
|
+
| "ReadProcessMemory" ";" -> readprocessmemory
|
|
189
|
+
| "WriteProcessMemory" ";" -> writeprocessmemory
|
|
190
|
+
| "ExitThread" ";" -> exitthread
|
|
191
|
+
|
|
161
192
|
postex_options: "set" "spawnto_x86" string ";" -> spawnto_x86
|
|
162
193
|
| "set" "spawnto_x64" string ";" -> spawnto_x64
|
|
163
194
|
| "set" "obfuscate" string ";" -> obfuscate
|
|
@@ -350,6 +350,50 @@ class ExecuteOptionsBlock(ConfigBlock):
|
|
|
350
350
|
return block
|
|
351
351
|
|
|
352
352
|
|
|
353
|
+
class BeaconGateBlock(ConfigBlock):
|
|
354
|
+
"""`.stage.beacon_gate` block"""
|
|
355
|
+
|
|
356
|
+
__name__ = "BeaconGateBlock"
|
|
357
|
+
|
|
358
|
+
none = ConfigBlock._enable
|
|
359
|
+
comms = ConfigBlock._enable
|
|
360
|
+
core = ConfigBlock._enable
|
|
361
|
+
cleanup = ConfigBlock._enable
|
|
362
|
+
all = ConfigBlock._enable
|
|
363
|
+
internetopena = ConfigBlock._enable
|
|
364
|
+
internetconnecta = ConfigBlock._enable
|
|
365
|
+
virtualalloc = ConfigBlock._enable
|
|
366
|
+
virtualallocex = ConfigBlock._enable
|
|
367
|
+
virtualprotect = ConfigBlock._enable
|
|
368
|
+
virtualprotextex = ConfigBlock._enable
|
|
369
|
+
virtualfree = ConfigBlock._enable
|
|
370
|
+
getthreadcontext = ConfigBlock._enable
|
|
371
|
+
setthreadcontext = ConfigBlock._enable
|
|
372
|
+
resumethread = ConfigBlock._enable
|
|
373
|
+
createthread = ConfigBlock._enable
|
|
374
|
+
createremotethread = ConfigBlock._enable
|
|
375
|
+
openprocess = ConfigBlock._enable
|
|
376
|
+
openthread = ConfigBlock._enable
|
|
377
|
+
closehandle = ConfigBlock._enable
|
|
378
|
+
createfilemappinga = ConfigBlock._enable
|
|
379
|
+
mapviewoffile = ConfigBlock._enable
|
|
380
|
+
unmapviewoffile = ConfigBlock._enable
|
|
381
|
+
virtualquery = ConfigBlock._enable
|
|
382
|
+
duplicatehandle = ConfigBlock._enable
|
|
383
|
+
readprocessmemory = ConfigBlock._enable
|
|
384
|
+
writeprocessmemory = ConfigBlock._enable
|
|
385
|
+
exitthread = ConfigBlock._enable
|
|
386
|
+
|
|
387
|
+
@classmethod
|
|
388
|
+
def from_beacon_gate_option_strings(cls, options: list[str]):
|
|
389
|
+
block = cls()
|
|
390
|
+
|
|
391
|
+
for option in options:
|
|
392
|
+
block._enable(option.lower(), True)
|
|
393
|
+
|
|
394
|
+
return block
|
|
395
|
+
|
|
396
|
+
|
|
353
397
|
class C2Profile(ConfigBlock):
|
|
354
398
|
"""A :class:`C2Profile` object represents a parsed Malleable C2 Profile
|
|
355
399
|
|
|
@@ -618,6 +662,15 @@ class C2Profile(ConfigBlock):
|
|
|
618
662
|
dns_beacon.set_option("dns_sleep", value)
|
|
619
663
|
elif setting == BeaconSetting.SETTING_MAXDNS:
|
|
620
664
|
dns_beacon.set_option("maxdns", value)
|
|
665
|
+
elif setting == BeaconSetting.SETTING_PROCINJ_BOF_REUSE_MEM and value:
|
|
666
|
+
proc_inj.set_option("bof_reuse_memory", "true")
|
|
667
|
+
elif setting == BeaconSetting.SETTING_BOF_ALLOCATOR:
|
|
668
|
+
proc_inj.set_option("bof_allocator", value)
|
|
669
|
+
elif setting == BeaconSetting.SETTING_DATA_STORE_SIZE:
|
|
670
|
+
stage.set_option("data_store_size", value)
|
|
671
|
+
elif setting == BeaconSetting.SETTING_BEACON_GATE and value:
|
|
672
|
+
block = BeaconGateBlock.from_beacon_gate_option_strings(value)
|
|
673
|
+
stage.set_config_block("beacon_gate", block)
|
|
621
674
|
|
|
622
675
|
if c2_recover:
|
|
623
676
|
http_get.set_non_empty_config_block("server", HttpOptionsBlock(output=DataTransformBlock(steps=c2_recover)))
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
|
|
1
3
|
from dissect.cobaltstrike import beacon, c2profile
|
|
2
4
|
|
|
3
5
|
C2PROFILE_SOURCE = """
|
|
@@ -294,3 +296,102 @@ def test_c2profile_v48():
|
|
|
294
296
|
"""
|
|
295
297
|
profile = c2profile.C2Profile.from_text(c2profile_fragment)
|
|
296
298
|
assert profile.properties["stage.syscall_method"] == ["direct"]
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
def test_c2profile_v49():
|
|
302
|
+
c2profile_fragment = """
|
|
303
|
+
stage {
|
|
304
|
+
set data_store_size "1024";
|
|
305
|
+
}
|
|
306
|
+
"""
|
|
307
|
+
profile = c2profile.C2Profile.from_text(c2profile_fragment)
|
|
308
|
+
assert profile.properties["stage.data_store_size"] == ["1024"]
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
def test_c2profile_v410():
|
|
312
|
+
c2profile_fragment = """
|
|
313
|
+
stage {
|
|
314
|
+
beacon_gate {
|
|
315
|
+
All;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
"""
|
|
319
|
+
profile = c2profile.C2Profile.from_text(c2profile_fragment)
|
|
320
|
+
assert profile.properties["stage.beacon_gate"] == ["All"]
|
|
321
|
+
|
|
322
|
+
c2profile_fragment = """
|
|
323
|
+
stage {
|
|
324
|
+
beacon_gate {
|
|
325
|
+
VirtualAlloc;
|
|
326
|
+
WriteProcessMemory;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
"""
|
|
330
|
+
profile = c2profile.C2Profile.from_text(c2profile_fragment)
|
|
331
|
+
assert profile.properties["stage.beacon_gate"] == ["VirtualAlloc", "WriteProcessMemory"]
|
|
332
|
+
|
|
333
|
+
|
|
334
|
+
@pytest.mark.parametrize(
|
|
335
|
+
("allocator_enum", "bof_allocator"),
|
|
336
|
+
[
|
|
337
|
+
(beacon.BofAllocator.HeapAlloc, "HeapAlloc"),
|
|
338
|
+
(beacon.BofAllocator.MapViewOfFile, "MapViewOfFile"),
|
|
339
|
+
(beacon.BofAllocator.HeapAlloc, "HeapAlloc"),
|
|
340
|
+
],
|
|
341
|
+
)
|
|
342
|
+
def test_c2profile_bof_allocator(allocator_enum, bof_allocator):
|
|
343
|
+
data = beacon.Setting(
|
|
344
|
+
index=beacon.BeaconSetting.SETTING_BOF_ALLOCATOR,
|
|
345
|
+
type=beacon.SettingsType.TYPE_SHORT,
|
|
346
|
+
length=0x2,
|
|
347
|
+
value=allocator_enum.dumps(),
|
|
348
|
+
).dumps()
|
|
349
|
+
bconfig = beacon.BeaconConfig(data)
|
|
350
|
+
profile = c2profile.C2Profile.from_beacon_config(bconfig)
|
|
351
|
+
assert profile.properties["process-inject.bof_allocator"] == [bof_allocator]
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
@pytest.mark.parametrize(
|
|
355
|
+
("bof_reuse_memory",),
|
|
356
|
+
[
|
|
357
|
+
(True,),
|
|
358
|
+
(False,),
|
|
359
|
+
],
|
|
360
|
+
)
|
|
361
|
+
def test_c2profile_bof_reuse_memory(bof_reuse_memory):
|
|
362
|
+
data = beacon.Setting(
|
|
363
|
+
index=beacon.BeaconSetting.SETTING_PROCINJ_BOF_REUSE_MEM,
|
|
364
|
+
type=beacon.SettingsType.TYPE_SHORT,
|
|
365
|
+
length=0x2,
|
|
366
|
+
value=beacon.cs_struct.uint16(bof_reuse_memory).dumps(),
|
|
367
|
+
).dumps()
|
|
368
|
+
bconfig = beacon.BeaconConfig(data)
|
|
369
|
+
profile = c2profile.C2Profile.from_beacon_config(bconfig)
|
|
370
|
+
if bof_reuse_memory:
|
|
371
|
+
assert profile.properties["process-inject.bof_reuse_memory"] == ["true"]
|
|
372
|
+
else:
|
|
373
|
+
assert "project.inject.bof_reuse_memory" not in profile.properties
|
|
374
|
+
|
|
375
|
+
|
|
376
|
+
def test_c2profile_beacon_gate():
|
|
377
|
+
# beacon gate with all options
|
|
378
|
+
data = beacon.Setting(
|
|
379
|
+
index=beacon.BeaconSetting.SETTING_BEACON_GATE,
|
|
380
|
+
type=beacon.SettingsType.TYPE_PTR,
|
|
381
|
+
length=0x40,
|
|
382
|
+
value=b"\x01" * 0x40,
|
|
383
|
+
).dumps()
|
|
384
|
+
bconfig = beacon.BeaconConfig(data)
|
|
385
|
+
profile = c2profile.C2Profile.from_beacon_config(bconfig)
|
|
386
|
+
assert profile.properties["stage.beacon_gate"] == ["All"]
|
|
387
|
+
|
|
388
|
+
# empty beacon gate should not result into any profile setting
|
|
389
|
+
data = beacon.Setting(
|
|
390
|
+
index=beacon.BeaconSetting.SETTING_BEACON_GATE,
|
|
391
|
+
type=beacon.SettingsType.TYPE_PTR,
|
|
392
|
+
length=0x40,
|
|
393
|
+
value=b"\x00" * 0x40,
|
|
394
|
+
).dumps()
|
|
395
|
+
bconfig = beacon.BeaconConfig(data)
|
|
396
|
+
profile = c2profile.C2Profile.from_beacon_config(bconfig)
|
|
397
|
+
assert "stage.beacon_gate" not in profile.properties
|
{dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/.github/workflows/dissect-ci.yml
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
|
{dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/dissect/cobaltstrike/__init__.py
RENAMED
|
File without changes
|
{dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/dissect/cobaltstrike/artifact.py
RENAMED
|
File without changes
|
{dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/dissect/cobaltstrike/c2.py
RENAMED
|
File without changes
|
{dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/dissect/cobaltstrike/c_c2.py
RENAMED
|
File without changes
|
{dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/dissect/cobaltstrike/client.py
RENAMED
|
File without changes
|
{dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/dissect/cobaltstrike/pcap.py
RENAMED
|
File without changes
|
{dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/dissect/cobaltstrike/pe.py
RENAMED
|
File without changes
|
{dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/dissect/cobaltstrike/utils.py
RENAMED
|
File without changes
|
{dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/dissect/cobaltstrike/version.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/docs/c2profile-grammar.rst
RENAMED
|
File without changes
|
{dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/docs/codespell-ignore-words.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/docs/images/beacon-client.png
RENAMED
|
File without changes
|
|
File without changes
|
{dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/docs/images/teamserver_ls.png
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/docs/scripts/example_client.rst
RENAMED
|
File without changes
|
|
File without changes
|
{dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/docs/structures/c2_def.rst
RENAMED
|
File without changes
|
{dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/docs/structures/cs_def.rst
RENAMED
|
File without changes
|
{dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/docs/structures/index.rst
RENAMED
|
File without changes
|
{dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/docs/structures/pe_def.rst
RENAMED
|
File without changes
|
{dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/docs/tools/beacon-artifact.rst
RENAMED
|
File without changes
|
{dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/docs/tools/beacon-client.rst
RENAMED
|
File without changes
|
{dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/docs/tools/beacon-dump.rst
RENAMED
|
File without changes
|
{dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/docs/tools/beacon-pcap.rst
RENAMED
|
File without changes
|
{dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/docs/tools/beacon-xordecode.rst
RENAMED
|
File without changes
|
{dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/docs/tools/c2profile-dump.rst
RENAMED
|
File without changes
|
|
File without changes
|
{dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/docs/tutorials/index.rst
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/scripts/checksum8-accesslogs.py
RENAMED
|
File without changes
|
{dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/scripts/dump_beacon_keys.py
RENAMED
|
File without changes
|
{dissect_cobaltstrike-1.2.1.dev4 → dissect_cobaltstrike-1.2.1.dev6}/scripts/example_client.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
|