Flow
Learn about the template flow engine in Nuclei v3
Overview
The template flow engine was introduced in nuclei v3, and brings two significant enhancements to Nuclei:
- The ability to conditionally execute requests
- The orchestration of request execution
These features are implemented using JavaScript (ECMAScript 5.1) via the goja backend.
Conditional Execution
Many times when writing complex templates we might need to add some extra checks (or conditional statements) before executing certain part of request.
An ideal example of this would be when bruteforcing wordpress login with default usernames and passwords, but if we carefully re-evaluate this template, we can see that template is sending 276 requests without even checking, if the url actually exists or target site is actually a wordpress site.
With addition of flow in Nuclei v3 we can re-write this template to first check if target is a wordpress site, if yes then bruteforce login with default credentials and this can be achieved by simply adding one line of content i.e flow: http(1) && http(2)
and nuclei will take care of everything else.
The update template now seems straight forward and easy to understand. we are first checking if target is a wordpress site and then executing bruteforce requests. This is just a simple example of conditional execution and flow accepts any Javascript (ECMAScript 5.1) expression/code so you are free to craft any conditional execution logic you want.
Request Execution Orchestration
Flow is a powerful Nuclei feature that provides enhanced orchestration capabilities for executing requests. The simplicity of conditional execution is just the beginning. With flow, you can:
- Iterate over a list of values and execute a request for each one
- Extract values from a request, iterate over them, and perform another request for each
- Get and set values within the template context (global variables)
- Write output to stdout for debugging purposes or based on specific conditions
- Introduce custom logic during template execution
- Use ECMAScript 5.1 JavaScript features to build and modify variables at runtime
- Update variables at runtime and use them in subsequent requests.
Think of request execution orchestration as a bridge between JavaScript and Nuclei, offering two-way interaction within a specific template.
Practical Example: Vhost Enumeration
To better illustrate the power of flow, let’s consider developing a template for vhost (virtual host) enumeration. This set of tasks typically requires writing a new tool from scratch. Here are the steps we need to follow:
- Retrieve the SSL certificate for the provided IP (using tlsx)
- Extract
subject_cn
(CN) from the certificate - Extract
subject_an
(SAN) from the certificate - Remove wildcard prefixes from the values obtained in the steps above
- Extract
- Bruteforce the request using all the domains found from the SSL request
You can utilize flow to simplify this task. The JavaScript code below orchestrates the vhost enumeration:
In this code, we’ve introduced 5 extra lines of JavaScript. This allows the template to perform vhost enumeration. The best part? You can run this at scale with all features of Nuclei, using supported inputs like ASN, CIDR, URL.
Let’s break down the JavaScript code:
ssl()
: This function executes the SSL request.template["ssl_domains"]
: Retrieves the value ofssl_domains
from the template context.iterate()
: Helper function that iterates over any value type while handling empty or null values.set("vhost", vhost)
: Creates a new variablevhost
in the template and assigns thevhost
variable’s value to it.http()
: This function conducts the HTTP request.
By understanding and taking advantage of Nuclei’s flow
, you can redefine the way you orchestrate request executions, making your templates much more powerful and efficient.
Here is working template for vhost enumeration using flow:
JS Bindings
This section contains a brief description of all nuclei JS bindings and their usage.
Protocol Execution Function
In nuclei, any listed protocol can be invoked or executed in JavaScript using the protocol_name()
format. For example, you can use http()
, dns()
, ssl()
, etc.
If you want to execute a specific request of a protocol (refer to nuclei-flow-dns for an example), it can be achieved by passing either:
- The index of that request in the protocol (e.g.,
dns(1)
,dns(2)
) - The ID of that request in the protocol (e.g.,
dns("extract-vps")
,http("probe-http")
)
For more advanced scenarios where multiple requests of a single protocol need to be executed, you can specify their index or ID one after the other (e.g., dns(“extract-vps”,“1”)).
This flexibility in using either index numbers or ID strings to call specific protocol requests provides controls for tailored execution, allowing you to build more complex and efficient workflows. more complex use cases multiple requests of a single protocol can be executed by just specifying their index or id one after another (ex: dns("extract-vps","1")
)
Iterate Helper Function
Iterate is a nuclei js helper function which can be used to iterate over any type of value like array, map, string, number while handling empty/nil values.
This is addon helper function from nuclei to omit boilerplate code of checking if value is empty or not and then iterating over it
Set Helper Function
When iterating over a values/array or some other use case we might want to invoke a request with custom/given value and this can be achieved by using set()
helper function. When invoked/called it adds given variable to template context (global variables) and that value is used during execution of request/protocol. the format of set()
is set("variable_name",value)
ex: set("username","admin")
.
Note: In above example we used set("vhost", vhost)
which added vhost
to template context (global variables) and then called http(1)
which used this value in request.
Template Context
A template context is nothing but a map/jsonl containing all this data along with internal/unexported data that is only available at runtime (ex: extracted values from previous requests, variables added using set()
etc). This template context is available in javascript as template
variable and can be used to access any data from it. ex: template["dns_cname"]
, template["ssl_subject_cn"]
etc.
Lot of times we don’t known what all data is available in template context and this can be easily found by printing it to stdout using log()
function
Log Helper Function
It is a nuclei js alternative to console.log
and this pretty prints map data in readable format
Note: This should be used for debugging purposed only as this prints data to stdout
Dedupe
Lot of times just having arrays/slices is not enough and we might need to remove duplicate variables . for example in earlier vhost enumeration we did not remove any duplicates as there is always a chance of duplicate values in ssl_subject_cn
and ssl_subject_an
and this can be achieved by using dedupe()
object. This is nuclei js helper function to abstract away boilerplate code of removing duplicates from array/slice
And that’s it, this automatically converts any slice/array to map and removes duplicates from it and returns a slice/array of unique values
Similar to DSL helper functions . we can either use built in functions available with
Javscript (ECMAScript 5.1)
or use DSL helper functions and its upto user to decide which one to uses.
Skip Internal Matchers in MultiProtocol / Flow Templates
Before nuclei v3.1.4 , A template like CVE-2023-43177
which has multiple requests/protocols and uses flow
for logic, used to only return one result but it conflicted with logic when for
loop was used in flow
to fix this nuclei engine from v3.1.4 will print all events/results in a template and template writers can use internal: true
in matchers to skip printing of events/results just like dynamic extractors.
Note: this is only relevant if matchers/extractors are used in previous requests/protocols
Example of CVE-2023-6553
with new internal: true
logic would be
Was this page helpful?