Back to Tsunami Security Scanner

Writing the first actions

docs/howto/new-detector/templated/03-first-actions.md

0.2.03.0 KB
Original Source

Writing the first actions

Each action is defined by a name and a subtype. A subtype defines what the action is able to do: For example "HTTP request" is a subtype that allows to send an HTTP request and inspect responses.

Let's start building our fingerprinting step with a very simple action:

proto
actions: {
  name: "fingerprinting"
  http_request: {
    method: GET
    uri: "/version"
  }
}

In that action, named fingerprinting we simply send a GET HTTP request to /version on the currently targeted service.

Note that Tsunami will only send HTTP requests to services that have been identified as HTTP services during the port scanning phase.

But that action will always succeed because it does not verify anything in the response. Let's use the response field and add a condition on the status code:

proto
actions: {
  name: "fingerprinting"
  http_request: {
    method: GET
    uri: "/version"
    response: {
      http_status: 200
    }
  }
}

Now we want to ensure the header contains MyVulnerableApp: we need to use expectations. We can either use expect_all or expect_any, which perform checks on the response that must respectively "all be true" or "at least one true". Here, we have only one expectation, so we will use expect_all with one conditions:

proto
actions: {
  name: "fingerprinting"
  http_request: {
    method: GET
    uri: "/version"
    response: {
      http_status: 200
      expect_all: {
        conditions: [
          { header: { name: "Server" } contains: "MyVulnerableApp" }
        ]
      }
    }
  }
}

The condition is that the header with name Server contains the string MyVulnerableApp.

Now, let's build a POST request for our exploitation step:

proto
actions: {
  name: "exploitation"
  http_request: {
    method: POST
    uri: "/exploit"
    data: "process=%{ print(\"tsunami_%d_marker\", 1250*1+3) }%"
    response: {
      http_status: 200
      expect_all: {
        conditions: [
          { body: {} contains: "tsunami_1253_marker" }
        ]
      }
    }
  }
}

This action is very similar to the previous one but:

  • It sends a POST request instead of a GET one;
  • As part of the POST it sends process=%{ print(\"tsunami_%d_marker\", 1250*1+3) }% as data;
  • The expectation has been changed to check that the response body contains tsunami_1253_marker.

Redirects

Note that by default, the HTTP client will follow any HTTP redirects. If you wish to change that behavior, you can configure your HTTP request using the client_options stanza. For example, with our previous request:

proto
actions: {
  name: "exploitation"
  http_request: {
    method: POST
    uri: "/exploit"
    data: "process=%{ print(\"tsunami_%d_marker\", 1250*1+3) }%"
    client_options: {
      disable_follow_redirects: true
    }
    response: {
      http_status: 200
      expect_all: {
        conditions: [
          { body: {} contains: "tsunami_1253_marker" }
        ]
      }
    }
  }
}

What is next

Putting it together in workflows