Skip to content
Command & Controlintermediate

Malleable C2 Profiles

Operator-supplied profiles let a C2 framework reshape its beacon traffic to mimic legitimate web services, controlling URIs, headers, and how data is encoded and hidden in requests.

A Malleable C2 profile is a text configuration — popularised by Cobalt Strike but copied by other frameworks — that dictates exactly what a beacon's network traffic looks like. Instead of a fixed, fingerprintable protocol, the operator describes the URIs to request, the HTTP headers to send, the User-Agent, and how task data and results are transformed (base64, mask/XOR, prepend/append, netbios) and placed into a request (in a cookie, a header, a URI parameter, or the body). The result is a beacon that can convincingly impersonate jQuery CDN traffic, Office 365 telemetry, or an Amazon API call.

Profiles are powerful for the attacker precisely because they collapse a network signature into operator-chosen data. They are equally powerful for the defender: the profile is the protocol specification, so recovering it (from the beacon config or from public profile repositories) hands you a decoder for the traffic and a high-fidelity hunting signature.

How it works

A profile defines client and server transactions. The relevant fragment for an analyst describes where data hides and how it is encoded:

# Descriptive Cobalt-Strike-style profile excerpt.
http-get {
    set uri "/jquery-3.3.1.min.js";
    client {
        header "Accept" "*/*";
        metadata {
            base64url;            # encode beacon metadata
            prepend "__cfduid=";  # hide it inside a benign-looking cookie
            header "Cookie";
        }
    }
    server {
        header "Content-Type" "application/javascript";
        output {
            base64;
            print;                # tasking returned in the response body
        }
    }
}

The beacon reads this profile from its embedded configuration block and applies the transforms at runtime. For a reverser, the practical win is extracting that config: tools such as parse routines for the Cobalt Strike beacon config (the obfuscated settings table, historically single-byte XOR 0x2E/0x69) yield the exact URIs, headers, User-Agent, and transform chain.

Detection & analysis

Static analysis:

  • Locate and decode the beacon configuration block. Cobalt Strike beacons store settings in an XOR-encoded table; community parsers (e.g. 1768.py, SentinelOne/Didier Stevens tooling) extract the profile fields directly, revealing URIs, headers, sleep/jitter, and the watermark.
  • The recovered transform chain (base64 → mask → prepend → store-in-cookie) is a complete decoder: apply it in reverse to captured traffic to read metadata and tasking.
  • Match the recovered profile against public profile repositories; many actors reuse off-the-shelf profiles, which can attribute the intrusion set.

Dynamic analysis:

  • Detonate and capture HTTP(S). Even when content is encoded, the structure is fixed by the profile: the same URI, the same header ordering, a static User-Agent, and regular beacon intervals modulated by jitter. Profile-driven traffic is rigidly self-consistent in a way real browser traffic is not.
  • JA3/JA3S and HTTP header-order fingerprinting catch the divergence between a claimed application (e.g. "jQuery CDN") and the beacon's actual TLS/HTTP stack.

Detection rule hint:

Hunt for HTTP(S) sessions matching a known malleable profile's URI + header + User-Agent triad combined with regular, jittered beacon timing — and corroborate with a JA3 fingerprint inconsistent with the impersonated service. Because the profile fixes every observable field, a single high-fidelity profile signature plus periodic beaconing is a reliable detector.

Votes

Comments(0)