Skip to content

Reverse HTTP listener for built agents

HTTP listener is listener that open HTTP Server on given port and implements data traffic with agents via HTTP/HTTPS connections.

Plugin ID: shelldot.listener.agent-reverse-http

Configuration

  • port - On what port the HTTP listener is listening for connection
  • httpCallbacks[] - Callback configuration
    • hosts - String array of the IP-s and hostnames the agent will use to connect C2
    • hostsRotation - Rule about when is next host selected (described in detail below)
      • type - Type of the rule (FAILOVER, ROTATE, RANDOM)
      • counter - Numeric value of the rule
      • unit - In what units the counter is (TRIES, SECONDS, MINUTES, HOURS)
    • sleep - Sleep time(ms) between requests
    • sleepRandom - Sleep time(ms) randomness (+-)
    • hostHeaders - List of HTTP host headers used when connecting given host/-s
    • hostsHeadersRotation - Rule about when is next HTTP host header selected (described in detail below)
      • type - Type of the rule (FAILOVER, ROTATE, RANDOM)
      • counter - Numeric value of the rule
      • unit - In what units the counter is (TRIES, SECONDS, MINUTES, HOURS)
  • getURI - URI that the agent will use to ask data from C2 (via GET request) if it has none to send itself
  • postURI - URI that the agent will use to send data to C2 (via POST request) - it will also receive data from C2
  • stagedURI - URI that can be used to ask C2 to generate agent executable/dll/service/shellcode
  • stagedURIlistenerId - If agent should not connect given listener, you can define ID of any other listener via GET parameter defined by this conf value
  • stagedURItype - Name of the GET variable that should contain type of the agent to generate
  • fileStorageURI - Base URI for getting files from file storage
  • metadataCookieName - What cookie should contain metadata
  • metadataPrefix - Prefix for the metadata
  • metadataSuffix - Suffix for the metadata
  • https - is traffic over HTTPS or HTTP
  • startTime - If listener should not start right away then this value defines starting time (for example "2023-04-10T11:02:09Z")
  • sleep - Sleep time(ms) between requests (every host can also define it's own)
  • sleepRandom - Sleep time(ms) randomness (+-) between requests (every host can also define it's own)
  • headers - Additional headers used in HTTP requests, format is [{ "name": "headerName", "value": "headerValue"}]
  • instantResponses -: Should the Agent send data as soon as it is available (eg. command result), or wait until the sleep time rolls around for maximum OPSEC

Hosts string array

If inner hosts string array contains more than 1 hostname/IP, then it's same as host object array to contain same number of objects, each with only one value in host string array bus rest configuration same. This is just so users would be able to keep configuration smaller.

These two configurations are equal:

"configuration": 
{
    "port": 8089,
    "hosts": [
      {
        "hosts": [
          "localhost",
          "192.168.1.100"
        ],
        "hostsRotation": {
          "type": "ROTATE",
          "counter": 7,
          "unit": "TRIES"
        },
        "sleep": 3000,
        "sleepRandom": 1000,
        "hostHeaders": [
          "alpha",
          "bravo",
          "charlie"
        ],
        "hostsHeadersRotation": {
          "type": "FAILOVER",
          "counter": 2,
          "unit": "TRIES"
        }
      }
    ],
    "getURI": "/GIVEITTOME",
    "postURI": "/NOWIGIVETOYOU",
    "stagedURI": "/candy",
    "stagedURIlistenerId": "candyTarget",
    "stagedURItype": "candyType",
    "fileStorageURI": "/files/",
    "metadataCookieName": "PHPSESSID",
    "metadataPrefix": "ABC",
    "metadataSuffix": "XYZ",
    "secure": 0,
    "startTime": "2023-04-10T11:02:09Z",
    "headers": [
        { 
          "name": "Extra-Header-Name",
          "value": "Extra-Header-Value"
        }
      ]
}
vs
"configuration": 
{
    "port": 8089,
    "hosts": [
      {
        "hosts": [
          "localhost"
        ],
        "hostsRotation": {
          "type": "ROTATE",
          "counter": 7,
          "unit": "TRIES"
        },
        "sleep": 3000,
        "sleepRandom": 1000,
        "hostHeaders": [
          "alpha",
          "bravo",
          "charlie"
        ],
        "hostsHeadersRotation": {
          "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"
        ],
        "hostsHeadersRotation": {
          "type": "FAILOVER",
          "counter": 2,
          "unit": "TRIES"
        }
      }
    ],
    "getURI": "/GIVEITTOME",
    "postURI": "/NOWIGIVETOYOU",
    "stagedURI": "/candy",
    "stagedURIlistenerId": "candyTarget",
    "stagedURItype": "candyType",
    "fileStorageURI": "/files/",
    "metadataCookieName": "PHPSESSID",
    "metadataPrefix": "ABC",
    "metadataSuffix": "XYZ",
    "secure": 0,
    "startTime": "2023-04-10T11:02:09Z",
    "headers": [
        { 
          "name": "Extra-Header-Name",
          "value": "Extra-Header-Value"
        }
      ]
}

Examples

Example 1

For first let's take the same example provided couple lines ago. As said they are equal configurations. What happens when agent set to connect to this listener will start:

  1. Agent will connect HTTP server at localhost on port 8089 and will use host header value "alpha"
  2. Agent switches to 192.168.1.100 when there has been connection attempts to C2 (no matter were they successful or not). The switch back happens in same conditions
  3. HTTP host header value "alpha" is used until 2 consecutive requests fails. Then value "bravo" is used and after 2 failed request the value "charlie". If "charlie" also fails, the circle is started again with "alpha".

NB * The change of selected host (localhost & 192.168.1.100) is never caused by changes in host header * If host selection (localhost & 192.168.1.100) changes, the counters for host headers is reset

Example 2

"configuration": 
{
    "port": 8089,
    "hosts": [
      {
        "hosts": [
          "localhost"
        ],
        "hostsRotation": {
          "type": "FAILOVER",
          "counter": 5,
          "unit": "MINUTES"
        },
        "sleep": 10000,
        "sleepRandom": 4000,
        "hostHeaders": [
          "alpha",
          "bravo",
          "charlie"
        ],
        "hostsHeadersRotation": {
          "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"
        ],
        "hostsHeadersRotation": {
          "type": "RANDOM",
          "counter": 2,
          "unit": "TRIES"
        }
      }
    ],
    "getURI": "/GIVEITTOME",
    "postURI": "/NOWIGIVETOYOU",
    "stagedURI": "/candy",
    "stagedURIlistenerId": "candyTarget",
    "stagedURItype": "candyType",
    "fileStorageURI": "/files/",
    "metadataCookieName": "PHPSESSID",
    "metadataPrefix": "ABC",
    "metadataSuffix": "XYZ",
    "secure": 0,
    "startTime": "2023-04-10T11:02:09Z",
    "headers": [
      { 
        "name": "Extra-Header-Name",
        "value": "Extra-Header-Value"
      }
    ]
}
  1. Agent will connect HTTP server at localhost on port 8089 and will use host header value "alpha"
  2. Agent will switch from localhost to 192.168.1.100 when it has failed for 5 minutes to connect to C2
  3. Agent will switch from 192.168.1.100 to localhost if it has failed 3 consecutive requests
  4. If agent is trying to connect to localhost the host header values will switch between "alpha", "bravo" and "charlie" in every 30 seconds
  5. If agent is trying to connect to 192.168.1.100 the host header values will switch between "delta" and "echo" on random (before every request there is 1/2 or 50% possibility that switch is made)