Skip to content
TarradeMarc edited this page Jul 10, 2024 · 10 revisions

The detect section defines where decoy interaction should be sought and how to alert when interaction has been detected. The detect section is optional. You may want to skip it to inject decoys which are simply meant to confuse adversaries. You might for example overwrite the value of a status banner with something else, for example pretending that your server is running Apache where it is running IIS and let attackers waste time trying incompatible attacks. In the default configuration, we inject a header x-cloud-active-defense=ACTIVE. We do this so that you can see that the proxy is doing something. Of course you can remove this decoy, but leaving it there has an advantage: since attackers will see it, they might (rightly so, hopefully) suppose that your application is protected with deceptive elements. This will have a psychological effect as from then on, every parameter will look like a potential trap to avoid...

But back to the topic. Here an example of a typical detect section:

"detect": {
  "seek": {
    "inRequest": ".*",
    "withVerb": "GET",
    "in": "url"
  }
}

This detection must be understood as: "search for the decoy key in the url (path) of every GET request received from the user".

detect has two parts: seek and alert. The options for seek are the following:

seek

inRequest

Searches for the presence of the decoy key in the received request. The value is the url path of the request which should be matched. This value is treated as a regular expression.

inResponse

Instead of searching for the decoy key in the request, it is possible to search for the presence of the decoy in the returned response. This is useful if for example you store a certain (invalid) entry in /etc/shadow (this has to be done manually, cloud active defense cannot (and should not) modify existing files). Let's say that someone manages to display the content of /etc/shadow by exploiting a path traversal vulnerability. If you see the invalid entry in the response, you know that someone managed to exfiltrate your /etc/shadow file.

Please note that the usefulness of detecting a decoy in a response is limited. If the attacker manages to encode the result before displaying it, of if the attacker manages to extract the content character by character, or if you monitor the wrong URL, then you may not notice the attack. Still, this feature exists, and you might be more creative than us in how to make the best use of it :)

withVerb

Filters requests to scan to only the selected operations. If not specified, all verbs will be considered. Can be set to any verb, but will mostly be useful if set to one of GET, POST, PUT and DELETE.

in

Specifies where to search. Supported values are: cookie, header, url, getParam, postParam and payload. Please note that since headers can be sent differently depending on browsers and servers (e.g. Content-Type vs content-type), we convert all names to lowercase. As such, use only lowercase for your detection keys for headers.

Envoy supports pseudo-headers, these can be used for detection as any other headers. These include:

  • :status : the returned status code (200, 404...)
  • :path : the URL path (equivalent to using the url type)
  • :method : the requested verb

payload vs postParam

If you expect POST parameters, it is more efficient to search in postParam specifically rather than in payload. Searching in payload will work, but will be less efficient. Also, if you use payload, the injected value won't show up in the alert (this is due to a technical limitation that we then don't have a clear terminator for the value).

06-detect.mp4

alert

Let's complete our example with a typical alert section:

"detect": {
  "seek": {
    "inRequest": ".*",
    "withVerb": "GET",
    "in": "url"
  },
  "alert": {
    "severity": "LOW",
    "whenModified": true
  }
}

Whenever the key of the decoy is found, the different alert rules will be reviewed. Upon a match, a security alert will be sent to the console. The format of these alerts is detailed in the Alert section.

severity

Can be one of: LOW, MEDIUM, HIGH. This is just displayed as-is on the console, without further side effect. We recommend using the severity values according to the following use-cases:

  • if the decoy can be triggered by accident (e.g. via a botched copy-paste) or if the decoy is Internet-facing and does not require any authentication to be triggered, then it should be assigned LOW severity (you'll want to avoid creating such decoys as you may be swamped with alerts - it might be useful to detect and ban automatic scanners, though)
  • on the contrary, if the user needs to be authenticated before being able to trigger the decoy (we call these post-authentication decoys), then the detection should be assigned to a HIGH severity (ideally you'll never see HIGH severity alerts, but when you do, you know you have an urgent problem)
  • last, the MEDIUM priority can be assigned to pre-authentication decoys which require non-trivial operations to be triggered (for example: you hide a hardcoded URL into the comment section of an obscure javascript file used by your application and detect someone visiting that URL, or in a FORM field requiring a valid email address you detect something which violates the client-side validation). It can also be assigned to post-authentication decoys which could possibly be a false positive (for example, a request to a forbidden path automatically triggered by a Firefox extension)

whenModified

Can be set to false (default) or to true. An alert will be raised in the following case:

  • the decoy key was found
  • the decoy value was found
  • the received value is different from the value initially set

This is probably your most typical use-case: you inject a cookie, or a form field, and you get another value back. This option can be used to detect probing, which is a typical active reconnaissance activity.

whenComplete

Can be set to false (default) or to true. This is the pendant to whenModified. An alert will be raised in the following case:

  • the decoy key was found
  • the decoy value was found
  • the received value is the same as the one set initially

The typical use of this feature is for pure detection decoys (e.g. decoys without an inject section) and can be used for example to detect if someone tries to login as admin/admin. It can also be used in a more standard way: for example, you may inject in a HTML comment some instructions pretending to be coming from the developer, and "accidentally leaking", such as a username/password combination or a hidden backdoor feature in the form of a specific user-agent or header to use.

whenSeen

Can be set to false (default) or to true. An alert will be raised in the following case:

  • the decoy key was found

This use-case is similar to the one of the whenComplete, except that it only considers the key. It is useful if what you inject is not in a key=value format. Can be used to detect leakage of a preset value set in the database or in /etc/shadow. Can be used to detect the visit of an endpoint path injected in a comment or in unused javascript code. Can be used to detect JSON injection attacks (for example to detect that a request expecting a JSON payload containing a user id and an email also contains a 'role' parameter)

whenAbsent

Can be set to false (default) or to true. An alert will be raised in the following case:

  • the decoy key was not found

This use-case can be used to detect the absence of a parameter which is required by the UI but was obviously removed by the attacker (such as the 'password' field in an attempt to trigger an access control bypass).

07-alert.mp4

respond

Let's further add a typical respond section:

"detect": {
  "seek": {
    "inRequest": ".*",
    "withVerb": "GET",
    "in": "url"
  },
  "alert": {
    "severity": "LOW",
    "whenModified": true
  },
  "respond": [{
    "source": "ip,userAgent",
    "behavior": "throttle",
    "property": "3-7",
    "delay": "120s",
    "duration": "24h"
  }]
}

Whenever the key of the decoy is found, the different respond rules will be reviewed. Upon a match, a respond event will be sent to the console. The format of these events is detailed in the Respond section. The proxy will further enforce the corresponding response upon receiving future matching requests (e.g. matching in the specified combination of IP address, user agent and session token)

It is possible to configure a global responses in the config-default.json file. If a 'respond' section is configured in the decoy, then this response will be enforced instead of the global one. For details, please refer to the general Respond section. The format of a global response is the same as for a decoy:

"respond": [{
  "source": "ip,userAgent",
  "behavior": "throttle",
  "property": "3-7",
  "delay": "120s",
  "duration": "24h"
}]

Please note that the 'respond' section is an array, as it can be useful to set different responses depending on the available information. One might want to divert based on the session value, and to throttle based on IP and user agent value, for example.

source

Can be one of: "ip", "userAgent", "session", "ip,userAgent", "ip,session", "userAgent,session", "ip,userAgent,session". Defines what to look for in subsequent request(s). This field is mandatory.

ip

The response behavior will be applied to alls requests coming from the specified IP address. Can be effective to catch different tools used by the same attacker on the same machine (e.g. one web browser and one python script used in parallel). Can lead to false positives if the attacker is behind a proxy also used by legitimate users (such as a corporate proxy). The response may be escaped by attacking from another machine or through a different VPN.

userAgent

The response behavior will be applied to alls requests coming from the specified user agent. Can be effective to catch attackers when using the IP address is ill-advised. Can lead to false positives if the user agent is a popular one, also used by legitimate users. The response can be escaped by using another browser or by spoofing the user agent.

session

The response behavior will be applied to alls requests coming with the specified session token. This is the most effective way to catch the attacker and not anyone else. In theory, cannot lead to false positives as session tokens are supposed to be unique. Requires the attacker to already be authenticated. Can be escaped by logging out and logging in again as this will change the session token.

ip,userAgent

The response behavior will be applied to alls requests coming from the specified IP / user agent combination. Avoids most of the false positives issues with 'ip' and 'userAgent' single options, as now the only risk is to catch a legitimate user behind the same proxy and using the exact same browser version. Can be escaped by using a second browser or by attacking through a VPN with a different IP address.

ip,session

The response behavior will be applied to alls requests coming from the specified IP / session combination. If the session token is unique, this does not add anything to catching only on 'session'. May even be inferior if the attacker switched VPN address and resumes with the active session. This option is offered to support applications where session tokens are not unique.

userAgent,session

The response behavior will be applied to alls requests coming from the specified user agent / session combination. If the session token is unique, this does not add anything to catching only on 'session'. May even be inferior if the attacker copies the active session token to a secondary tool such as a python script. This option is offered to support applications where session tokens are not unique.

ip,userAgent,session

The response behavior will be applied to alls requests coming from the specified ip / user agent / session combination. If the session token is unique, this does not add anything to catching only on 'session'. Comes with the drawbacks of the "ip,session" and "userAgent,session" options. This option is offered to support applications where session tokens are not unique.

behavior

Can be one of: divert, error, drop, throttle. What will happen to requests matching with what is specified in the source field. This field is mandatory.

divert (experimental)

The matching requests will be re-routed to another application, either the 'clone' or the 'exhaust'. This feature is experimental. In the demo mode, the user will be shown a page telling 'Clone' or 'Exhaust' instead of 'Welcome'. This diversion can be used to redirect the attacker to a honeypot mimicking the real application.

All diverted requests are by essence malicious and should thus be logged with maximal verbosity, including POST parameters, including submitted passwords. An attacker may try each and every collected credential to see which ones work, logging them is your chance to determine which credentials were successfully stolen.

For more details, refer to the Divert section.

error (experimental)

The matching requests will be replied with an Error 500 response, mimicking a server error. Currently there is no way to customize this response message, meaning that an attacker may realize that the answer is a fake one.

Can be an effective response, especially coupled with throttling, to pretend that the application is not reachable anymore.

drop

The matching requests will be dropped by the proxy, meaning that they will eventually time out on the client side. Can be an effective response, to pretend that the application is not responding anymore.

throttle

The matching requests will be throttled, meaning that the proxy will wait a specified amount of time before replying back. The attacker may believe that the application is under heavy load.

Can be an effective response, especially coupled with error, to pretend that the application is not reachable anymore. Can also be used to slow-down probing.

property

property is a value aimed at tuning the response option. At the moment, property is only taken into account if the response is set to "throttle". Property can be in the form of an integer, specifying the number of seconds to wait, or in the form of two integers separated by a '-' sign, specifying a range of seconds to wait, chosen at random. '3' will throttle all requests by 3 seconds. '0-5' will throttle all requests by a number of seconds which can range from 0 (no throttling for that request) to 5 seconds. If not specified, the default throttling will be "30-120".

delay

Can be one of: "now", "XXs", "YYm", "ZZh". The number of seconds / minutes / hours to wait before applying the response. It is useful to set a delay so that the attacker cannot easily understand which action lead to detection. This can be defeated by the attacker if several minutes are spent between each request, but this dramatically slows down attacks, which is good for defense. It is also possible to set more than one response with different delays, for a gradual response (for example: throttle after one minute, reply with a 500 error message after 3 minutes). If not specified, the delay will be set to "now" (zero second).

duration

Can be one of: "XXs", "YYm", "ZZh", "forever". The number of seconds / minutes / hours the response will be applied before expiring. It is useful to set a duration to avoid clogging the block list (as IP addresses and user agents tend to change over time). Can also be a way to deal with false positives. If not specified, the duration will be set to "forever" (never expires).

08-respond.mp4