Skip to content

Reverse HTTP Listener

The HTTP listener opens an HTTP/HTTPS server on a specified port and manages bidirectional data traffic with agents.

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.
https bool Yes - Protocol flag. false = HTTP, true = HTTPS.
startTime string No - Optional UTC start time (e.g. 2025-04-10T11:02:09Z).
instantResponses bool No false When true, the agent sends data immediately. When false, it waits for the sleep timeout (better OPSEC).

URIs and Metadata

Parameter Type Required Default Description
getUri string Yes - URI for GET requests when the agent has no data to send (polling).
postUri string Yes - URI for POST requests to send data (also receives data in the response).
stagedUri string No - URI for downloading generated agent executable/DLL/service/shellcode.
stagedUriPayloadId string No - GET parameter name containing the payload ID when downloading via stagedUri.
filename string No - Template string for the Content-Disposition filename when serving payloads. See filename Template Functions.
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. Can be overridden per callback group via httpCallbacks[].sleep.
sleepRandom int No 0 Global jitter in seconds. Can be overridden per callback group via httpCallbacks[].sleepRandom.

HTTP Headers

Parameter Type Required Default Description
headers[] array No [] Additional HTTP headers (array of objects with name and value fields).

Callback Groups (httpCallbacks[])

Each callback group defines a set of hosts the agent can connect to, along with independent sleep and rotation settings.

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.
hostsRotation object No - Rotation rules for host selection.
hostHeaderRotation object No - Rotation rules for host header selection.

Rotation Object

Parameter Type Required Description
type string Yes Rotation strategy: FAILOVER, ROTATE, or RANDOM.
counter int Yes Numeric threshold that triggers a rotation.
unit string Yes Unit for the counter: TRIES, SECONDS, MINUTES, or HOURS.

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 settings. This keeps configurations compact.


Equivalent Configurations

These two configurations are equivalent - the compact form puts two hosts in one callback group, while the expanded form uses separate callback groups:

Compact form:

{
  "port": 8089,
  "httpCallbacks": [
    {
      "hosts": ["localhost", "192.168.1.100"],
      "hostsRotation": { "type": "ROTATE", "counter": 7, "unit": "TRIES" },
      "sleep": 3000,
      "sleepRandom": 1000,
      "hostHeaders": ["alpha", "bravo", "charlie"],
      "hostHeaderRotation": { "type": "FAILOVER", "counter": 2, "unit": "TRIES" }
    }
  ],
  "getUri": "/GIVEITTOME",
  "postUri": "/NOWIGIVETOYOU",
  "stagedUri": "/candy",
  "fileStorageUri": "/files/",
  "metadataCookieName": "PHPSESSID",
  "metadataPrefix": "ABC",
  "metadataSuffix": "XYZ",
  "https": false,
  "startTime": "2023-04-10T11:02:09Z",
  "headers": [
    { "name": "Extra-Header-Name", "value": "Extra-Header-Value" }
  ],
  "sleep": 1500
}

Expanded form:

{
  "port": 8089,
  "httpCallbacks": [
    {
      "hosts": ["localhost"],
      "hostsRotation": { "type": "ROTATE", "counter": 7, "unit": "TRIES" },
      "sleep": 3000,
      "sleepRandom": 1000,
      "hostHeaders": ["alpha", "bravo", "charlie"],
      "hostHeaderRotation": { "type": "FAILOVER", "counter": 2, "unit": "TRIES" }
    },
    {
      "hosts": ["192.168.1.100"],
      "hostsRotation": { "type": "ROTATE", "counter": 7, "unit": "TRIES" },
      "sleep": 3000,
      "sleepRandom": 1000,
      "hostHeaders": ["alpha", "bravo", "charlie"],
      "hostHeaderRotation": { "type": "FAILOVER", "counter": 2, "unit": "TRIES" }
    }
  ],
  "getUri": "/GIVEITTOME",
  "postUri": "/NOWIGIVETOYOU",
  "stagedUri": "/candy",
  "fileStorageUri": "/files/",
  "metadataCookieName": "PHPSESSID",
  "metadataPrefix": "ABC",
  "metadataSuffix": "XYZ",
  "https": false,
  "startTime": "2023-04-10T11:02:09Z",
  "headers": [
    { "name": "Extra-Header-Name", "value": "Extra-Header-Value" }
  ],
  "sleep": 1500
}


Examples

Example 1 - Basic Configuration with Host Rotation

{
  "port": 8089,
  "https": false,
  "httpCallbacks": [
    {
      "hosts": ["localhost", "192.168.1.100"],
      "hostsRotation": { "type": "ROTATE", "counter": 7, "unit": "TRIES" },
      "sleep": 3000,
      "sleepRandom": 1000,
      "hostHeaders": ["alpha", "bravo", "charlie"],
      "hostHeaderRotation": { "type": "FAILOVER", "counter": 2, "unit": "TRIES" }
    }
  ],
  "getUri": "/GIVEITTOME",
  "postUri": "/NOWIGIVETOYOU",
  "stagedUri": "/candy",
  "fileStorageUri": "/files/",
  "metadataCookieName": "PHPSESSID",
  "metadataPrefix": "ABC",
  "metadataSuffix": "XYZ",
  "startTime": "2023-04-10T11:02:09Z",
  "headers": [
    { "name": "Extra-Header-Name", "value": "Extra-Header-Value" }
  ],
  "instantResponses": false,
  "sleep": 1500
}

Example 2 - Complex Rotation Rules

{
  "port": 8089,
  "https": false,
  "httpCallbacks": [
    {
      "hosts": ["localhost"],
      "hostsRotation": { "type": "FAILOVER", "counter": 5, "unit": "MINUTES" },
      "sleep": 10000,
      "sleepRandom": 4000,
      "hostHeaders": ["alpha", "bravo", "charlie"],
      "hostHeaderRotation": { "type": "ROTATE", "counter": 30, "unit": "SECONDS" }
    },
    {
      "hosts": ["192.168.1.100"],
      "hostsRotation": { "type": "FAILOVER", "counter": 3, "unit": "TRIES" },
      "sleep": 8000,
      "sleepRandom": 6000,
      "hostHeaders": ["delta", "echo"],
      "hostHeaderRotation": { "type": "RANDOM", "counter": 2, "unit": "TRIES" }
    }
  ],
  "getUri": "/GIVEITTOME",
  "postUri": "/NOWIGIVETOYOU",
  "stagedUri": "/candy",
  "fileStorageUri": "/files/",
  "metadataCookieName": "PHPSESSID",
  "metadataPrefix": "ABC",
  "metadataSuffix": "XYZ",
  "startTime": "2023-04-10T11:02:09Z",
  "headers": [
    { "name": "Extra-Header-Name", "value": "Extra-Header-Value" }
  ],
  "instantResponses": false,
  "sleep": 1500
}

How the rotation works:

  1. Agent starts with connection to localhost using host header alpha
  2. For the localhost callback group:
    • Host rotation occurs after 5 minutes of failed connections
    • Host headers rotate every 30 seconds between alpha, bravo, and charlie
  3. For the 192.168.1.100 callback group:
    • Host rotation occurs after 3 failed connection attempts
    • Host headers randomly switch between delta and echo with 50% probability before each request

Info

Host rotation and header rotation operate independently. A successful connection resets the host rotation counter, while header rotation continues according to its own rules.


Custom User-Agent Header

By default, agents use a built-in User-Agent string. Override it using the headers array:

1
2
3
"headers": [
  { "name": "User-Agent", "value": "not-curl" }
]

Result: The first request uses the default User-Agent. After the configuration is applied, subsequent requests use the custom value:

1
2
3
4
5
6
7
8
GET /get HTTP/1.1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36 Edg/129.0.0.0
Cookie: JWT_SESSION=<...metadata...>
Host: 172.16.235.129:8888

HTTP/1.1 200 OK
Content-Type: text/plain
Content-Length: 0
1
2
3
4
5
6
7
8
GET /get HTTP/1.1
User-Agent: not-curl
Cookie: JWT_SESSION=<...metadata...>
Host: 172.16.235.129:8888

HTTP/1.1 200 OK
Content-Type: text/plain
Content-Length: 0

filename Template Functions

Template Description
{rand_str_X} Random case-insensitive string of length X.
{rand_str_X_Y} Random string with length between X and Y.
{rand_int_X_Y} Random integer between X and Y.
{ext} File extension of the requested payload, including the dot (e.g. .exe, .dll).
{payload_id} Payload ID of the requested payload.

Example:

"filename": "{rand_str_10}-Little-{rand_str_9_20}-Agent-{rand_int_9_2000000000}-With-{payload_id}-{ext}"

Result:

> GET /payload?payloadId=4 HTTP/1.1
> Host: skippy.and.joe
> User-Agent: curl/1337.81.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Content-Type: application/octet-stream
< Content-Disposition: attachment; filename="A9JfMQRwq8-Little-guhRgWYRqV-Agent-391964415-With-4-.exe"
< Content-Length: 770560