mirror of https://github.com/daffainfo/nuclei.git
276 lines
8.1 KiB
Markdown
276 lines
8.1 KiB
Markdown
---
|
|
title: "Headless"
|
|
---
|
|
|
|
## Basic Headless Navigation Example
|
|
|
|
This template visits a URL in the headless browser and waits for it to load.
|
|
|
|
```yaml
|
|
id: basic-headless-request
|
|
|
|
info:
|
|
name: Basic Headless Request
|
|
author: pdteam
|
|
severity: info
|
|
|
|
headless:
|
|
- steps:
|
|
- action: navigate
|
|
args:
|
|
url: "{{BaseURL}}"
|
|
- action: waitload
|
|
```
|
|
|
|
## Headless prototype pollution detection
|
|
|
|
The below template detects prototype pollution on pages with Nuclei headless capabilities. The code for detection is taken from [https://github.com/msrkp/PPScan](https://github.com/msrkp/PPScan). We make use of script injection capabilities of nuclei to provide reliable detection for prototype pollution.
|
|
|
|
```yaml
|
|
id: prototype-pollution-check
|
|
|
|
info:
|
|
name: Prototype Pollution Check
|
|
author: pd-team
|
|
severity: medium
|
|
reference: https://github.com/msrkp/PPScan
|
|
|
|
headless:
|
|
- steps:
|
|
- action: setheader
|
|
args:
|
|
part: response
|
|
key: Content-Security-Policy
|
|
value: "default-src * 'unsafe-inline' 'unsafe-eval' data: blob:;"
|
|
- action: setheader
|
|
args:
|
|
part: response
|
|
key: X-Frame-Options
|
|
value: foo
|
|
- action: setheader
|
|
args:
|
|
part: response
|
|
key: If-None-Match
|
|
value: foo
|
|
# Set the hook to override window.data for xss detection
|
|
- action: script
|
|
args:
|
|
hook: true
|
|
code: |
|
|
// Hooking code adapted from https://github.com/msrkp/PPScan/blob/main/scripts/content_script.js
|
|
(function() {window.alerts = [];
|
|
|
|
function logger(found) {
|
|
window.alerts.push(found);
|
|
}
|
|
|
|
function check() {
|
|
loc = location.href;
|
|
|
|
if (loc.indexOf("e32a5ec9c99") >= 0 && loc.search("a0def12bce") == -1) {
|
|
setTimeout(function() {
|
|
if (Object.prototype.e32a5ec9c99 == "ddcb362f1d60") {
|
|
logger(location.href);
|
|
}
|
|
var url = new URL(location.origin + location.pathname);
|
|
url.hash = "__proto__[a0def12bce]=ddcb362f1d60&__proto__.a0def12bce=ddcb362f1d60&dummy";
|
|
location = url.href;
|
|
}, 5 * 1000);
|
|
} else if (loc.search("a0def12bce") != -1) {
|
|
setTimeout(function() {
|
|
if (Object.prototype.a0def12bce == "ddcb362f1d60") {
|
|
logger(location.href);
|
|
}
|
|
window.close();
|
|
}, 5 * 1000);
|
|
} else {
|
|
var url = new URL(loc);
|
|
url.searchParams.append("__proto__[e32a5ec9c99]", "ddcb362f1d60");
|
|
url.searchParams.append("__proto__.e32a5ec9c99", "ddcb362f1d60");
|
|
location = url.href;
|
|
}
|
|
}
|
|
|
|
window.onload = function() {
|
|
if (Object.prototype.e32a5ec9c99 == "ddcb362f1d60" || Object.prototype.a0def12bce == "ddcb362f1d60") {
|
|
logger(location.href);
|
|
} else {
|
|
check();
|
|
}
|
|
};
|
|
|
|
var timerID = setInterval(function() {
|
|
if (Object.prototype.e32a5ec9c99 == "ddcb362f1d60" || Object.prototype.a0def12bce == "ddcb362f1d60") {
|
|
logger(location.href);
|
|
clearInterval(timerID);
|
|
}
|
|
}, 5 * 1000)})();
|
|
- args:
|
|
url: "{{BaseURL}}"
|
|
action: navigate
|
|
- action: waitload
|
|
- action: script
|
|
name: alerts
|
|
args:
|
|
code: "window.alerts"
|
|
matchers:
|
|
- type: word
|
|
part: alerts
|
|
words:
|
|
- "__proto__"
|
|
extractors:
|
|
- type: kval
|
|
part: alerts
|
|
kval:
|
|
- alerts
|
|
```
|
|
|
|
## DVWA XSS Reproduction With Headless Mode
|
|
|
|
This template logs into DVWA (Damn Vulnerable Web App) and tries to automatically reproduce a Reflected XSS, returning a match if it found that the payload was executed successfully.
|
|
|
|
```yaml
|
|
id: dvwa-xss-verification
|
|
|
|
info:
|
|
name: DVWA Reflected XSS Verification
|
|
author: pd-team
|
|
severity: info
|
|
|
|
headless:
|
|
- steps:
|
|
- args:
|
|
url: "{{BaseURL}}"
|
|
action: navigate
|
|
- action: waitload
|
|
|
|
# Set the hook to override window.data for xss detection
|
|
- action: script
|
|
args:
|
|
hook: true
|
|
code: "(function() { window.alert = function() { window.data = 'found' } })()"
|
|
- args:
|
|
by: x
|
|
value: admin
|
|
xpath: /html/body/div/div[2]/form/fieldset/input
|
|
action: text
|
|
- args:
|
|
by: x
|
|
value: password
|
|
xpath: /html/body/div/div[2]/form/fieldset/input[2]
|
|
action: text
|
|
- args:
|
|
by: x
|
|
xpath: /html/body/div/div[2]/form/fieldset/p/input
|
|
action: click
|
|
- action: waitload
|
|
- args:
|
|
by: x
|
|
xpath: /html/body/div/div[2]/div/ul[2]/li[11]/a
|
|
action: click
|
|
- action: waitload
|
|
- args:
|
|
by: x
|
|
value: '"><svg/onload=alert(1)>'
|
|
xpath: /html/body/div/div[3]/div/div/form/p/input
|
|
action: text
|
|
- args:
|
|
keys: "\r" # Press the enter key on the keyboard
|
|
action: keyboard
|
|
- action: waitload
|
|
- action: script
|
|
name: alert
|
|
args:
|
|
code: "window.data"
|
|
matchers:
|
|
- part: alert
|
|
type: word
|
|
words:
|
|
- "found"
|
|
```
|
|
|
|
## DOM XSS Detection
|
|
|
|
This template performs detection of DOM-XSS for `window.name` source by hooking common sinks such as `eval`, `innerHTML` and `document.write`.
|
|
|
|
```yaml
|
|
id: window-name-domxss
|
|
|
|
info:
|
|
name: window.name DOM XSS
|
|
author: pd-team
|
|
severity: medium
|
|
|
|
headless:
|
|
- steps:
|
|
- action: setheader
|
|
args:
|
|
part: response
|
|
key: Content-Security-Policy
|
|
value: "default-src * 'unsafe-inline' 'unsafe-eval' data: blob:;"
|
|
- action: script
|
|
args:
|
|
hook: true
|
|
code: |
|
|
(function() {window.alerts = [];
|
|
|
|
function logger(found) {
|
|
window.alerts.push(found);
|
|
}
|
|
|
|
function getStackTrace () {
|
|
var stack;
|
|
try {
|
|
throw new Error('');
|
|
}
|
|
catch (error) {
|
|
stack = error.stack || '';
|
|
}
|
|
stack = stack.split('\n').map(function (line) { return line.trim(); });
|
|
return stack.splice(stack[0] == 'Error' ? 2 : 1);
|
|
}
|
|
window.name = "{{randstr_1}}'\"<>";
|
|
|
|
var oldEval = eval;
|
|
var oldDocumentWrite = document.write;
|
|
var setter = Object.getOwnPropertyDescriptor(Element.prototype, 'innerHTML').set;
|
|
Object.defineProperty(Element.prototype, 'innerHTML', {
|
|
set: function innerHTML_Setter(val) {
|
|
if (val.includes("{{randstr_1}}'\"<>")) {
|
|
logger({sink: 'innerHTML', source: 'window.name', code: val, stack: getStackTrace()});
|
|
}
|
|
return setter.call(this, val)
|
|
}
|
|
});
|
|
eval = function(data) {
|
|
if (data.includes("{{randstr_1}}'\"<>")) {
|
|
logger({sink: 'eval' ,source: 'window.name', code: data, stack: getStackTrace()});
|
|
}
|
|
return oldEval.apply(this, arguments);
|
|
};
|
|
document.write = function(data) {
|
|
if (data.includes("{{randstr_1}}'\"<>")) {
|
|
logger({sink: 'document.write' ,source: 'window.name', code: data, stack: getStackTrace()});
|
|
}
|
|
return oldEval.apply(this, arguments);
|
|
};
|
|
})();
|
|
- args:
|
|
url: "{{BaseURL}}"
|
|
action: navigate
|
|
- action: waitload
|
|
- action: script
|
|
name: alerts
|
|
args:
|
|
code: "window.alerts"
|
|
matchers:
|
|
- type: word
|
|
part: alerts
|
|
words:
|
|
- "sink:"
|
|
extractors:
|
|
- type: kval
|
|
part: alerts
|
|
kval:
|
|
- alerts
|
|
``` |