mirror of
https://github.com/github/codeql.git
synced 2026-04-24 16:25:15 +02:00
ssti query and help updated
This commit is contained in:
@@ -5,7 +5,7 @@
|
||||
|
||||
<overview>
|
||||
<p>
|
||||
Server-Side Template Injection vulnerabilities occur when user input is embedded
|
||||
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>
|
||||
@@ -21,13 +21,30 @@ render engine with sandbox options.
|
||||
|
||||
<example>
|
||||
<p>
|
||||
The following example shows a page being rendered with user input allowing attackers to access the
|
||||
The following example shows a page being rendered with user input allowing attackers to access the
|
||||
template context and run arbitrary code on the application server.
|
||||
Pug template engine (and other template engines) provides Interpolation feature - insertion of variable values into a string of some kind.
|
||||
For example, `Hello #{user.username}!`, could be used for printing username from scoped variable user, but `user.username` expression will be executed as valid javascript code.
|
||||
Unsafe injection of user input provides attacker ability to inject conteqnt like #{some_js_expression}.
|
||||
Injection of `#{global.process.exit(1)}` leads to code execution of `global.process.exit(1)` by server.
|
||||
Working exploit (as curl command):
|
||||
curl -i -s -k -X $'POST' -H $'Host: 127.0.0.1:5061' -H $'Connection: close' -H $'Content-Length: 40' -H $'Content-Type: application/x-www-form-urlencoded' --data-binary $'name=%23%7Bglobal.process.exit%281%29%7D' $'http://127.0.0.1:5061/'
|
||||
</p>
|
||||
|
||||
<sample src="examples/ServerSideTemplateInjection.js" />
|
||||
</example>
|
||||
|
||||
<example>
|
||||
<p>
|
||||
As the example of safe usage of rendering engine, please see example below.
|
||||
In opposite to first example, instead of concatenation of provided user input with the template
|
||||
it is possible to provide user input as a context - user input will be safely insterted
|
||||
and rendered inside correspondent placeholders.
|
||||
</p>
|
||||
|
||||
<sample src="examples/ServerSideTemplateInjectionSafe.js" />
|
||||
</example>
|
||||
|
||||
<references>
|
||||
<li>
|
||||
OWASP:
|
||||
@@ -35,7 +52,7 @@ OWASP:
|
||||
</li>
|
||||
<li>
|
||||
PortSwigger Research Blog:
|
||||
<a href="https://portswigger.net/research/server-side-template-injection">Server Side Template Injection</a>.
|
||||
<a href="https://portswigger.net/research/server-side-template-injection">Server-Side Template Injection</a>.
|
||||
</li>
|
||||
</references>
|
||||
</qhelp>
|
||||
|
||||
@@ -26,13 +26,12 @@ 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
|
||||
renderImport = moduleImport(["pug", "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)
|
||||
compile = renderImport.getAMemberCall("render")
|
||||
) and
|
||||
this = compile.getArgument(0)
|
||||
)
|
||||
@@ -43,7 +42,6 @@ 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)
|
||||
)
|
||||
@@ -51,26 +49,16 @@ class SSTIDotSink extends ServerSideTemplateInjectionSink {
|
||||
}
|
||||
|
||||
class SSTIEjsSink extends ServerSideTemplateInjectionSink {
|
||||
SSTIEjsSink() {
|
||||
exists(CallNode compile, Node sink |
|
||||
compile = moduleImport("ejs").getAMemberCall("render") and
|
||||
compile.flowsTo(sink) and
|
||||
this = compile.getArgument(0)
|
||||
)
|
||||
}
|
||||
SSTIEjsSink() { this = moduleImport("ejs").getAMemberCall("render").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)
|
||||
)
|
||||
this = moduleImport("nunjucks").getAMemberCall("renderString").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.",
|
||||
select sink.getNode(), source, sink, "$@ flows to here and unsafely used as part of rendered template",
|
||||
source.getNode(), "User-provided value"
|
||||
|
||||
Reference in New Issue
Block a user