Created
May 22, 2020 15:36
-
-
Save pwntester/486fc423503d222d0afb1b32a4c6a159 to your computer and use it in GitHub Desktop.
SSTI QL query
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @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