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.
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
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.
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 Fuzzingpart: header
- Header Fuzzingpart: cookie
- Cookie Fuzzingpart: body
- Body FuzzingWhen 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.
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
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.
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 valuepostfix
- Add payload as a postfix to the valuereplace
- Replace the value with payloadinfix
- Add payload as an infix to the valuereplace-regex
- Replace the value with payload using regexNuclei now supports various input formats to load HTTP requests, and these can be grouped into two categories:
🗒️
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.
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[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
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 filters becomes crucial. Filters evaluate whether a specific fuzzing template should be activated for a particular HTTP request, ensuring targeted and effective fuzzing practices.
Filters 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:
- filters:
- 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.
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
- filters:
- 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 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
- filters:
- 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.
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:
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.
We would love to hear about your applications and the awesome templates you will build in our #showcase
discord channel 🚀 .
Happy Fuzzing!