Skip to content

Instantly share code, notes, and snippets.

@pwntester
Created May 22, 2020 15:36
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pwntester/486fc423503d222d0afb1b32a4c6a159 to your computer and use it in GitHub Desktop.
Save pwntester/486fc423503d222d0afb1b32a4c6a159 to your computer and use it in GitHub Desktop.
SSTI QL query
/**
* @name SSTI
* @kind path-problem
* @id java/ssti
*/
import java
import semmle.code.java.dataflow.TaintTracking
import semmle.code.java.dataflow.FlowSources
import DataFlow
import DataFlow::PathGraph
// StringSwriter.append(0...,this)
class StringWriter1 extends TaintTracking::AdditionalTaintStep {
override predicate step(DataFlow::Node n1, DataFlow::Node n2) {
exists(MethodAccess ma, Method m |
ma.getMethod() = m and
m.getName() = "append" and
m.getDeclaringType().hasQualifiedName("java.io", "StringWriter") and
ma.getAnArgument() = n1.asExpr() and
ma.getQualifier() = n2.asExpr()
)
}
}
// StringSwriter.toString(this,return)
class StringWriter2 extends TaintTracking::AdditionalTaintStep {
override predicate step(DataFlow::Node n1, DataFlow::Node n2) {
exists(MethodAccess ma, Method m |
ma.getMethod() = m and
m.getName() = "toString" and
m.getDeclaringType().hasQualifiedName("java.io", "StringWriter") and
ma.getQualifier() = n1.asExpr() and
ma = n2.asExpr()
)
}
}
// FreeMarker
class FreeMarker_Constructor_Sink extends DataFlow::Node {
FreeMarker_Constructor_Sink() {
exists(ConstructorCall cc, Constructor c |
cc.getConstructor() = c and
c.getDeclaringType().hasQualifiedName("freemarker.template", "Template") and
exists(Expr e |
e = cc.getAnArgument() and
e.getType().(RefType).hasQualifiedName("java.io", "Reader") and
this.asExpr() = e
)
)
}
}
class FreeMarker_Method_Sink extends DataFlow::Node {
FreeMarker_Method_Sink() {
exists(MethodAccess ma, Method m |
this.asExpr() = ma.getArgument(1) and
ma.getMethod() = m and
m.getName() = "putTemplate" and
m.getDeclaringType().hasQualifiedName("freemarker.cache", "StringTemplateLoader")
)
}
}
// Velocity
class Velocity_Method_Sink_1 extends DataFlow::Node {
Velocity_Method_Sink_1() {
exists(MethodAccess ma, Method m |
this.asExpr() = ma.getArgument(3) and
ma.getMethod() = m and
m.getName() = "evaluate" and
(
m.getDeclaringType().hasQualifiedName("org.apache.velocity.app", "VelocityEngine") or
m.getDeclaringType().hasQualifiedName("org.apache.velocity.app", "Velocity") or
m
.getDeclaringType()
.getASupertype*()
.hasQualifiedName("org.apache.velocity.runtime", "RuntimeServices")
)
)
}
}
class Velocity_Method_Sink_2 extends DataFlow::Node {
Velocity_Method_Sink_2() {
exists(MethodAccess ma, Method m |
this.asExpr() = ma.getArgument(0) and
ma.getMethod() = m and
m.getName() = "parse" and
(
m
.getDeclaringType()
.getASupertype*()
.hasQualifiedName("org.apache.velocity.runtime", "RuntimeServices")
or
m
.getDeclaringType()
.getASupertype*()
.hasQualifiedName("org.apache.velocity.runtime", "RuntimeSingleton")
)
)
}
}
class Velocity_Method_Sink_3 extends DataFlow::Node {
Velocity_Method_Sink_3() {
exists(MethodAccess ma, Method m |
this.asExpr() = ma.getArgument(1) and
ma.getMethod() = m and
m.getName() = "putStringResource" and
m
.getDeclaringType()
.getASupertype*()
.hasQualifiedName("org.apache.velocity.runtime.resource.util", "StringResourceRepository")
)
}
}
class Velocity_Method_Sink_4 extends DataFlow::Node {
Velocity_Method_Sink_4() {
exists(MethodAccess ma, Method m |
this.asExpr() = ma.getArgument(1) and
ma.getMethod() = m and
m.getName() = "addVelocimacro" and
(
m
.getDeclaringType()
.getASupertype*()
.hasQualifiedName("org.apache.velocity.runtime", "RuntimeServices")
or
m
.getDeclaringType()
.getASupertype*()
.hasQualifiedName("org.apache.velocity.runtime", "RuntimeSingleton")
)
)
}
}
// Thymeleaf
class Thymeleaf_Method_Sink extends DataFlow::Node {
Thymeleaf_Method_Sink() {
exists(MethodAccess ma, Method m |
this.asExpr() = ma.getArgument(0) and
ma.getMethod() = m and
m.getName() = "process" and
m.getDeclaringType().hasQualifiedName("org.thymeleaf", "TemplateEngine")
)
}
}
class Thymeleaf_Return_Sink extends DataFlow::Node {
Thymeleaf_Return_Sink() {
exists(Method m |
m.getName() = "getResourceAsStream" and
m
.getDeclaringType()
.getASupertype*()
.hasQualifiedName("org.thymeleaf.resourceresolver", "IResourceResolver") and
exists(ReturnStmt ret |
this.asExpr() = ret.getResult() and
ret.getEnclosingCallable() = m
)
)
}
}
// JinJava
class JinJava_Method_Sink extends DataFlow::Node {
JinJava_Method_Sink() {
exists(MethodAccess ma, Method m |
this.asExpr() = ma.getArgument(0) and
ma.getMethod() = m and
(
m.getName() = "render" or
m.getName() = "renderForResult"
) and
m.getDeclaringType().hasQualifiedName("com.hubspot.jinjava", "JinJava")
)
}
}
// Pebble
class Pebble_Method_Sink extends DataFlow::Node {
Pebble_Method_Sink() {
exists(MethodAccess ma, Method m |
this.asExpr() = ma.getArgument(0) and
ma.getMethod() = m and
m.getName() = "getTemplate" and
m.getDeclaringType().hasQualifiedName("com.mitchellbosecke.pebble", "PebbleEngine")
)
}
}
// MVEL
class MVEL_Method_Sink extends DataFlow::Node {
MVEL_Method_Sink() {
exists(MethodAccess ma, Method m |
this.asExpr() = ma.getArgument(0) and
ma.getMethod() = m and
m.getName() = "compileTemplate" and
m.getDeclaringType().hasQualifiedName("org.mvel2.templates", "TemplateCompiler")
)
}
}
class MVEL_Constructor_Sink extends DataFlow::Node {
MVEL_Constructor_Sink() {
exists(ConstructorCall cc, Constructor c |
cc.getConstructor() = c and
c.getDeclaringType().hasQualifiedName("org.mvel2.templates", "TemplateCompiler") and
this.asExpr() = cc.getArgument(0)
)
}
}
class SSTITaintConfig extends TaintTracking::Configuration {
SSTITaintConfig() { this = "TaintConfig" }
override int explorationLimit() { result = 4 }
override predicate isSource(DataFlow::Node source) {
source instanceof RemoteFlowSource
}
override predicate isSink(DataFlow::Node sink) {
sink instanceof FreeMarker_Constructor_Sink or
sink instanceof FreeMarker_Method_Sink or
sink instanceof Velocity_Method_Sink_1 or
sink instanceof Velocity_Method_Sink_2 or
sink instanceof Velocity_Method_Sink_3 or
sink instanceof Velocity_Method_Sink_4 or
sink instanceof Thymeleaf_Method_Sink or
sink instanceof Thymeleaf_Return_Sink or
sink instanceof JinJava_Method_Sink or
sink instanceof Pebble_Method_Sink or
sink instanceof MVEL_Constructor_Sink or
sink instanceof MVEL_Method_Sink
}
}
from SSTITaintConfig cfg, DataFlow::PathNode source, DataFlow::PathNode sink
where cfg.hasFlowPath(source, sink)
select sink, source, sink, "tainted template"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment