▸ On this page 6 sections
Background
A C2 framework's default profile is a detection fingerprint. Every mature SOC has signatures for default Cobalt Strike check-in URIs, default User-Agent strings, and beacon sleep/jitter patterns. Malleable profiles let you reshape that traffic to match something legitimately present in the target environment - a health-check endpoint, a CDN poll, an analytics beacon.
This is a tradecraft note on writing a minimal but effective profile for an authorized red team engagement.
What a profile controls
A malleable profile shapes three main dimensions:
- HTTP request/response structure - URI, headers, User-Agent, how data is encoded in the body or parameters
- Sleep/jitter - check-in interval and randomization range
- Process injection and in-memory staging behavior - relevant for EDR evasion, out of scope for this note
set sleeptime "45000"; # 45s base
set jitter "20"; # ±20%
http-get {
set uri "/api/v1/health";
client {
header "Accept" "application/json";
header "User-Agent" "Mozilla/5.0 (Windows NT 10.0; Win64; x64)";
metadata { base64url; parameter "sid"; }
}
server {
header "Content-Type" "application/json";
output { base64url; print; }
}
}
Match the User-Agent to what actually appears in the target's proxy logs. A generic Chrome UA on a network that only runs Edge will still stand out.
Matching the environment baseline
Before writing a profile, spend time understanding the target's legitimate traffic. Look for:
- High-frequency, low-payload polling - monitoring agents, CDN health checks, analytics pings. These are ideal mimicry targets.
- Expected header sets - what headers does their SaaS tooling send? Copy them faithfully.
- Certificate subjects - if you're doing HTTPS C2, use a categorized domain with a matching cert, not a fresh Let's Encrypt on a newly registered domain.
# Pull proxy logs for top URIs by frequency
Get-Content proxy.log | Group-Object {($_ -split ' ')[6]} |
Sort-Object Count -Descending | Select-Object -First 20
High jitter (30–40%) matters more than low sleep for avoiding frequency-based detection. A beacon that checks in every 45s ± 18s looks like an application poll; one that checks in exactly every 60s looks like a cron job.
Validating the profile
Before the engagement, run the profile through a packet capture and review it through a defender's lens:
# Capture beacon traffic to pcap and open in Wireshark / Zeek
tcpdump -i lo -w beacon-test.pcap host <teamserver>
# Check for obvious signatures: default URIs, odd header ordering,
# non-browser TLS fingerprint (JA3/JA4)
TLS fingerprinting (JA3/JA4) is independent of your HTTP headers - it's derived from the TLS ClientHello. A perfect HTTP profile on a non-browser TLS stack is still fingerprintable. Use a browser-derived TLS stack or configure your C2 framework's TLS behavior explicitly.
Cleaning up
After the engagement, pull your implants and verify no stager artifacts remain on disk. Rotate your C2 domain out of active use - a domain that called back during an engagement becomes a permanent signature in the client's SIEM.
Takeaway
A good malleable profile is environment-specific. Generic "stealth" profiles from public repositories are known to every EDR vendor and SIEM rule author. The investment is in understanding the target's network baseline first, then writing a profile that fits inside it - not in applying a one-size-fits-all template.