Skip to content

Reverse HTTP listener for built agents

The HTTP Listener is a component that establishes an HTTP server on a specified port, managing data traffic with agents through HTTP or HTTPS connections. This functionality is vital for maintaining discreet and secure communication channels between the Command and Control (C2) infrastructure and the agents. By leveraging HTTP or HTTPS protocols, the listener ensures reliable and encrypted data exchange, which is crucial for operational security and efficiency. The ability to operate over commonly used web protocols also aids in blending the traffic with regular internet data, thereby reducing the likelihood of detection. This listener is essential for scenarios where agents need to communicate over the web, providing a robust and flexible means of data transmission.

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

Rotation rules

Rotation rules within the configuration are defined guidelines dictating when a listener's shellcode should alternate the host it connects to, or modify the HTTP host header within the request itself. This latter function is particularly useful for domain fronting, a technique employed to disguise the true destination of a web request.

Rule Type

This specifies the nature or category of the rotation rule. It determines the condition under which the rotation should occur, providing a contextual basis for the switch.

  • FAILOVER - With this kind of rule, the switch to next host or host header will happen if agent is failed it's connection to C2 for given set of tries or given set of time.
  • ROTATE - With this kind of rule, the switch to next host or host header will happen if agent is done (successful or not) given set of tries to connect to C2 or given set of time is passed.
  • RANDOM - The switch to next host or host header happens in random. With this type, the unit value is not important and before every connection to C2, the listener shellcode will "throw a dice" and decides to switch or not. The chance for switching is 1/counter

Rule unit

This element provides a unit of measurement for the numeric value, offering a scale or dimension to the rule. It contextualizes the numeric value, whether it's time-based, or count-based.

  • TRIES
  • SECONDS
  • MINUTES
  • HOURS

Rule examples

Switch to next happens after 7 request to C2, no matter if they succeed or not

  • type: ROTATE
  • counter: 7
  • unit: TRIES

Switch to next happens after 2 failed request to C2

  • type: FAILOVER
  • counter: 2
  • unit: TRIES

Switch to next happens when there has been 3 minutes since last successful request to C2

  • type: FAILOVER
  • counter: 3
  • unit: MINUTES

Switch to next happens when there has been 1 hour since last change

  • type: ROTATE
  • counter: 1
  • unit: HOURS

Before every request there is 12.5% (1/8) possibility that switch is made

  • type: RANDOM
  • counter: 8
  • unit: TRIES

Rotation logic

The rotation logic in our system follows a specific workflow diagram, designed to guide the decision-making process for when and how the listener shellcode should switch its connection host or modify the HTTP host header.

alt text

Rotation logic example 1

In this simple example, let's consider a scenario where an agent is configured to alternate between two IP addresses for connection attempts, and it utilizes three different host header names. The rotation logic for this setup could be described as follows.

"configuration": {
    "port": 8070,
    "httpCallbacks": [
      {
        "hosts": [
          "1.2.3.4",
          "5.6.7.8"
        ],
        "hostsRotation": {
          "type": "FAILOVER",
          "counter": 9,
          "unit": "TRIES"
        },
        "sleep": 10,
        "sleepRandom": 1,
        "hostHeaders": [
          "alpha",
          "bravo",
          "charlie"
        ],
        "hostHeaderRotation": {
          "type": "FAILOVER",
          "counter": 3,
          "unit": "TRIES"
        }
      }
    ],
    "fileStorageUri": "/files/",
    "getUri": "/ask_commands",
    "postUri": "/give_result",
    "metadataCookieName": "PHPSESSID",
    "metadataPrefix": "",
    "metadataSuffix": "",
    "https": true,
    "sleep": 10,
    "sleepRandom": 0,
    "headers": [
        { 
          "name": "Extra-Header-Name",
          "value": "Extra-Header-Value"
        }
      ]
}

How it works:

1 Agent starts with connection to IP 1.2.3.4 using host header "alpha"

2 If connection to C2 fails 3 times straight (because hostHeaderRotation has "FAILOVER" type with counter 3)

  • the host header "bravo" is now used
  • connection to 1.2.3.4 remains same because hostsRotation rule is not yet reached

3 If connection to C2 fails another 3 times straight (because hostHeaderRotation has "FAILOVER" type with counter 3)

  • the host header "charlie" is now used
  • connection to 1.2.3.4 still remains same because hostsRotation rule is still not yet reached

4 If connection to C2 fails another 3 times straight then 2 rules are reached - the hostsRotation and hostHeaderRotation. In such situation hostHeaderRotation is ignored

  • connection to 5.6.7.8 is now used
  • hostHeaderRotation counters are reset and first value "alpha" is now used

5 If connection to C2 fails another 3 times straight (because hostHeaderRotation has "FAILOVER" type with counter 3)

  • the host header "bravo" is now used
  • connection to 5.6.7.8 remains same because hostsRotation rule is not yet reached

6 If connection to C2 fails another 3 times straight (because hostHeaderRotation has "FAILOVER" type with counter 3)

  • the host header "charlie" is now used
  • connection to 5.6.7.8 still remains same because hostsRotation rule is still not yet reached

7 If connection to C2 fails yet another 3 times straight then 2 rules are again reached - the hostsRotation and hostHeaderRotation. Again hostHeaderRotation is ignored

  • connection to 1.2.3.4 is now used - circular selection
  • hostHeaderRotation counters are reset and first value "alpha" is now used

Extra notes

  • The counters for host rotation and hostHeader rotations operate independently. In this scenario, 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. This is because its counter resets after the successful connection. Similarly, the host header counters reset, but they are activated after every three consecutive failed connections. Consequently, in this specific case, the host header will have undergone three rotations, ultimately returning to the value "charlie."