dissect.cobaltstrike.beacon =========================== .. py:module:: dissect.cobaltstrike.beacon .. autoapi-nested-parse:: This module is responsible for extracting and parsing configuration from Cobalt Strike beacon payloads. Attributes ---------- .. autoapisummary:: dissect.cobaltstrike.beacon.logger dissect.cobaltstrike.beacon.CS_DEF dissect.cobaltstrike.beacon.cs_struct dissect.cobaltstrike.beacon.TransformStep dissect.cobaltstrike.beacon.BeaconSetting dissect.cobaltstrike.beacon.DeprecatedBeaconSetting dissect.cobaltstrike.beacon.SettingsType dissect.cobaltstrike.beacon.Setting dissect.cobaltstrike.beacon.BeaconProtocol dissect.cobaltstrike.beacon.CryptoScheme dissect.cobaltstrike.beacon.ProxyServer dissect.cobaltstrike.beacon.InjectAllocator dissect.cobaltstrike.beacon.InjectExecutor dissect.cobaltstrike.beacon.BofAllocator dissect.cobaltstrike.beacon.BeaconGateOptions dissect.cobaltstrike.beacon.DEFAULT_XOR_KEYS dissect.cobaltstrike.beacon.SETTING_TO_PRETTYFUNC Classes ------- .. autoapisummary:: dissect.cobaltstrike.beacon.BeaconConfig Functions --------- .. autoapisummary:: dissect.cobaltstrike.beacon.find_beacon_config_bytes dissect.cobaltstrike.beacon.iter_beacon_config_blocks dissect.cobaltstrike.beacon.make_byte_list dissect.cobaltstrike.beacon.iter_settings dissect.cobaltstrike.beacon.parse_recover_binary dissect.cobaltstrike.beacon.parse_transform_binary dissect.cobaltstrike.beacon.parse_execute_list dissect.cobaltstrike.beacon.parse_process_injection_transform_steps dissect.cobaltstrike.beacon.parse_gargle dissect.cobaltstrike.beacon.parse_pivot_frame dissect.cobaltstrike.beacon.parse_beacon_gate dissect.cobaltstrike.beacon.beacon_gate_options_string dissect.cobaltstrike.beacon.sha256sum_pubkey dissect.cobaltstrike.beacon.null_terminated_bytes dissect.cobaltstrike.beacon.null_terminated_str dissect.cobaltstrike.beacon.build_parser dissect.cobaltstrike.beacon.main Module Contents --------------- .. py:data:: logger .. py:data:: CS_DEF :value: Multiline-String .. raw:: html
Show Value .. code-block:: python """ enum BeaconSetting: uint16 { SETTING_PROTOCOL = 1, SETTING_PORT = 2, SETTING_SLEEPTIME = 3, SETTING_MAXGET = 4, SETTING_JITTER = 5, SETTING_MAXDNS = 6, SETTING_PUBKEY = 7, SETTING_DOMAINS = 8, SETTING_USERAGENT = 9, SETTING_SUBMITURI = 10, SETTING_C2_RECOVER = 11, SETTING_C2_REQUEST = 12, SETTING_C2_POSTREQ = 13, SETTING_SPAWNTO = 14, // releasenotes.txt // CobaltStrike version >= 3.4 (27 Jul, 2016) SETTING_PIPENAME = 15, SETTING_KILLDATE_YEAR = 16, // Deprecated since Cobalt Strike 4.7 SETTING_BOF_ALLOCATOR = 16, // Introduced in Cobalt Strike 4.7 SETTING_KILLDATE_MONTH = 17, // Deprecated since Cobalt Strike 4.8 SETTING_SYSCALL_METHOD = 17, // Introduced in Cobalt Strike 4.8 SETTING_KILLDATE_DAY = 18, SETTING_DNS_IDLE = 19, SETTING_DNS_SLEEP = 20, // CobaltStrike version >= 3.5 (22 Sept, 2016) SETTING_SSH_HOST = 21, SETTING_SSH_PORT = 22, SETTING_SSH_USERNAME = 23, SETTING_SSH_PASSWORD = 24, SETTING_SSH_KEY = 25, SETTING_C2_VERB_GET = 26, SETTING_C2_VERB_POST = 27, SETTING_C2_CHUNK_POST = 28, SETTING_SPAWNTO_X86 = 29, SETTING_SPAWNTO_X64 = 30, // CobaltStrike version >= 3.6 (8 Dec, 2016) SETTING_CRYPTO_SCHEME = 31, // CobaltStrike version >= 3.7 (15 Mar, 2016) SETTING_PROXY_CONFIG = 32, SETTING_PROXY_USER = 33, SETTING_PROXY_PASSWORD = 34, SETTING_PROXY_BEHAVIOR = 35, // CobaltStrike version >= 3.8 (23 May 2017) // DEPRECATED_SETTING_INJECT_OPTIONS = 36, // Renamed from DEPRECATED_SETTING_INJECT_OPTIONS in CobaltStrike 4.5 SETTING_WATERMARKHASH = 36, // CobaltStrike version >= 3.9 (Sept 26, 2017) SETTING_WATERMARK = 37, // CobaltStrike version >= 3.11 (April 9, 2018) SETTING_CLEANUP = 38, // CobaltStrike version >= 3.11 (May 24, 2018) SETTING_CFG_CAUTION = 39, // CobaltStrike version >= 3.12 (Sept 6, 2018) SETTING_KILLDATE = 40, SETTING_GARGLE_NOOK = 41, // https://www.youtube.com/watch?v=nLTgWdXrx3U SETTING_GARGLE_SECTIONS = 42, SETTING_PROCINJ_PERMS_I = 43, SETTING_PROCINJ_PERMS = 44, SETTING_PROCINJ_MINALLOC = 45, SETTING_PROCINJ_TRANSFORM_X86 = 46, SETTING_PROCINJ_TRANSFORM_X64 = 47, SETTING_PROCINJ_ALLOWED = 48, // Deprecated since Cobalt Strike 4.7 SETTING_PROCINJ_BOF_REUSE_MEM = 48, // Introduced in Cobalt Strike 4.7 // CobaltStrike version >= 3.13 (Jan 2, 2019) SETTING_BINDHOST = 49, // CobaltStrike version >= 3.14 (May 4, 2019) SETTING_HTTP_NO_COOKIES = 50, SETTING_PROCINJ_EXECUTE = 51, SETTING_PROCINJ_ALLOCATOR = 52, SETTING_PROCINJ_STUB = 53, // .self = MD5(cobaltstrike.jar) // CobaltStrike version >= 4.0 (Dec 5, 2019) SETTING_HOST_HEADER = 54, SETTING_EXIT_FUNK = 55, // CobaltStrike version >= 4.1 (June 25, 2020) SETTING_SSH_BANNER = 56, SETTING_SMB_FRAME_HEADER = 57, SETTING_TCP_FRAME_HEADER = 58, // CobaltStrike version >= 4.2 (Nov 6, 2020) SETTING_HEADERS_REMOVE = 59, // CobaltStrike version >= 4.3 (Mar 3, 2021) SETTING_DNS_BEACON_BEACON = 60, SETTING_DNS_BEACON_GET_A = 61, SETTING_DNS_BEACON_GET_AAAA = 62, SETTING_DNS_BEACON_GET_TXT = 63, SETTING_DNS_BEACON_PUT_METADATA = 64, SETTING_DNS_BEACON_PUT_OUTPUT = 65, SETTING_DNSRESOLVER = 66, SETTING_DOMAIN_STRATEGY = 67, SETTING_DOMAIN_STRATEGY_SECONDS = 68, SETTING_DOMAIN_STRATEGY_FAIL_X = 69, SETTING_DOMAIN_STRATEGY_FAIL_SECONDS = 70, // CobaltStrike version >= 4.5 (Dec 14, 2021) SETTING_MAX_RETRY_STRATEGY_ATTEMPTS = 71, SETTING_MAX_RETRY_STRATEGY_INCREASE = 72, SETTING_MAX_RETRY_STRATEGY_DURATION = 73, // CobaltStrike version >= 4.7 (Aug 17, 2022) SETTING_MASKED_WATERMARK = 74, // CobaltStrike version >= 4.9 (Sep 19, 2023) SETTING_DATA_STORE_SIZE = 76, // CobaltStrike version >= 4.10 (Jul 16, 2024) SETTING_HTTP_DATA_REQUIRED = 77, SETTING_BEACON_GATE = 78, }; enum DeprecatedBeaconSetting: uint16 { SETTING_KILLDATE_YEAR = 16, SETTING_INJECT_OPTIONS = 36, }; enum TransformStep: uint32 { APPEND = 1, PREPEND = 2, BASE64 = 3, PRINT = 4, PARAMETER = 5, HEADER = 6, BUILD = 7, NETBIOS = 8, _PARAMETER = 9, _HEADER = 10, NETBIOSU = 11, URI_APPEND = 12, BASE64URL = 13, STRREP = 14, MASK = 15, // CobaltStrike version >= 4.0 (Dec 5, 2019) _HOSTHEADER = 16, }; enum SettingsType: uint16 { TYPE_NONE = 0, TYPE_SHORT = 1, TYPE_INT = 2, TYPE_PTR = 3, }; struct Setting { BeaconSetting index; // uint16 SettingsType type; // uint16 uint16 length; // uint16 char value[length]; }; flag BeaconProtocol { http = 0, dns = 1, smb = 2, tcp = 4, https = 8, bind = 16 }; flag ProxyServer { MANUAL = 0, DIRECT = 1, PRECONFIG = 2, MANUAL_CREDS = 4 }; enum CryptoScheme: uint16 { CRYPTO_LICENSED_PRODUCT = 0, CRYPTO_TRIAL_PRODUCT = 1 }; enum InjectAllocator: uint8 { VirtualAllocEx = 0, NtMapViewOfSection = 1, }; enum InjectExecutor: uint8 { CreateThread = 1, SetThreadContext = 2, CreateRemoteThread = 3, RtlCreateUserThread = 4, NtQueueApcThread = 5, CreateThread_ = 6, CreateRemoteThread_ = 7, NtQueueApcThread_s = 8 }; enum BofAllocator: uint16 { VirtualAlloc = 0, MapViewOfFile = 1, HeapAlloc = 2, }; // https://hstechdocs.helpsystems.com/manuals/cobaltstrike/current/userguide/content/topics/beacon-gate.htm struct BeaconGateOptions { uint8 InternetOpenA; // commms uint8 InternetConnectA; uint8 VirtualAlloc; // core uint8 VirtualAllocEx; uint8 VirtualProtect; uint8 VirtualProtectEx; uint8 VirtualFree; uint8 GetThreadContext; uint8 SetThreadContext; uint8 ResumeThread; uint8 CreateThread; uint8 CreateRemoteThread; uint8 OpenProcess; uint8 OpenThread; uint8 CloseHandle; uint8 CreateFileMappingA; uint8 MapViewOfFile; uint8 UnmapViewOfFile; uint8 VirtualQuery; uint8 DuplicateHandle; uint8 ReadProcessMemory; uint8 WriteProcessMemory; uint8 ExitThread; // cleanup }; """ .. raw:: html
.. py:data:: cs_struct .. py:data:: TransformStep .. py:data:: BeaconSetting .. py:data:: DeprecatedBeaconSetting .. py:data:: SettingsType .. py:data:: Setting .. py:data:: BeaconProtocol .. py:data:: CryptoScheme .. py:data:: ProxyServer .. py:data:: InjectAllocator .. py:data:: InjectExecutor .. py:data:: BofAllocator .. py:data:: BeaconGateOptions .. py:data:: DEFAULT_XOR_KEYS :type: List[bytes] :value: [b'i', b'.', b'\x00'] Default XOR keys used by Cobalt Strike for obfuscating Beacon config bytes .. py:function:: find_beacon_config_bytes(fh: BinaryIO, xorkey: bytes) -> Iterator[bytes] Find and yield (possible) Cobalt Strike configuration bytes from file `fh` using `xorkey` (eg: b"\x69"). This is done by scraping the file `fh` for XOR encoded configuration blocks. A beacon configuration block always (unless modified) starts with:: Setting(index=SETTING_PROTOCOL, type=TYPE_SHORT, length=0x2) # which translates to the following bytes b"\x00\x01\x00\x01\x00\x02\x00" These bytes are used in conjunction with the XOR key for finding the (potential) start of a configuration block. :param fh: file object :param xorkey: XOR key (as bytes) :Yields: Beacon configuration bytes (4096 bytes), in deobfuscated (un-XOR'd) form. .. py:function:: iter_beacon_config_blocks(fobj: BinaryIO, xor_keys=None, xordecode=True, all_xor_keys=False) -> Iterator[Tuple[bytes, dict]] Yield tuple with found Beacon `config_block_bytes` from file `fobj` and `extra_info` dict It always start seeking from the beginning of `fobj`. Side effects: file handle position due to seeking The `extra_info` dictionary holds some metadata such as if the `fobj` was xorencoded and which xorkey was used. :param xor_keys: list XOR keys (as bytes), defaults to: :attr:`DEFAULT_XOR_KEYS` if not specified. :param xordecode: If ``True`` it will also try to `XorDecode` the file object. :param all_xor_keys: Try ALL single-byte XOR keys if no beacon config is found using the default keys. :Yields: Tuple as ``(config_block_bytes, extra_info_dict)`` -- `extra_info` dict contains: ``{"xorkey": bytes, "xorencoded": bool}`` .. py:function:: make_byte_list(exclude: List[bytes] = None) -> List[bytes] Return all single-byte bytes as an ordered list, excluding `exclude` bytes. .. py:function:: iter_settings(fobj: Union[bytes, BinaryIO]) -> Iterator[Setting] Returns an iterator yielding :class:`Setting` objects by reading data from `fobj` The file position will be at the end of the Beacon config after parsing is done. This can be used to determine the exact size of the Beacon configuration block. Some edge cases are also handled: - User-Agent string that exceeds the Setting length. - Deprecated setting SETTING_INJECT_OPTIONS :param fobj: bytes or file-like object with Beacon configuration data :Yields: :class:`Setting` objects .. py:function:: parse_recover_binary(program: bytes) -> List[Tuple[str, Union[int, bool]]] Parse ``SETTING_C2_RECOVER`` (`.http-get.server.output`) data .. py:function:: parse_transform_binary(program: bytes, build: str = 'metadata') -> List[Tuple[str, Union[str, bytes, bool]]] Parse ``SETTING_C2_{REQUEST,POSTREQ}`` (`http-{get,post}.client`) data .. py:function:: parse_execute_list(data: bytes) -> List[str] Parse ``SETTING_PROCINJ_EXECUTE`` (`.process-inject.execute`) data .. py:function:: parse_process_injection_transform_steps(data: bytes) -> list Parse ``SETTING_PROCINJ_TRANSFORM_X{86,64}`` (`process-inject.transform-x{86,64}`) data .. py:function:: parse_gargle(data: bytes) -> list Parse ``SETTING_GARGLE_SECTIONS`` (`.stage.{sleep_mask,obfuscate,userwx}`) data .. py:function:: parse_pivot_frame(data: bytes) -> bytes Parse ``SETTING_{TCP,SMB}_FRAME_HEADER`` (`.{tcp,smb}_frame_header`) data .. py:function:: parse_beacon_gate(data: bytes) -> BeaconGateOptions Parse ``SETTING_BEACON_GATE`` (`.stage.beacon_gate`) data .. py:function:: beacon_gate_options_string(bgo: BeaconGateOptions) -> list[str] Return the enabled BeaconGate WinAPI's as a list of strings .. py:function:: sha256sum_pubkey(der_data: bytes) -> str Return the SHA-256 digest of `der_data` .. py:function:: null_terminated_bytes(data: bytes) -> bytes Return null terminated `data` as bytes. >>> null_terminated_bytes(b"Hello World\x00\x00Foobar\x00\x00") b'Hello World' >>> null_terminated_bytes(b"foo\xffbar\x00\x00\x00baz\x00") b'foo\xffbar' .. py:function:: null_terminated_str(data: bytes) -> str Return null terminated `data` as string. Non ascii characters are ignored. >>> null_terminated_str(b"Hello World\x00\x00foo bar\x00\x00") 'Hello World' >>> null_terminated_str(b"Goodbye\xffPlanet\x00\x00") 'GoodbyePlanet' .. py:data:: SETTING_TO_PRETTYFUNC :type: Dict[BeaconSetting, Callable] BeaconSetting enum to pretty function mapping .. py:class:: BeaconConfig(config_block: bytes) A :class:`BeaconConfig` object represents a single Beacon configuration It holds configuration data, parsed settings and other metadata of a Cobalt Strike Beacon and provides useful methods and properties for accessing the Beacon settings. It does *not* contain the Beacon payload data itself. It can be directly instantiated using configuration data. Otherwise, use the following constructors: - :meth:`BeaconConfig.from_file` - :meth:`BeaconConfig.from_path` - :meth:`BeaconConfig.from_bytes` The **from_** constructors automatically tries to extract the configuration data (first candidate only) and also handles `xorencoded` payloads and `XOR` decoding of obfuscated configuration blocks that is common with Cobalt Strike. .. py:attribute:: config_block :type: bytes Raw beacon configuration block bytes .. py:attribute:: settings_tuple Tuple containing the `Setting` objects parsed from `config_block` .. py:attribute:: xorkey :type: Optional[bytes] :value: None XOR key that was used to obfuscate the configuration block, ``None`` if unknown. .. py:attribute:: xorencoded :type: bool :value: False ``True`` if the beacon was xorencoded, otherwise ``False`` .. py:attribute:: pe_export_stamp :type: Optional[int] :value: None PE export timestamp, ``None`` if unknown. .. py:attribute:: pe_compile_stamp :type: Optional[int] :value: None PE compile timestamp, ``None`` if unknown. .. py:attribute:: architecture :type: Optional[str] :value: None PE architecture, ``"x86"`` or ``"x64"`` and ``None`` if unknown. .. py:attribute:: guardrails :type: Optional[dissect.cobaltstrike.guardrails.GuardrailMetadata] :value: None Guardrails metadata, ``None`` if not available. .. py:attribute:: _settings :type: Optional[Mapping[str, Any]] :value: None .. py:attribute:: _settings_by_index :type: Optional[Mapping[int, Any]] :value: None .. py:attribute:: _raw_settings :type: Optional[Mapping[str, Any]] :value: None .. py:attribute:: _raw_settings_by_index :type: Optional[Mapping[int, Any]] :value: None .. py:method:: from_file(fobj: BinaryIO, xor_keys: List[bytes] = None, all_xor_keys: bool = False) -> BeaconConfig :classmethod: Create a :class:`BeaconConfig` from file object, or raises ValueError if no beacon config is found. :param fobj: file-like object :param xor_keys: override the default `XOR` keys (as bytes) when specified. Default ``None``. :param all_xor_keys: if ``True``, it will try ALL single-byte `XOR` keys if the defaults don't work :returns: :class:`BeaconConfig` :raises ValueError: If no valid beacon configuration was found .. py:method:: from_path(path: Union[str, os.PathLike], xor_keys: List[bytes] = None, all_xor_keys: bool = False) -> BeaconConfig :classmethod: Create a :class:`BeaconConfig` from path, or raises ValueError if no beacon config is found. :param path: path to file on disk :param xor_keys: override the default `XOR` keys (as bytes) when specified. Default ``None``. :param all_xor_keys: if ``True`` it will try ALL single-byte `XOR` keys if the defaults don't work :returns: :class:`BeaconConfig` :raises ValueError: If no valid beacon configuration was found .. py:method:: from_bytes(data: bytes, xor_keys: List[bytes] = None, all_xor_keys: bool = False) -> BeaconConfig :classmethod: Create a :class:`BeaconConfig` from bytes, or raises ValueError if no beacon config is found. :param data: configuration bytes :param xor_keys: override the default `XOR` keys when specified. Default ``None``. :param all_xor_keys: if ``True`` it will try ALL single-byte `XOR` keys if the defaults don't work :returns: :class:`BeaconConfig` :raises ValueError: If no valid beacon configuration was found .. py:method:: __repr__() -> str .. py:property:: setting_enums :type: list List of BeaconSetting `enum` values in the order of appearance within the Beacon configuration. Example value:: [1, 2, 3, 4, 5, 7, ..., 45, 46, 47, 53, 51, 52] .. py:property:: max_setting_enum :type: int The maximum BeaconSetting `enum` value present in the Beacon configuration. .. py:method:: settings_map(index_type='enum', pretty=False, parse=True) -> types.MappingProxyType Return a read-only settings mapping indexed by given `index_type`. :param index_type: index type of the dictionary, can be one of: - ``name``: indexed by `BeaconSetting` name (str) - ``const``: indexed by `BeaconSetting` constant (int) - ``enum``: indexed by `BeaconSetting` enum (enum object). :param pretty: if `True`, apply pretty functions on the values. :param parse: if `True`, the raw bytes of `TYPE_SHORT` and `TYPE_INT` values are converted to int. :returns: OrderedDict .. py:property:: raw_settings :type: Mapping[str, Any] Read-only Beacon settings mapping with raw values, indexed by `BeaconSetting` name. The raw bytes of `TYPE_SHORT` and `TYPE_INT` values are converted to int. Example value:: mappingproxy({ 'SETTING_PROTOCOL': 8, 'SETTING_PORT': 443, 'SETTING_SLEEPTIME': 60000, ... 'SETTING_C2_VERB_POST': b'POST\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', 'SETTING_PROCINJ_STUB': b'\x0c\xe2\xf5TD\xe4y5\x16\xb5\xaf\xe9g\xbe\x92U', }) .. py:property:: raw_settings_by_index :type: Mapping[int, Any] Read-only Beacon settings mapping with raw values, indexed by `BeaconSetting` constant. The raw bytes of `TYPE_SHORT` and `TYPE_INT` values are converted to int. Example value:: mappingproxy({ 1: 8, 2: 443, 3: 60000, ... 27: b'POST\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', 53: b'\x0c\xe2\xf5TD\xe4y5\x16\xb5\xaf\xe9g\xbe\x92U', }) .. py:property:: settings :type: Mapping[str, Any] Read-only Beacon settings mapping with human readable values, indexed by `BeaconSetting` name. Example value:: mappingproxy({ 'SETTING_PROTOCOL': 8, 'SETTING_PORT': 443, 'SETTING_SLEEPTIME': 60000, ... 'SETTING_C2_VERB_POST': 'POST', 'SETTING_PROCINJ_STUB': '0ce2f55444e4793516b5afe967be9255', }) .. py:property:: settings_by_index :type: Mapping[int, Any] Read-only Beacon settings mapping with human readable values, indexed by `BeaconSetting` constant. Example value:: mappingproxy({ 1: 8, 2: 443, 3: 60000, ... 27: 'POST', 53: '0ce2f55444e4793516b5afe967be9255', }) .. py:property:: domain_uri_pairs :type: List[Tuple[str, str]] List of configured `(domain, uri)` pairs in the Beacon. Example value:: [ ('c1.example.com', '/__utm.gif'), ('c2.example.com', '/en_US/all.js'), ] .. py:property:: uris :type: List[str] List of configured Beacon URIs. Example value:: ['/__utm.gif', '/en_US/all.js'] .. py:property:: domains :type: List[str] List of configured Beacon domains. Example value:: ['c1.example.com', 'c2.example.com'] .. py:property:: submit_uri :type: Optional[str] The submit URI that the beacon uses for sending callback data. Example value:: '/submit.php' .. py:property:: killdate :type: Optional[str] Normalized kill date as YYYY-mm-dd string or ``None`` if not defined in Beacon. .. note:: The reason why the return type is a :class:`str` instead of a :class:`datetime.date` object is that the configured `killdate` in the Beacon can be arbitrary. e.g. 9999-99-99 .. py:property:: protocol :type: Optional[str] The protocol the Beacon uses for communication, e.g. ``"http"``, ``"dns"``. ``None`` if unknown. .. py:property:: port :type: Optional[int] The port the Beacon uses for communication, e.g. ``80``, ``443``. ``None`` if not defined in config. .. py:property:: watermark :type: Optional[int] Beacon watermark (also known as customer or authorization id). .. py:property:: is_trial :type: bool True if Beacon is a trial version (CRYPTO_TRIAL_PRODUCT). Otherwise, False. .. py:property:: version :type: dissect.cobaltstrike.version.BeaconVersion Deduced version of Cobalt Strike as :class:`~dissect.cobaltstrike.version.BeaconVersion` object. The version is deduced from the Beacon's :attr:`pe_export_stamp` when available, otherwise from :attr:`max_setting_enum`. .. py:property:: public_key :type: bytes The RSA public key used by the Beacon in DER format. .. py:property:: sleeptime :type: Optional[int] The sleep time in milliseconds the Beacon uses between communication attempts. .. py:property:: jitter :type: Optional[int] The jitter in milliseconds the Beacon uses between communication attempts. .. py:function:: build_parser() .. py:function:: main() Entrypoint for beacon-dump.