XSS (Cross-Site Scripting) detection has long been a challenge, balancing accuracy with avoiding excessive false positives. Traditionally, this meant creating specific reflection based string matchers for each target, leading to complex and hard-to-maintain configurations. But with headless modes, we can simplify and improve XSS detection in a more intuitive and efficient way.
In this post, we'll explore how to leverage nuclei headless mode to detect XSS payloads more easily and accurately, using the waitdialog
action. This approach significantly reduces the complexity of matching specific server responses, while maintaining high accuracy.
For those who've worked with XSS detection templates, the complexity of configuring specific matchers
for every scenario is all too familiar. It becomes especially cumbersome when analyzing unique technologies or servers. Often, security engineers have to conduct additional research, using tools like Shodan or setting up vulnerable environments to fine-tune their matchers. While this approach improves accuracy and reduces false positives, it places a heavy burden on the user.
For example, look at the following template snippet:
matchers-condition: and
matchers:
- type: word
part: body
words:
- 'topic_id: "</script><script>alert(document.domain)</script>'
- "window.erxesEnv"
condition: and
In this method, specific keywords in the response body are used to check if the injected script is reflected (although this doesn’t guarantee that the payload will actually be triggered). This approach requires detailed knowledge of the target's structure and can easily fail if the structure changes - even a little.
Nuclei's headless mode lets us mimic real user actions on a web page, including running JavaScript. This opens up a new way to detect XSS: instead of just looking for specific HTML output or script tags, we can check if an XSS payload actually triggers a JavaScript dialog (like alert
).
The waitdialog
action listens for these dialogs on a page, showing us clearly if an XSS payload has been executed. This method simplifies detection by focusing on the behavior of the payload rather than the page's source code.
Let's take a look at how we can implement this in practice.
Before headless mode, detecting XSS relied heavily on matchers, as seen below:
id: CVE-2021-32853
# ... SNIPPED ...
http:
- method: GET
path:
- "{{BaseURL}}/widgets/knowledgebase?topicId=%3C%2Fscript%3E%3Cscript%3Ealert%283%2B4%29%3C%2Fscript%3E"
matchers-condition: and
matchers:
- type: word
part: body
words:
- 'topic_id: "</script><script>alert(3+4)</script>'
- "window.erxesEnv"
condition: and
- type: word
part: header
words:
- text/html
- type: status
status:
- 200
In this older method, you had to define the HTTP headers and exact patterns to match the payload. While it works, the setup is more complicated because you need to create separate matchers
for each different environment.
With headless mode, we can simplify this process by detecting the JavaScript execution directly:
id: CVE-2021-32853
# ... SNIPPED ...
headless:
- steps:
- args:
url: "{{BaseURL}}/widgets/knowledgebase?topicId=%3C%2Fscript%3E%3Cscript%3Ealert%283%2B4%29%3C%2Fscript%3E"
action: navigate
- action: waitdialog
name: reflected_topicId_query
matchers:
- type: dsl
dsl:
- reflected_topicId_query == true
- reflected_topicId_query_message == "7" # 3+4
condition: and
Here, instead of searching for specific HTML content or headers, we use the waitdialog
action to wait for a JavaScript dialog to pop up. If the dialog gets triggered, the matcher checks if it matches the expected result (like alert(3+4)
).
💡
The waitdialog
action has been available since Nuclei v3.3.2 (bump now!), and you can refer to the documentation for more details on its usage.
$ nuclei -t headless-xss.yaml -target https://erxes.xss -headless
__ _
____ __ _______/ /__ (_)
/ __ \/ / / / ___/ / _ \/ /
/ / / / /_/ / /__/ / __/ /
/_/ /_/\__,_/\___/_/\___/_/ v3.3.2
projectdiscovery.io
[INF] Current nuclei version: v3.3.2 (latest)
[INF] Current nuclei-templates version: v9.9.4 (latest)
[WRN] Scan results upload to cloud is disabled.
[INF] New templates added in latest release: 59
[INF] Templates loaded for current scan: 1
[WRN] Loading 1 unsigned templates for scan. Use with caution.
[INF] Targets loaded for current scan: 1
[CVE-2021-32853] [headless] [critical] https://erxes.xss/widgets/knowledgebase?topicId=%3C%2Fscript%3E%3Cscript%3Ealert%283%2B4%29%3C%2Fscript%3E
💡
To run headless based Nuclei templates, use the -headless
option (disabled by default).
Integrating headless mode into XSS detection is a game-changer, making things easier and more accurate. With the waitdialog
action, we can skip the headaches of traditional reflection based detection. No more tweaking detection for every server or technology—just straightforward, reliable XSS detection.
By combining headless mode with dialog handling, users can create simpler detection templates that focus on how XSS payloads behave. This approach cuts down the complexity and boosts reliability.
Headless mode is the future of XSS detection, and this approach brings us one step closer to making it easier for everyone.
You can also join our Discord server. It's a great place to connect with fellow contributors and stay updated with the latest developments. Thank you, once again!
By leveraging Nuclei and actively engaging with the open-source community, or by becoming a part of the ProjectDiscovery Cloud Platform, companies can enhance their security measures, proactively address emerging threats, and establish a more secure digital landscape. Security represents a shared endeavor, and by collaborating, we can consistently adapt and confront the ever-evolving challenges posed by cyber threats.