JS SSTI CWE-094

This commit is contained in:
John Doe
2020-05-03 02:42:45 +03:00
parent d8f32e3db5
commit 68b57502f9
3 changed files with 150 additions and 0 deletions

View File

@@ -0,0 +1,41 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>
Server Side Template Injection vulnerabilities occur when user input is embedded
in a template in an unsafe manner allowing attackers to access the template context and
run arbitrary code on the application server.
</p>
</overview>
<recommendation>
<p>
Avoid including user input in any expression or template which may be dynamically rendered.
If user input must be included, use context-specific escaping before including it or run
render engine with sandbox options.
</p>
</recommendation>
<example>
<p>
The following example shows html page being rendered with user input allowing attackers to access the
template context and run arbitrary code on the application server.
</p>
<sample src="examples/ServerSideTemplateInjection.js" />
</example>
<references>
<li>
OWASP:
<a href="https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/07-Input_Validation_Testing/18-Testing_for_Server_Side_Template_Injection">Server Side Template Injection</a>.
</li>
<li>
PortSwigger Research Blog:
<a href="https://portswigger.net/research/server-side-template-injection">Server Side Template Injection</a>.
</li>
</references>
</qhelp>

View File

@@ -0,0 +1,76 @@
/**
* @name Server Side Template Injection
* @description Rendering templates with unsanitized user input allows a malicious user arbitrary
* code execution.
* @kind path-problem
* @problem.severity error
* @precision high
* @id js/code-injection
* @tags security
* external/cwe/cwe-094
*/
import javascript
import DataFlow
class ServerSideTemplateInjectionConfiguration extends TaintTracking::Configuration {
ServerSideTemplateInjectionConfiguration() { this = "ServerSideTemplateInjectionConfiguration" }
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
override predicate isSink(DataFlow::Node sink) { sink instanceof ServerSideTemplateInjectionSink }
}
abstract class ServerSideTemplateInjectionSink extends DataFlow::Node { }
class SSTIPugSink extends ServerSideTemplateInjectionSink {
SSTIPugSink() {
exists(CallNode compile, ModuleImportNode renderImport, Node sink |
(renderImport = moduleImport("pug") or renderImport = moduleImport("jade")) and
(
compile = renderImport.getAMemberCall("compile") and
compile.flowsTo(sink) and
sink.getStartLine() != sink.getASuccessor().getStartLine()
or
compile = renderImport.getAMemberCall("render") and compile.flowsTo(sink)
) and
this = compile.getArgument(0)
)
}
}
class SSTIDotSink extends ServerSideTemplateInjectionSink {
SSTIDotSink() {
exists(CallNode compile, Node sink |
compile = moduleImport("dot").getAMemberCall("template") and
compile.flowsTo(sink) and
sink.getStartLine() != sink.getASuccessor().getStartLine() and
this = compile.getArgument(0)
)
}
}
class SSTIEjsSink extends ServerSideTemplateInjectionSink {
SSTIEjsSink() {
exists(CallNode compile, Node sink |
compile = moduleImport("ejs").getAMemberCall("render") and
compile.flowsTo(sink) and
this = compile.getArgument(0)
)
}
}
class SSTINunjucksSink extends ServerSideTemplateInjectionSink {
SSTINunjucksSink() {
exists(CallNode compile, Node sink |
compile = moduleImport("nunjucks").getAMemberCall("renderString") and
compile.flowsTo(sink) and
this = compile.getArgument(0)
)
}
}
from DataFlow::PathNode source, DataFlow::PathNode sink, ServerSideTemplateInjectionConfiguration c
where c.hasFlowPath(source, sink)
select sink.getNode(), source, sink, "$@ flows to here and is used in an XPath expression.",
source.getNode(), "User-provided value"

View File

@@ -0,0 +1,33 @@
const express = require('express')
var bodyParser = require('body-parser');
const app = express()
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
//Dependent of Templating engine
var jade = require('pug');
const port = 5061
function getHTML(input) {
var template = `
doctype
html
head
title= 'Hello world'
body
form(action='/' method='post')
label(for='name') Name:
input#name.form-control(type='text', placeholder='' name='name')
button.btn.btn-primary(type='submit') Submit
p Hello `+ input
var fn = jade.compile(template);
var html = fn();
console.log(html);
return html;
}
app.post('/', (request, response) => {
var input = request.param('name', "")
var html = getHTML(input)
response.send(html);
})