contrib.nodejsscan.ssrf_phantomjs.phantom_ssrf

Author
59
Download Count*
License
If unverified user data can reach the phantom
methods it can result in Server-Side Request Forgery vulnerabilities.
Run Locally
Run in CI
Defintion
rules:
- id: phantom_ssrf
patterns:
- pattern-inside: |
require('phantom');
...
- pattern-either:
- pattern-inside: function $FUNC($REQ, $RES, ...) {...}
- pattern-inside: $X = function $FUNC($REQ, $RES, ...) {...}
- pattern-inside: var $X = function $FUNC($REQ, $RES, ...) {...};
- pattern-inside: $APP.$METHOD(..., function $FUNC($REQ, $RES, ...) {...})
- pattern-either:
- pattern: $PAGE.open(<... $REQ.$QUERY.$FOO ...>,...)
- pattern: $PAGE.setContent(<... $REQ.$QUERY.$FOO ...>,...)
- pattern: $PAGE.open(<... $REQ.$BODY ...>,...)
- pattern: $PAGE.setContent(<... $REQ.$BODY ...>,...)
- pattern: $PAGE.openUrl(<... $REQ.$QUERY.$FOO ...>,...)
- pattern: $PAGE.openUrl(<... $REQ.$BODY ...>,...)
- pattern: $PAGE.evaluateJavaScript(<... $REQ.$QUERY.$FOO ...>,...)
- pattern: $PAGE.evaluateJavaScript(<... $REQ.$BODY ...>,...)
- pattern: $PAGE.property("content",<... $REQ.$QUERY.$FOO ...>,...)
- pattern: $PAGE.property("content",<... $REQ.$BODY ...>,...)
- pattern: |
$INPUT = <... $REQ.$QUERY.$FOO ...>;
...
$PAGE.open(<... $INPUT ...>,...);
- pattern: |
$INPUT = <... $REQ.$BODY ...>;
...
$PAGE.open(<... $INPUT ...>,...);
- pattern: |
$INPUT = <... $REQ.$QUERY.$FOO ...>;
...
$PAGE.setContent(<... $INPUT ...>,...);
- pattern: |
$INPUT = <... $REQ.$BODY ...>;
...
$PAGE.setContent(<... $INPUT ...>,...);
- pattern: |
$INPUT = <... $REQ.$QUERY.$FOO ...>;
...
$PAGE.openUrl(<... $INPUT ...>,...);
- pattern: |
$INPUT = <... $REQ.$BODY ...>;
...
$PAGE.openUrl(<... $INPUT ...>,...);
- pattern: |
$INPUT = <... $REQ.$QUERY.$FOO ...>;
...
$PAGE.evaluateJavaScript(<... $INPUT ...>,...);
- pattern: |
$INPUT = <... $REQ.$BODY ...>;
...
$PAGE.evaluateJavaScript(<... $INPUT ...>,...);
- pattern: |
$INPUT = <... $REQ.$QUERY.$FOO ...>;
...
$PAGE.property("content",<... $INPUT ...>,...);
- pattern: |-
$INPUT = <... $REQ.$BODY ...>;
...
$PAGE.property("content",<... $INPUT ...>,...);
message: If unverified user data can reach the `phantom` methods it can result
in Server-Side Request Forgery vulnerabilities.
metadata:
owasp: A01:2017 - Injection
cwe: "CWE-918: Server-Side Request Forgery (SSRF)"
category: security
technology:
- node.js
- express
- phantomjs
license: Commons Clause License Condition v1.0[LGPL-2.1-only]
severity: ERROR
languages:
- javascript
Examples
ssrf_phantomjs.js
const express = require('express')
const app = express()
const port = 3000
const phantom = require('phantom');
app.get('/test', async (req, res) => {
const instance = await phantom.create();
const page = await instance.createPage();
await page.on('onResourceRequested', function (requestData) {
console.info('Requesting', requestData.url);
});
// ruleid: phantom_ssrf
const status = await page.property('content', req.get('name'));
// ruleid: phantom_ssrf
await page.setContent(req.query.q);
res.send('Hello World!')
})
app.post('/test2', async (req, res) => {
const instance = await phantom.create();
const page = await instance.createPage();
await page.on('onResourceRequested', function (requestData) {
console.info('Requesting', requestData.url);
});
// ruleid: phantom_ssrf
const status = await page.property('content', req.query.q);
// ruleid: phantom_ssrf
await page.setContent(req.body);
const express = require('express')
const app = express()
const port = 3000
const phantom = require('phantom');
app.get('/test', async (req, res) => {
const instance = await phantom.create();
const page = await instance.createPage();
await page.on('onResourceRequested', function (requestData) {
console.info('Requesting', requestData.url);
});
// ruleid: phantom_ssrf
const status = await page.property('content', req.get('name'));
// ruleid: phantom_ssrf
await page.setContent(req.query.q);
res.send('Hello World!')
})
app.post('/test2', async (req, res) => {
const instance = await phantom.create();
const page = await instance.createPage();
await page.on('onResourceRequested', function (requestData) {
console.info('Requesting', requestData.url);
});
// ruleid: phantom_ssrf
const status = await page.property('content', req.query.q);
// ruleid: phantom_ssrf
await page.setContent(req.body);
await instance.exit();
res.send('Hello World!')
})
app.post('/test3', async (req, res) => {
const instance = await phantom.create();
const page = await instance.createPage();
await page.on('onResourceRequested', function (requestData) {
console.info('Requesting', requestData.url);
});
// ruleid: phantom_ssrf
const status = await page.openUrl(req.params.url, {}, {});
// ruleid: phantom_ssrf
await page.evaluateJavaScript(req.body.script);
await instance.exit();
res.send('Hello World!')
})
app.listen(port, () => console.log(`Example app listening at http://localhost:${port}`))
await instance.exit();
res.send('Hello World!')
})
app.post('/test3', async (req, res) => {
const instance = await phantom.create();
const page = await instance.createPage();
await page.on('onResourceRequested', function (requestData) {
console.info('Requesting', requestData.url);
});
// ruleid: phantom_ssrf
const status = await page.openUrl(req.params.url, {}, {});
// ruleid: phantom_ssrf
await page.evaluateJavaScript(req.body.script);
await instance.exit();
res.send('Hello World!')
})
app.listen(port, () => console.log(`Example app listening at http://localhost:${port}`))
Short Link: https://sg.run/oxzd