Using Kaitai Struct to Parse Cobalt Strike Beacon Configs

Parsing Beacon Configs: Basics

To Start

Binary Config Structure

Two I-TLV structures at the beginning of the sample config.
  • Index # = 0x01 (Beacon Type) | Type = 0x01 (Short) | Length = 0x02 | Value = 0x00 (HTTP Beacon)
  • Index # = 0x02 (Port) | Type = 0x01 (Short) | Length = 0x02 | Value = 0x50 (Port 80)
Config field 0x8 showing an example blob structure in the sample data
config_entry:
seq:
- id: index
type: u2
- id: fieldtype
type: u2
- id: fieldlength
type: u2
- id: fieldvalue
size: fieldlength
type:
switch-on: fieldtype
cases:
1: u2
2: u4
3: bytes
bytes:
seq:
- id: byte_val
type:
switch-on: _parent._parent.index
cases:
11: transform_blocks
12: req_malleablec2
13: req_malleablec2
42: gargle_section
46: procinj_transform
47: procinj_transform
....... SUB STRUCTURES CONTINUE

Beacon Configs: Malleable C2

Malleable C2 Request Blocks

Comparison showing the binary structure for malleable c2 and the actual written c2 profile.
  • (0xa or _Header| 0xb | “Accept: */*”)
  • (0xa or _Header | 0x16 | “Content-Type: text/xml”)
  • (0xa or _Header | 0x20 | “X-Requested-With” “XMLHttpRequest”)
  • (0x10 or _HostHeader | 0x14 | “Host: www.amazon.com”)
  • (0x9 or _Parameter | 0xa | “sz=160x600”)
  • …. And so on
malleable_block:
seq:
- id: statement
type: u4
enum: transform_actions
- id: statement_value
type:
switch-on: statement
cases:
transform_actions::uheader: length_val_string
transform_actions::uparameter: length_val_string
transform_actions::build: data_transform
transform_actions::uhostheader: length_val_string
if: statement != transform_actions::stop

DataTransform Blocks

output {            
base64;
print;
}
Example DataTransform block within the binary structure.
  • (0x07 = DataTransform) (0x01 = Output Section) (0x03 = Base64) (0x04 = Terminate_Print)
 data_transform:
seq:
- id: type_code
type: u4
- id: transform_statement
type: transform_statement
repeat: until
repeat-until: _.action == <TERMINATION ACTION>
transform_statement:
seq:
- id: action
type: u4
enum: transform_actions
- id: action_args
type:
switch-on: action
cases:
transform_actions::append: length_val_bytes
transform_actions::prepend: length_val_bytes
transform_actions::termination_header: length_val_string
transform_actions::termination_parameter: length_val_string
if: <NOT A TERMINATION ACTION>

Results & Future Work

GraphViz output of my parser structs. This is not very pretty but so easy to generate!
Screenshot of simple HTML/Javascript wrapper POC using my Kaitai Struct Beacon Config Parser. Some wrapping functionality is required to display and pretty print the structure information.
  • This parser will break if CS adds sub-structures to existing assumed formats such as Malleable C2 Req. For example, if there is a new Malleable Transform Action that has a (length | value) argument, this proof-of-concept will not know about it today. This should handle new “fields” at the higher level just fine, it will treat them as blobs.
  • The current parser assumes you start the input at the config start (it does not handle unpacking, xor decoding, or seeking the config).
  • I believe my structure definition is overly nested and complicated. I’d bet that it could be optimized many ways by someone with more time in the language. It could definitely be prettier.
  • I would love to extend the parser to handle Beacon dlls or stages entirely without the need to first parse the start of the config bytes. I didn’t implement this for the sake of time.
  • There are probably more blob structures that have meaning to the Beacon agent and could use sub-structures. I implemented the obvious ones.
  • Validate all of the bytes fields that should be strings are properly casted.

Would I do it again?

--

--

--

Tech: Threat Intel | Photographer @ https://www.justinwarnerphoto.com

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

Adobe Xd — Creating your first project

Ruby i18n — Translate Ruby Projects With Gettext & PO Files

Creating Sneakers workers dynamically

BI Dashboards are Creating a Technical Debt Black Hole

Data Pipeline to Visualize CloudWatch logs in Kibana

Managing Pod configuration using ConfigMaps and Secrets in Kubernetes

Why businesses should apply ‘Agile’ to everything

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Justin Warner

Justin Warner

Tech: Threat Intel | Photographer @ https://www.justinwarnerphoto.com

More from Medium

Data Privacy Day: Accellion Fined 💸 Red Cross Breached 🚑 & Ransomware in Indonesia🏴‍☠️

EU working on a government controlled DNS service

Evil phase of extensions we use — In cybersecurity perspective

Reverse engineering musings: WhisperGate Stages 1 & 2