Reverse HTTP Listener
The HTTP Listener establishes an HTTP/HTTPS server on a specified port, managing bidirectional data traffic with agents. It provides secure and discreet communication channels between the C2 infrastructure and deployed agents, blending with regular web traffic patterns.
Plugin ID: shelldot.listener.agent-reverse-http
Configuration Reference
Connection
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
port |
int | Yes | - | Port number the agent calls home to. Also the listener port unless bindToPort is set. |
bindToPort |
int | No | null |
Port number the listener actually binds to. When null, the port value is used. Useful when a reverse proxy or redirector sits in front of the listener. |
https |
bool | Yes | - | Protocol flag. false = HTTP, true = HTTPS. |
startTime |
string | No | - | Optional UTC start time for the listener (e.g. 2025-04-10T11:02:09Z). |
instantResponses |
bool | No | false |
When true, the agent sends data immediately. When false, the agent waits for the sleep timeout before responding - better OPSEC but higher latency. |
URIs and Metadata
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
getUri |
string | Yes | - | URI the agent uses for GET requests when it has no data to send (polling). |
postUri |
string | Yes | - | URI the agent uses for POST requests to send data (also receives data in the response). |
stagedUri |
string | No | - | URI for downloading a generated agent executable, DLL, service binary, or shellcode. |
stagedUriPayloadId |
string | No | - | GET parameter name that contains the payload ID when downloading via stagedUri. |
filename |
string | No | - | Template string for the Content-Disposition filename when serving payloads via stagedUri. See filename Template Functions below. |
fileStorageUri |
string | No | - | Base URI for retrieving files from file storage. |
metadataCookieName |
string | Yes | - | Cookie name used to carry agent metadata. |
metadataPrefix |
string | No | "" |
String prepended to metadata before encoding. |
metadataSuffix |
string | No | "" |
String appended to metadata before encoding. |
Sleep
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
sleep |
int | Yes | - | Global base sleep time in seconds between agent requests. Can be overridden per callback group via httpCallbacks[].sleep. |
sleepRandom |
int | No | 0 |
Global jitter in seconds added to the sleep time. Can be overridden per callback group via httpCallbacks[].sleepRandom. |
Web Proxy
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
webProxy |
string | No | - | URL of the web proxy for agent connections (e.g. http://proxy.corp:8080). |
webProxyUsername |
string | No | - | Username for proxy authentication. |
webProxyPassword |
string | No | - | Password for proxy authentication. |
webProxyWindowsAuth |
bool | No | false |
Use Kerberos/NTLM authentication for the proxy (Windows only). |
HTTP Headers
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
headers[] |
array | No | [] |
Additional HTTP headers sent with every agent request. Each entry is an object with name and value fields. |
Example:
Custom User-Agent
By default, agents use a built-in User-Agent string. Override it by adding a User-Agent entry to the headers array. The first request uses the default value; subsequent requests use the custom value.
Callback Groups (httpCallbacks[])
Each callback group defines a set of hosts the agent can connect to, along with independent sleep and rotation settings. Multiple callback groups allow the agent to use completely different connection profiles.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
hosts[] |
string[] | Yes | - | IP addresses or hostnames the agent can connect to. |
sleep |
int | Yes | - | Base sleep time in seconds for this callback group. |
sleepRandom |
int | No | 0 |
Jitter in seconds for this callback group. |
hostHeaders[] |
string[] | No | [] |
HTTP Host header values used when connecting - enables domain fronting. |
hostsRotation |
object | No | - | Rotation rules for host selection. See Rotation Rules. |
hostHeaderRotation |
object | No | - | Rotation rules for host header selection. See Rotation Rules. |
Multiple hosts shorthand
If hosts[] contains more than one entry, each host is treated as if it were its own callback group with the same rotation, sleep, and header settings. This is a shorthand to keep configurations compact. See the equivalent configurations example below.
Rotation Rules
Rotation rules define when the agent should switch to the next host or change the HTTP Host header. This is used for resilience (failover to backup endpoints) and evasion (domain fronting rotation).
Rotation Object
| Parameter | Type | Required | Description |
|---|---|---|---|
type |
string | Yes | Rotation strategy: FAILOVER, ROTATE, or RANDOM. |
counter |
int | Yes | Numeric threshold that triggers a rotation. Interpretation depends on type. |
unit |
string | Yes | Unit for the counter: TRIES, SECONDS, MINUTES, or HOURS. |
Rotation Types
FAILOVER - Switch to the next host/header after a number of consecutive failures.
- Counter +
TRIES: switch after N consecutive failed connection attempts - Counter + time unit: switch after N seconds/minutes/hours since the last successful connection
ROTATE - Switch to the next host/header after a number of total attempts (successful or not).
- Counter +
TRIES: switch after every N connection attempts - Counter + time unit: switch after N seconds/minutes/hours since the last rotation
RANDOM - Switch randomly before each request.
- The probability of switching is
1/counterper request - The
unitvalue is ignored for this type
Rotation Examples
| Scenario | Type | Counter | Unit | Behavior |
|---|---|---|---|---|
| Switch after 7 requests (success or fail) | ROTATE |
7 |
TRIES |
Cycles through hosts every 7 attempts |
| Switch after 2 consecutive failures | FAILOVER |
2 |
TRIES |
Only switches when connectivity breaks |
| Switch after 3 min without success | FAILOVER |
3 |
MINUTES |
Time-based failover |
| Switch every hour | ROTATE |
1 |
HOURS |
Periodic rotation regardless of success |
| 12.5% chance per request | RANDOM |
8 |
TRIES |
Random switching (1/8 probability) |
Rotation Logic
The rotation logic follows the workflow below. Host rotation and host header rotation operate independently, each with their own counters. When both trigger simultaneously, the host rotation takes priority and the host header counter resets.

Counter independence
A successful connection resets the FAILOVER counter for host rotation but does not affect the host header rotation counter. Each counter tracks its own state independently.
Configuration Scenarios
Scenario 1 - Basic HTTP Beaconing
The minimal configuration for an agent calling back over plain HTTP. Suitable for lab environments or controlled exercises.
Scenario 2 - HTTPS with Domain Fronting
The agent connects to a CDN edge IP but sends a different Host header pointing to a CDN-fronted domain. Traffic appears as legitimate CDN activity. Requires an HTTPS listener and a valid (or self-signed) certificate.
Info
Domain fronting requires that the CDN or proxy permits requests with a mismatched Host header. Some CDN providers have restrictions on this technique. Test in your environment before relying on it operationally.
Scenario 3 - Resilient Multi-Endpoint Rotation
The agent alternates between multiple C2 endpoints across different IPs. Designed for long-haul operations where individual endpoints may go offline or get blocked. The FAILOVER strategy ensures the agent only switches when connectivity actually breaks.
How it works:
- Agent connects to
c2-primary.example.com - After 3 consecutive failures, it switches to
c2-secondary.example.com - After 3 more consecutive failures, it moves to
c2-tertiary.example.com - The cycle repeats - the agent keeps retrying all endpoints indefinitely
- A successful connection resets the failure counter for that host
Tip
For maximum resilience, host each endpoint on a different cloud provider or geographic region. Combine with long sleep intervals (sleep: 300+) to reduce detection surface during low-activity periods.
Scenario 4 - Detailed Rotation Walkthrough
A configuration with two IPs and three host headers, showing exactly how rotation counters interact.
Step-by-step rotation behavior:
- Agent starts connecting to
1.2.3.4with host headeralpha - After 3 consecutive failures, the host header switches to
bravo(host stays at1.2.3.4- only 3 of 9 failures reached) - After 3 more consecutive failures, the host header switches to
charlie(host still1.2.3.4- only 6 of 9 failures) - After 3 more failures, both rotation rules trigger simultaneously. Host rotation takes priority:
- Connection switches to
5.6.7.8 - Host header counter resets back to
alpha
- Connection switches to
- The pattern repeats for
5.6.7.8: header rotates throughalpha→bravo→charlieevery 3 failures - After 9 total failures on
5.6.7.8, the host rotates back to1.2.3.4(circular selection) and headers reset toalpha
Info
The counters for host rotation and host header rotation operate independently. If there are three failed connections followed by a successful connection, and then six subsequent failures, the connection will not switch to 5.6.7.8 - its counter resets after the successful connection. Similarly, host header counters reset after each rotation trigger, so in this case the host header will have rotated three times and returned to "charlie".
Equivalent Configurations
When the hosts[] array in a callback group contains more than one entry, it is shorthand for multiple callback groups with identical settings. These two configurations are equivalent:
Compact form (two hosts in one callback group):
Expanded form (each host in its own callback group):
filename Template Functions
Template tokens for the filename parameter, which controls the Content-Disposition header when payloads are served via stagedUri.
| Template | Description |
|---|---|
{rand_str_X} |
Random case-insensitive string of length X (e.g. {rand_str_10} produces A9JfMQRwq8). |
{rand_str_X_Y} |
Random string with length between X and Y (e.g. {rand_str_9_20}). |
{rand_int_X_Y} |
Random integer between X and Y (e.g. {rand_int_9_2000000000}). |
{ext} |
File extension of the requested payload, including the dot (e.g. .exe, .dll). |
{payload_id} |
Payload ID of the requested payload. |
Example:
Result: