Fuzzing for Unknown Vulnerabilities with Nuclei v3.2

Fuzzing for Unknown Vulnerabilities with Nuclei v3.2

At ProjectDiscovery, our goal is to democratize security. Nuclei, our flagship project, plays a pivotal role in achieving this by offering a fast, adaptable, and potent vulnerability scanner, powered by the innovative nuclei-templates. The launch of Nuclei v3.0 was a significant step, incorporating comprehensive capabilities for developing checks against Common Vulnerabilities and Exposures (CVEs). Earlier, with Nuclei v2.8.0, we ventured into Query Fuzzing.

Overview

Nuclei v3.2.0 represents a crucial advancement in fuzzing capabilities. This version introduces complete support for crafting fuzzing templates, covering everything from importing HTTP Traffic from tools like Proxify, httpx, and Burp Suite to generating requests from API schema files like OpenAPI and Swagger. Let’s explore the fuzzing enhancements in Nuclei v3.2.0 in greater detail!

nuclei -l fuzzplayground-proxify.yaml -im yaml -t fuzz/

                     __ _
   ____ __ _______/ /__ (_)
  / __ \/ / / / ___/ / _ \/ /
 / / / / /_/ / /__/ / __/ /
/_/ /_/\__,_/\___/_/\___/_/ v3.2.0-dev

        projectdiscovery.io

[INF] Current nuclei version: v3.2.0 (latest)
[INF] Current nuclei-templates version: v9.7.7 (latest)
[WRN] Scan results upload to cloud is disabled.
[INF] New templates added in latest release: 82
[INF] Templates loaded for current scan: 14
[WRN] Executing 15 unsigned templates. Use with caution.
[INF] Targets loaded for current scan: 9
[fuzz-query-num] [http] [info] http://127.0.0.1:8082/blog/post?postId=200&source=proxify
[fuzz-body-generic] [http] [info] http://127.0.0.1:8082/user
[body-params-error-sqli] [http] [info] http://127.0.0.1:8082/user       
[path-based-sqli] [http] [info] http://127.0.0.1:8082/user/55%2520OR%2520True/profile
[fuzz-body-generic] [http] [info] http://127.0.0.1:8082/user
[fuzz-query-num] [http] [info] http://127.0.0.1:8082/blog/post?postId=201&source=proxify
[fuzz-body-generic] [http] [info] http://127.0.0.1:8082/user
[body-multipart-error-sqli] [http] [info] http://127.0.0.1:8082/user
[fuzz-body-generic] [http] [info] http://127.0.0.1:8082/user
[cookie-fuzzing-error-sqli] [http] [info] http://127.0.0.1:8082/blog/posts
[host-header-injection] [http] [info] http://127.0.0.1:8082/host-header-lab

What is Fuzzing?

Fuzzing is a technique for uncovering unknown or yet-to-be-discovered vulnerabilities within an application by employing established strategies and methodologies, often referred to as rules. These rules are systematically applied to different components of HTTP requests to detect alterations in the application's response or behavior.

Fuzzing Parts

Supported Fuzzing Parts

As mentioned earlier, fuzzing rules are applied to various parts of HTTP requests. We call these parts part: in Nuclei templates; with the release of Nuclei v2.8.0, we introduced support for Query Fuzzing (part: Query), but with this release, we have added support for all other parts of HTTP requests along with abstractions. Here is the list of supported parts in Nuclei v3.2.0:

  • part: query - Query Fuzzing (Introduced in Nuclei v2.8.0)
  • part: path - Path Fuzzing
  • part: header - Header Fuzzing
  • part: cookie - Cookie Fuzzing
  • part: body - Body Fuzzing

When writing fuzzing rules, each rule is scoped to a specific part of the HTTP request. This means that a rule written for part: Query will only be applied to the query parameters of the HTTP request and not to any other part of the request.

HTTP Request Part Values

While Query, Path, Header, and Cookie are only represented in a fixed format in HTTP requests, Body is represented in various formats such as JSON, XML, Form, multipart-form data, etc. Usually, when writing templates for fuzzing, the rules would need to be written for each format separately, which would be a tedious task and include duplicate rules. To solve this problem,

Nuclei Abstracts Values of Every Part as a Key-Value Pair

Example HTTP request & parts

In the below example HTTP request, the key-value pairs of each part would be as follows:

POST /reset-password?token=x0x0x0&source=app HTTP/1.1
Host: 127.0.0.1:8082
User-Agent: Go-http-client/1.1
Cookie: PHPSESSID=1234567890
Content-Length: 23
Content-Type: application/json
Accept-Encoding: gzip
Connection: close

{"password":"12345678"}

part: query

key value
token x0x0x0
source app

part: path

key value
value /reset-password

part: header

key value
Host 127.0.0.1:8082
User-Agent Go-http-client/1.1
Content-Length 23
Content-Type application/json
Accept-Encoding gzip
Connection close

part: cookie

key value
PHPSESSID 1234567890

part: body

key value
password 12345678
🗒️
Note: XML, JSON, form, multipart-form data will be in key/value format, but if the body is binary or in any other format, the entire Body will be represented as a single key-value pair with key as `value` and value as the entire Body.

value \x08\x96\x01\x12\x07\x74

This abstraction significantly enhances efficiency, as it allows for the creation of a single rule for the Body that applies across all formats. For instance, when testing for SQL injection vulnerabilities in body values, a solitary rule can be effectively utilized for various formats, including JSON, XML, form, and multipart-form data. This streamlined approach simplifies the testing process and broadens the scope of vulnerability detection.

Fuzzing Rule Types

Each rule performs a specific action on the value, and nuclei supports the following types of rules:

  • prefix - Add payload as a prefix to the value
  • postfix - Add payload as a postfix to the value
  • replace - Replace the value with payload
  • infix - Add payload as an infix to the value
  • replace-regex - Replace the value with payload using regex

Loading HTTP Traffic

Nuclei now supports various input formats to load HTTP requests, and these can be grouped into two categories:

HTTP Traffic From Tools

Generating Requests from API Schema Files

  • OpenAPI
  • Swagger
  • Postman (via OpenAPI)
🗒️
Note: Since OpenAPI is a standard for describing RESTful APIs, other formats and tools like Postman can be exported to OpenAPI directly via the Client App or by using popular utility tools for conversion.

Providing HTTP Input to Nuclei

Files of the above formats can be provided to the existing flag -l -list along with the new flag -im -input-mode to specify the input mode or format of the file. Example:

$ nuclei -l ginandjuice. proxify.jsonl -im jsonl
$  ./nuclei -h target-format
Nuclei is a fast, template based vulnerability scanner focusing
on extensive configurability, massive extensibility and ease of use.

Usage:
  ./nuclei [flags]

Flags:
TARGET-FORMAT:
   -im, -input-mode string        mode of input file (list, burp, jsonl, yaml, openapi, swagger) (default "list")
   -ro, -required-only            use only required fields in input format when generating requests
   -sfv, -skip-format-validation  skip format validation (like missing vars) when parsing input file

Nuclei also enhances request generation with new options: use -V flag to override/pass variables, choose between essential or all fields for requests, and skip format validation for testing with dedicated flags.

Fuzzing Rule Format

Fuzzing rule[s] are written in the HTTP protocol section under fuzzing key. Here is a general format for writing a fuzzing rule:

http:
    ...
    payloads:
      injection:          # Variable name for payload
        - "'"
        ...
    fuzzing:
      - part: query       # One of query, path, header, cookie, body
        type: postfix     # Type of rule (prefix, postfix, replace, infix,replace-regex)
        mode: single      # mutation mode (single, multiple) (ex: replace all existing kv pairs at once or one by one)
        # replace-regex: # (optional) regex to be used in replace-regex type
        # keys-regex: # (optional) limit this rule to specific keys of the request part using regex
        # keys: # (optional) limit this rule to specific keys of request part
        # values: # (optional) limit this rule to specific values of the request part using regex
        fuzz:
          - '{{injection}}' # The payload to be injected

Pre-Condition

With Nuclei now supporting a wide range of input formats and rules for all segments of HTTP requests, it might seem that crafting any rule is straightforward. However, there's a significant aspect to consider: the challenge of managing request volume or noise. Specifically, when conducting fuzzing on targets protected by Web Application Firewalls (WAF), indiscriminate fuzzing can lead to issues such as IP bans. The most efficient strategy to mitigate this concern is to employ fuzzing judiciously, which is where the role of pre condition becomes crucial, it evaluate whether a specific fuzzing template should be activated for a particular HTTP request, ensuring targeted and effective fuzzing practices.

pre-condition can be considered a twin of matchers in nuclei templates. They support all matcher types, including DSL, and the only difference here is the purpose of each.

🗒️
Note: Currently, Only request data like header, host, input, method, path, etc is available, but soon, response data will be available once the support for loading the response along with the request is added.

Here's a basic filter to only execute this template if the request is POST and must have some body:

  - pre-condition:
      - type: dsl
        dsl:
          - method == POST
          - len(body) > 0
        condition: and
💡
TIP: When writing/executing a template, you can use the -v -svd flags to see all variables available in filters before applying the filter.

Example Templates

Error Based SQLi in Body

The following template is configured to run on all requests that use the POST method and have a non-empty body. It appends the specified payload as a postfix to every value within the body.

http:
    # filter checks if the template should be executed on a given request
  - pre-condition:
      - type: dsl
        dsl:
          - method == POST
          - len(body) > 0
        condition: and
    # payloads that will be used in fuzzing
    payloads:
      injection: # Variable name for payload
        - "'"
        - "\""
        - ";"
    # fuzzing rules
    fuzzing:
      - part: body  # This rule will be applied to the Body
        type: postfix # postfix type of rule (i.e., payload will be added at the end of exiting value)
        mode: single  # single mode (i.e., existing values will be replaced one at a time)
        fuzz:         # format of payload to be injected
          - '{{injection}}' # here, we are directly using the value of the injection variable

For the complete template, see body-error-sqli.yaml

Host Header Injection

Host Header Injection is a vulnerability where an attacker injects a malicious host header, often exploited through techniques like HTTP Request Smuggling or Reset Password Poisoning. The template described aims to exploit this vulnerability by tampering with the host header in reset password requests, redirecting them via updated Proxy Headers to a server under the attacker's control.

http:
    # filter to determine if the template should be executed
  - pre-condition:
      - type: dsl
        dsl:
          - 'method == "POST"'       # only run if method is POST
          - 'contains(path,"reset")' # only run if path contains reset word
        condition: and
    # fuzzing rules
    fuzzing:
      - part: header # This rule will be applied to the header
        type: replace # replace the type of rule (i.e., existing values will be replaced with payload)
        mode: multiple # multiple mode (i.e., all existing values will be replaced/used at once)
        fuzz:
          X-Forwarded-For: "{{domain}}"  # here {{domain}} is attacker-controlled server
          X-Forwarded-Host: "{{domain}}"
          Forwarded: "{{domain}}"
          X-Real-IP: "{{domain}}"
          X-Original-URL: "{{domain}}"
          X-Rewrite-URL: "{{domain}}"
          Host: "{{domain}}"

A difference to note here compared to the previous template is that we are not directly using payloads and specifying key/value pairs in fuzzing. This is because we attempt to add or replace multiple headers specified under the fuzz key in HTTP requests instead of updating the value.

💡
TIP: When writing a fuzzing template, if you want to add a new key-value pair instead of updating existing values, you should specify the key-value pair under the fuzz key in the HTTP request, as shown in the above example.

Learn More

You can read the updated documentation on fuzzing here!

Along with support for scanning targets behind, Nuclei v3.2.0 also includes a number of major enhancements:

Conclusion

Nuclei v3.2 represents a significant advancement in fuzzing capabilities, incorporating essential features that enable you to create custom fuzzing templates. Additionally, we've introduced the ability to import HTTP traffic from a range of tools and generate requests based on API schema files. We believe these enhancements will prove invaluable, and we eagerly anticipate witnessing the innovative ways you utilize them.

Join our Discord to share your thoughts!

We would love to hear about your applications and the awesome templates you will build in our #showcase discord channel 🚀 .

Happy Fuzzing!

Subscribe to our newsletter and stay updated.

Don't miss anything. Get all the latest posts delivered straight to your inbox. It's free!
Great! Check your inbox and click the link to confirm your subscription.
Error! Please enter a valid email address!
--