mirror of
https://github.com/github/codeql.git
synced 2026-04-27 09:45:15 +02:00
JS SSTI CWE-094
This commit is contained in:
@@ -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>
|
||||
@@ -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"
|
||||
@@ -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);
|
||||
})
|
||||
Reference in New Issue
Block a user