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

The decoy section defines what should be considered for injection and for detection. It typically consists in a single key or in a key/value pair. The decoy section is mandatory for any defined decoy.

Here is an example of a basic decoy:

"decoy": {
  "key": "x-cloud-active-defense",
  "separator": "=",
  "value": "ACTIVE"
}

This decoy should be understood as a key/value pair, which shall be injected or detected as x-cloud-active-defense=ACTIVE.

Key

The key defines what will be sought as parameter or as plain element. Typically, when bound to a value, the key will be an HTTP header name, a cookie name, a FORM parameter name or a json parameter name. But it can also be used as a url path, or as any text within a page. It is mandatory to have a key, unless you have a dynamicKey.

Value

The value defines what will be injected as parameter value, and what will be considered as the reference value during detection. Typically, you will inject a certain value, and alert if that reference value was modified.

Separator

The separator defines the key/value separator. If absent from the config, it is set to an equal sign. This separator is used to instruct cloud active defense on how to parse the request during the detect phase. You won't need to change this value except for certain advanced cases, such as this one:

"decoy": {
  "key": "username=admin",
  "separator": "&",
  "value": "password=admin"
}

This decoy can be used to detect, when someone is trying to log in, whether the specified username and password are both set to 'admin'. If you want to simply detect if someone tries to login as 'admin', you'll rather use this decoy:

"decoy": {
  "key": "username",
  "separator": "=",
  "value": "admin"
}

String

The string element offers more freedom in what to inject. Imagine that we want to add a 'hidden' form field in the 'login' page of our demo application. The page looks like this:

<html><head></head><body><h1>Login</h1>
    <form method="POST">
      <input type="text" name="username" placeholder="Username">
      <input type="password" name="password" placeholder="Password">
      <button type="submit">Sign In</button>
    </form>
  </body></html>

We want to turn it into this:

<html><head></head><body><h1>Login</h1>
    <form method="POST">
      <input type="text" name="username" placeholder="Username">
      <input type="password" name="password" placeholder="Password">
      <input type="hidden" name="system" value="2">
      <button type="submit">Sign In</button>
    </form>
  </body></html>

Whenever a user will press the 'login' button, the request will be sent to the POST /login endpoint, with the following payload:

username=foo&password=bar&system=2

We want to detect this system=2 key/value in the POST request and alert if the value (2) was changed to something else. We thus define this decoy:

"decoy": {
  "key": "system",
  "separator": "=",
  "value": "2",
}

However, while this will work fine for detection, when injecting into the GET /login page, our code will look like this garbled code:

<html><head></head><body><h1>Login</h1>
    <form method="POST">
      <input type="text" name="username" placeholder="Username">
      <input type="password" name="password" placeholder="Password">system=2
      <button type="submit">Sign In</button>
    </form>
  </body></html>

To solve this issue, we introduced the string parameter. String defines what will be injected. The content can be arbitrary. It supports \n characters and will be rendered as-is.

Consider this new version of the decoy:

"decoy": {
  "key": "system",
  "separator": "=",
  "value": "2",
  "string": "<input type=\"hidden\" name=\"system\" value=\"2\">\n      "
}

Upon receiving the response to a GET /login request, the string will be injected, leading to properly rendered HTML code. Note how we injected a carriage return as well as several spaces to preserve the layout of the HTML code.

The string is used only as the content to inject. For detection, the key, separator and value will be considered. It's up to you to make sure that whatever you inject in the string matches to what should be detected.

dynamicValue

The dynamicValue can be used instead of the value. You can only have one of these, not both at the same time. The dynamic value behaves exactly like a value, except that its content will be treated as a regular expression.

"decoy": {
  "key": "country",
  "separator": "=",
  "dynamicValue": "[A-Z]{3}"
}

If you try to inject this decoy, a random string composed of 3 uppercase letters will be generated and sent. Note that every injection will have a newly generated value. If you always want to inject the same value, you can combine this decoy with the string feature.

Upon detection, you will be able to detect whether the received value violates the regular expression, such as if you receive an SQL injection payload instead of 3 uppercase letters. However, you won't be able to notice if, for example, the value was changed from ABC to DEF.

A dynamic value can be useful in case you don't inject the decoy, but only detect violation. If your UI expects the user to only enter 3 uppercase characters for the country, and that you receive something else, you are 100% sure that the client-side validation was bypassed.

dynamicKey

Finally, the dynamicKey can be used instead of the key. It is mandatory to have either a key or a dynamicKey, and only one of them should be present.

The dynamic key behaves exactly like a key, except that its content will be treated as a regular expression. It can be useful to put variety in what you inject, for example, as a random URL GUID. As a detection mechanism, it can help detect violations, for example if you expect a URL to contain a certain GUID and if you receive an attempt at a path traversal.

05-decoy.mp4
Clone this wiki locally