Examples

Some examples showing how to use the dissect.cobaltstrike Python API.

Beacon Configuration

The main class for dealing with Cobalt Strike Beacon configuration is BeaconConfig. It’s recommended to instantiate the class by using one of the following constructors:

These from_ constructors will handle XorEncoded beacons by default and tries the default XOR keys used for obfuscating the beacon configuration. It raises ValueError if no beacon config was found.

For example to load the configuration of a Beacon payload on disk and access it’s settings:

In [1]: from dissect.cobaltstrike.beacon import BeaconConfig

In [2]: bconfig = BeaconConfig.from_path("beacon_92.bin")

In [3]: bconfig
Out[3]: <BeaconConfig ['londonteea.com']>

In [4]: bconfig.version
Out[4]: <BeaconVersion 'Cobalt Strike 4.2 (Nov 06, 2020)', tuple=(4, 2), date=2020-11-06>

In [5]: hex(bconfig.watermark)
Out[5]: '0x5109bf6d'

In [6]: bconfig.settings["SETTING_C2_REQUEST"]
Out[6]: 
[('_HEADER', b'Connection: close'),
 ('_HEADER', b'Accept-Language: en-US'),
 ('BUILD', 'metadata'),
 ('MASK', True),
 ('BASE64', True),
 ('PREPEND', b'wordpress_ed1f617bbd6c004cc09e046f3c1b7148='),
 ('HEADER', b'Cookie')]

If the beacon uses a non standard XOR key it will not find the beacon configuration and will raise ValueError:

In [7]: %xmode Minimal
Exception reporting mode: Minimal

In [8]: bconfig = BeaconConfig.from_path("beacon_xor.bin")
ValueError: No valid Beacon configuration found

Specify all_xor_keys=True to automatically try all single-byte XOR keys when the default keys fail:

In [9]: bconfig = BeaconConfig.from_path("beacon_xor.bin", all_xor_keys=True)

In [10]: bconfig
Out[10]: <BeaconConfig ['group.ccb.com.dsa.dnsv1.com']>

In [11]: bconfig.xorkey.hex()
Out[11]: 'cc'

In [12]: bconfig.version
Out[12]: <BeaconVersion 'Cobalt Strike 4.4 (Aug 04, 2021)', tuple=(4, 4), date=2021-08-04>

Or if you want to speed things up and you know a set of candidate XOR keys, just specify them using xor_keys to override the DEFAULT_XOR_KEYS:

In [13]: BeaconConfig.from_path("beacon_xor.bin", xor_keys=[b"\xcc"])
Out[13]: <BeaconConfig ['group.ccb.com.dsa.dnsv1.com']>

In [14]: _.xorkey.hex()
Out[14]: 'cc'

If you have extracted a Beacon configuration block manually, for example via x64dbg, you can pass it directly to BeaconConfig(). However, this only works with configuration bytes that is not obfuscated.

If the configuration block is obfuscated with a single-byte XOR key, use the BeaconConfig.from_bytes() constructor:

In [15]: data = '000000000000002e2f2e2f2e2c2e262e2c2e2f2e2c2f952e2d2e2c2e2a2e2ec44e2e2a2e2c2e2a2e3b7b762e2b2e2f2e2c2e302e292e2d2f2e1eafb11e23282704a866a8d9232f2f2f2b2e2dafa32e1eafa72cafaf2e889020f71e85a0e5a8d4e34a3795cda19b92a96ab5def70f62f93df6dc9630a2792be4a072feb87d581c02b171e1f5f869e40ea22cc29f1e77137f46199f49b70467f5f8d0901a7a321e92b6a3e5796ccd898a6b67f99d1861c6a0bf65e28e322f5b48a33edaed42ba921dcd6637560a4f309a8d1a313eeb9e0eae9e05e14cd52c2d2f2e2f2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e262e2d2f2e5d4740475a5b4a4b004d41430201594b4c014d464f5a5c005e415c5a4f422e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e202e2d2e3e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e332e2d2e6e0b5947404a475c0b725d575d594159181a724a424246415d5a004b564b2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e302e2d2e6e0b5947404a475c0b725d575d404f5a47584b724a424246415d5a004b564b2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e312e2f2e2c2e2e2e342e2d2e3e696b7a2e2e2e2e2e2e2e2e2e2e2e2e2e2e352e2d2e3e7e617d7a2e2e2e2e2e2e2e2e2e2e2e2e2e322e2c2e2a2e2e2e2e2e0b2e2c2e2a7f2791432e082e2f2e2c2e2e2e092e2f2e2c2e2e2e272e2d2f2e6341544742424f011b001e0e067947404a41595d0e607a0e18001c070e6f5e5e424b794b4c65475a011b1d19001d180e0665667a6362020e4247454b0e694b4d4541070e6d465c41434b01171e001e001a1a1d1e00161b0e7d4f484f5c47011b1d19001d182e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e242e2d2e6e01594b4c014241494140004f5d5e562e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e252e2d2f2e2e2e2e2a2e2e2e2d2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e222e2d2c2e2e2e2e242e2e2e396d41405a4b405a037a575e4b140e5a4b565a01465a43422e2e2e242e2e2e396d4f4d464b036d41405a5c4142140e4041034d4f4d464b2e2e2e292e2e2e2e2e2e2e262e2e2e222e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e232e2d2c2e2e2e2e242e2e2e0f6d41405a4b405a037a575e4b140e435b425a475e4f5c5a0148415c43034a4f5a4f2e2e2e242e2e2e396d4f4d464b036d41405a5c4142140e4041034d4f4d464b2e2e2e292e2e2e2e2e2e2e252e2e2e222e2e2e292e2e2e2f2e2e2e232e2e2e2a2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e182e2d2eae2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e1c2e2f2e2c2e2e2e0d2e2f2e2c2e2c2e142e2d2eae2e2bbe2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e172e2d2eae2e2b5e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e192e2f2e2c2e2e2e062e2c2e2a2e2e2e2e2e072e2c2e2a2e2e2e2e2e052e2f2e2c2e2a2e022e2f2e2c2e0e2e032e2c2e2a2e2e6a722e002e2d2f2e2e2e2e2cbebe2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e012e2d2f2e2e2e2e2cbebe2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e1b2e2d2e3e22ccdb7a6aca571b389b81c74990bc7b2e1d2e2d2eae282e082e2e2e28405a4a42422e2e2e2e3d7c5a427b5d4b5c7a465c4b4f4a7d5a4f5c5a2e2f26292e7f2e2e2e23454b5c404b421d1c004a42422e2e2e2e2362414f4a62474c5c4f5c576f2e2a2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e2e1a2e2f2e2c2e2f2e2ea9b00e0f83d6dcebcc255a8257385b0cfcd0b3e396662dbc1dfaa4760f06e45619877b1b8417ed572d4fb9dc3693800c78d5ad9efb6b49101afb1fcce586e1b08bb4bb746dd5114c2707c83b0b3cb571ba5d49ce24d84dc8c719c536d0491107dc284ba6ca8560274d4838c2fb866ef2a1875dead0f249885c0a7b1393dfc3630fb471753e907eef2ffeeb03bba60268453f444d83013fde9e95332e52fb82b1b59ecb31f2b83e90f6738ce1add1def1dddfee14c80445b2e2c5f9318d0efa7082519aa05fe2c3454ccb4950de6a924238bbeb9fe39721719f7ac8092087be5c2de004d6a39acc8135e86a13cac51e3448268a817742493aa3120059a109ef5e1812129f2c6d139a2b8859e8b40bc40eb643583bf993af9c7abaaa37450c426712337b1d18160be90b101698d1fd7b9928f593314b85117713222985f789362cdff09ea88cb167b72d1913961942e0d31ee2c8d256b4e4356d16fd5ea9f6bd42bb2ccb127db061f2003b5fc637873090180c951679a1bf8c8beae3203a6cc3c5638b8c5942bff2f7981b86798023f71d4e9acdd8b39d689c489445e8b9279a078fb6de1b8c527b339ef447039b1903b8b95ef5769502b9d7e0fd81d839c8903ad2244e4690e6839d9869301e0c2c0be9c725d8fb5d6cb96ac9cee3873ec5268c1eeed334317c01'

In [16]: BeaconConfig.from_bytes(bytes.fromhex(data))
Out[16]: <BeaconConfig ['sinitude.com']>

In [17]: config = _

In [18]: config.protocol
Out[18]: 'https'

In [19]: config.domain_uri_pairs
Out[19]: [('sinitude.com', '/web/chatr.portal')]

In [20]: config.settings
Out[20]: 
mappingproxy({'SETTING_PROTOCOL': 8,
              'SETTING_PORT': 443,
              'SETTING_SLEEPTIME': 60000,
              'SETTING_MAXGET': 1398104,
              'SETTING_JITTER': 30,
              'SETTING_PUBKEY': 'a83298f790d9a47e425ce5d67a148ba87498e7ed5eb4b4f4f1e0c5e177b274a2',
              'SETTING_DOMAINS': 'sinitude.com,/web/chatr.portal',
              'SETTING_SPAWNTO': '00000000000000000000000000000000',
              'SETTING_SPAWNTO_X86': '%windir%\\syswow64\\dllhost.exe',
              'SETTING_SPAWNTO_X64': '%windir%\\sysnative\\dllhost.exe',
              'SETTING_CRYPTO_SCHEME': 0,
              'SETTING_C2_VERB_GET': 'GET',
              'SETTING_C2_VERB_POST': 'POST',
              'SETTING_C2_CHUNK_POST': 0,
              'SETTING_WATERMARK': 1359593325,
              'SETTING_CLEANUP': 0,
              'SETTING_CFG_CAUTION': 0,
              'SETTING_USERAGENT': 'Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.85 Safari/537.36',
              'SETTING_SUBMITURI': '/web/logon.aspx',
              'SETTING_C2_RECOVER': [('print', True), ('base64', True)],
              'SETTING_C2_REQUEST': [('_HEADER', b'Content-Type: text/html'),
               ('_HEADER', b'Cache-Control: no-cache'),
               ('BUILD', 'metadata'),
               ('NETBIOS', True),
               ('URI_APPEND', True)],
              'SETTING_C2_POSTREQ': [('_HEADER',
                b'Content-Type: multipart/form-data'),
               ('_HEADER', b'Cache-Control: no-cache'),
               ('BUILD', 'id'),
               ('NETBIOSU', True),
               ('URI_APPEND', True),
               ('BUILD', 'output'),
               ('BASE64URL', True),
               ('PRINT', True)],
              'SETTING_HOST_HEADER': '',
              'SETTING_HTTP_NO_COOKIES': 0,
              'SETTING_PROXY_BEHAVIOR': 2,
              'SETTING_TCP_FRAME_HEADER': b'\x90',
              'SETTING_SMB_FRAME_HEADER': b'p',
              'SETTING_EXIT_FUNK': 0,
              'SETTING_KILLDATE': 0,
              'SETTING_GARGLE_NOOK': 0,
              'SETTING_PROCINJ_PERMS_I': 4,
              'SETTING_PROCINJ_PERMS': 32,
              'SETTING_PROCINJ_MINALLOC': 17500,
              'SETTING_PROCINJ_TRANSFORM_X86': [('append', b'\x90\x90'),
               ('prepend', b'')],
              'SETTING_PROCINJ_TRANSFORM_X64': [('append', b'\x90\x90'),
               ('prepend', b'')],
              'SETTING_PROCINJ_STUB': '0ce2f55444e4793516b5afe967be9255',
              'SETTING_PROCINJ_EXECUTE': ['CreateThread "ntdll!RtlUserThreadStart+0x26"',
               'CreateThread',
               'NtQueueApcThread_s',
               'CreateRemoteThread "kernel32.dll!LoadLibraryA+0x51"',
               'RtlCreateUserThread'],
              'SETTING_PROCINJ_ALLOCATOR': 1})

In [21]: config.version
Out[21]: <BeaconVersion 'Cobalt Strike 4.1 (Jun 25, 2020)', tuple=(4, 1), date=2020-06-25>

Memory dumps

While you can use BeaconConfig to load Beacon payloads directly, it can also load a memory dump (or any other file) and check for beacon configurations. However, the default constructors will only return the first found beacon configuration.

If you have a memory dump that could contain multiple beacons, use iter_beacon_config_blocks() to iterate over all found beacon configuration blocks and instantiate BeaconConfig manually:

import sys
from dissect.cobaltstrike import beacon

with open(sys.argv[1], "rb") as f:
    for config_block, extra_data in beacon.iter_beacon_config_blocks(f):
        try:
            bconfig = beacon.BeaconConfig(config_block)
            if not len(bconfig.domains):
                continue
        except ValueError:
            continue
        print(bconfig, bconfig.domain_uri_pairs)

This will try to find all beacon config_block bytes in the file and try to instantiate a BeaconConfig from it. For verification it will check if the beacon has a domain to ensure that config_block was not just some random data.

PE Artifacts

Use the dissect.cobaltstrike.pe module to extract PE artifacts. If the payload is XorEncoded you need to load it using XorEncodedFile first.

In [22]: from dissect.cobaltstrike import xordecode

In [23]: from dissect.cobaltstrike import pe

In [24]: import time

In [25]: xf = xordecode.XorEncodedFile.from_path("beacon_93.bin")

In [26]: pe.find_architecture(xf)
Out[26]: 'x64'

In [27]: pe.find_compile_stamps(xf)
Out[27]: (1628256615, 1614696183)

In [28]: compile_stamp, export_stamp = _

In [29]: time.ctime(compile_stamp)
Out[29]: 'Fri Aug  6 13:30:15 2021'

In [30]: pe.find_magic_mz(xf)
Out[30]: b'MZAR'

In [31]: pe.find_magic_pe(xf)
Out[31]: b'PE'

In [32]: pe.find_stage_prepend_append(xf)
Out[32]: (b'\x90\x90\x90\x90\x90\x90\x90\x90', None)

C2 Profiles

Loading Cobalt Strike Malleable C2 Profiles is also supported, to load a profile from disk:

In [33]: from dissect.cobaltstrike.c2profile import C2Profile

In [34]: profile = C2Profile.from_path("amazon.profile")

To access the C2Profile configuration settings use the C2Profile.as_dict method or the C2Profile.properties attribute. For example:

In [35]: profile.as_dict()
Out[35]: 
{'sleeptime': ['5000'],
 'jitter': ['0'],
 'maxdns': ['255'],
 'useragent': ['Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko'],
 'http-get.uri': ['/s/ref=nb_sb_noss_1/167-3294888-0262949/field-keywords=books'],
 'http-get.client.header': [('Accept', '*/*'), ('Host', 'www.amazon.com')],
 'http-get.client.metadata': ['base64',
  ('prepend', b'session-token='),
  ('prepend', b'skin=noskin;'),
  ('append', b'csm-hit=s-24KU11BB82RZSYGJ3BDK|1419899012996'),
  ('header', b'Cookie')],
 'http-get.server.header': [('Server', 'Server'),
  ('x-amz-id-1', 'THKUYEZKCKPGY5T42PZT'),
  ('x-amz-id-2',
   'a21yZ2xrNDNtdGRsa212bGV3YW85amZuZW9ydG5rZmRuZ2tmZGl4aHRvNDVpbgo='),
  ('X-Frame-Options', 'SAMEORIGIN'),
  ('Content-Encoding', 'gzip')],
 'http-get.server.output': ['print'],
 'http-post.uri': ['/N4215/adj/amzn.us.sr.aps'],
 'http-post.client.header': [('Accept', '*/*'),
  ('Content-Type', 'text/xml'),
  ('X-Requested-With', 'XMLHttpRequest'),
  ('Host', 'www.amazon.com')],
 'http-post.client.parameter': [('sz', '160x600'),
  ('oe', 'oe=ISO-8859-1;'),
  ('s', '3717'),
  ('dc_ref', 'http%3A%2F%2Fwww.amazon.com')],
 'http-post.client.id': [('parameter', b'sn')],
 'http-post.client.output': ['base64', 'print'],
 'http-post.server.header': [('Server', 'Server'),
  ('x-amz-id-1', 'THK9YEZJCKPGY5T42OZT'),
  ('x-amz-id-2',
   'a21JZ1xrNDNtdGRsa219bGV3YW85amZuZW9zdG5rZmRuZ2tmZGl4aHRvNDVpbgo='),
  ('X-Frame-Options', 'SAMEORIGIN'),
  ('x-ua-compatible', 'IE=edge')],
 'http-post.server.output': ['print']}

In [36]: profile.properties["useragent"]
Out[36]: ['Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko']

In [37]: profile.properties["http-get.uri"]
Out[37]: ['/s/ref=nb_sb_noss_1/167-3294888-0262949/field-keywords=books']

In [38]: profile.properties["http-post.client.parameter"]
Out[38]: 
[('sz', '160x600'),
 ('oe', 'oe=ISO-8859-1;'),
 ('s', '3717'),
 ('dc_ref', 'http%3A%2F%2Fwww.amazon.com')]

Note

Currently all the values in the dictionary are lists, this might change in the future.

BeaconConfig to C2 Profile

Use C2Profile.from_beacon_config to load settings from a BeaconConfig. This allows for dumping the Beacon Configuration to a more readable (and reusable) C2 Profile.

In [39]: config
Out[39]: <BeaconConfig ['sinitude.com']>

In [40]: profile = C2Profile.from_beacon_config(config)

In [41]: print(profile)
set sleeptime "60000";
set jitter "30";
set spawnto_x86 "%windir%\syswow64\dllhost.exe";
set spawnto_x64 "%windir%\sysnative\dllhost.exe";
set useragent "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.85 Safari/537.36";
set tcp_frame_header "\x90";
set smb_frame_header "p";

http-get {
    set uri "/web/chatr.portal";
    set verb "GET";

    server {

        output {
            base64;
            print;
        }
    }

    client {
        header "Content-Type" "text/html";
        header "Cache-Control" "no-cache";

        metadata {
            netbios;
            uri-append;
        }
    }
}

http-post {
    set verb "POST";
    set uri "/web/logon.aspx";

    client {
        header "Content-Type" "multipart/form-data";
        header "Cache-Control" "no-cache";

        id {
            netbiosu;
            uri-append;
        }

        output {
            base64url;
            print;
        }
    }
}

stage {
    set cleanup "0";
}

process-inject {
    set startrwx "false";
    set userwx "false";
    set min_alloc "17500";

    transform-x86 {
        append "\x90\x90";
    }

    transform-x64 {
        append "\x90\x90";
    }

    execute {
        CreateThread "ntdll!RtlUserThreadStart+0x26";
        CreateThread;
        CreateRemoteThread "kernel32.dll!LoadLibraryA+0x51";
        RtlCreateUserThread;
    }
    set allocator "NtMapViewOfSection";
}

Stager URIs and checksum8

checksum8 URIs are used for payload staging and used in Cobalt Strike shellcode stagers for retrieving the final Beacon payload from the Team Server.

Note

Metasploit also uses checksum8, it exists in Cobalt Strike to be compatible with Metasploit.

The following checksum8 values are used by Cobalt Strike:

checksum8

architecture

92

beacon x86

93

beacon x64

To calculate the checksum8 of an URI:

In [42]: from dissect.cobaltstrike import utils

In [43]: utils.checksum8("/rLEZ")
Out[43]: 93

In [44]: utils.is_stager_x64("/rLEZ")
Out[44]: True

In [45]: utils.is_stager_x86("/yearbook")
Out[45]: True

To easily generate valid Cobalt Strike stager URIs, use utils.random_stager_uri:

In [46]: from dissect.cobaltstrike import utils

In [47]: utils.random_stager_uri(x64=True)
Out[47]: '/J6sj'

In [48]: utils.random_stager_uri(length=30)
Out[48]: '/Wt1tX8Yk2ZryVJUl1Ovpw2uIMaWxC3'

Or, a fun script to check a dictionary or word list for valid stager x86 words:

import sys
from dissect.cobaltstrike import utils

for line in sys.stdin:
    line = line.strip().lower()
    if utils.is_stager_x86(line):
        print(line)
$ cat /usr/share/dict/words | python is_stager_x86.py | head -n 10
abortive
abshenry
accommodative
acosmism
acquirer
acroaesthesia
adance
adiposis
adoptive
adulator