Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import java
import TemplateInjection::TemplateInjection
import semmle.code.java.dataflow.DataFlow

from TemplateInjectionFlowConfig config, DataFlow::PathNode source, DataFlow::PathNode sink
where config.hasFlowPath(source, sink)
select source, sink
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
import java
import semmle.code.java.dataflow.TaintTracking
import semmle.code.java.dataflow.FlowSources
import experimental.semmle.code.java.frameworks.FreeMarker
import experimental.semmle.code.java.frameworks.Velocity
import experimental.semmle.code.java.frameworks.Jinjava
import experimental.semmle.code.java.frameworks.Pebble
import experimental.semmle.code.java.frameworks.Thymeleaf

module TemplateInjection {
class TemplateInjectionFlowConfig extends TaintTracking::Configuration {
// import TemplateInjectionCustomizations::TemplateInjection;
TemplateInjectionFlowConfig() { this = "TemplateInjectionFlowConfig" }

override predicate isSource(DataFlow::Node source) { source instanceof Source }

override predicate isSink(DataFlow::Node sink) { sink instanceof Sink }

override predicate isSanitizer(DataFlow::Node node) {
node.getType() instanceof PrimitiveType or node.getType() instanceof BoxedType
}

override predicate isAdditionalTaintStep(DataFlow::Node prev, DataFlow::Node succ) {
exists(AdditionalFlowStep a | a.isAdditionalTaintStep(prev, succ))
}
}

class Source extends DataFlow::Node {
Source() { this instanceof RemoteFlowSource or this instanceof LocalUserInput }
}

/**
* A data flow sink for `Configuration`.
*/
abstract class Sink extends DataFlow::ExprNode { }

abstract class AdditionalFlowStep extends string {
bindingset[this]
AdditionalFlowStep() { any() }

abstract predicate isAdditionalTaintStep(DataFlow::Node prev, DataFlow::Node succ);
}

/**
* Tainted data flowing into a Velocity Context through `put` method taints the context.
*/
class VelocityContextFlow extends AdditionalFlowStep {
VelocityContextFlow() { this = "Velocity Context Flow" }

override predicate isAdditionalTaintStep(DataFlow::Node prev, DataFlow::Node succ) {
exists(MethodAccess m | m.getMethod() instanceof MethodVelocityContextPut |
m.getArgument(1) = prev.asExpr() and
(succ.asExpr() = m or succ.asExpr() = m.getQualifier())
)
}
}

/**
* An argument to FreeMarker template engine's `process` method call is a sink for `Configuration`.
*/
class FreeMarkerProcessSink extends Sink {
FreeMarkerProcessSink() {
exists(MethodAccess m |
m.getCallee() instanceof MethodFreeMarkerTemplateProcess and
m.getArgument(0) = this.getExpr()
)
}
}

/**
* An reader passed an argument to FreeMarker template engine's `Template`
* construtor call is a sink for `Configuration`.
*/
class FreeMarkerConstructorSink extends Sink {
FreeMarkerConstructorSink() {
// Template(java.lang.String name, java.io.Reader reader)
// Template(java.lang.String name, java.io.Reader reader, Configuration cfg)
// Template(java.lang.String name, java.io.Reader reader, Configuration cfg, java.lang.String encoding)
// Template(java.lang.String name, java.lang.String sourceCode, Configuration cfg)
// Template(java.lang.String name, java.lang.String sourceName, java.io.Reader reader, Configuration cfg)
// Template(java.lang.String name, java.lang.String sourceName, java.io.Reader reader, Configuration cfg, ParserConfiguration customParserConfiguration, java.lang.String encoding)
// Template(java.lang.String name, java.lang.String sourceName, java.io.Reader reader, Configuration cfg, java.lang.String encoding)
exists(ConstructorCall cc |
cc.getConstructor().getDeclaringType() instanceof TypeFreeMarkerTemplate and
exists(Expr e |
e = cc.getAnArgument() and
e.getType().(RefType).hasQualifiedName("java.io", "Reader") and
this.asExpr() = e
)
)
}
}

/**
* An argument to FreeMarker template engine's `putTemplate` method call is a sink for `Configuration`.
*/
class FreeMarkerStringTemplateLoaderPutTemplateSink extends Sink {
FreeMarkerStringTemplateLoaderPutTemplateSink() {
exists(MethodAccess ma |
this.asExpr() = ma.getArgument(1) and
ma.getMethod() instanceof MethodFreeMarkerStringTemplateLoaderPutTemplate
)
}
}

/**
* An argument to Velocity template engine's `mergeTemplate` method call is a sink for `Configuration`.
*/
class VelocityMergeTempSink extends Sink {
VelocityMergeTempSink() {
exists(MethodAccess m |
// static boolean mergeTemplate(String templateName, String encoding, Context context, Writer writer)
m.getCallee() instanceof MethodVelocityMergeTemplate and
m.getArgument(2) = this.getExpr()
)
}
}

/**
* An argument to Velocity template engine's `evaluate` method call is a sink for `Configuration`.
*/
class VelocityEvaluateSink extends Sink {
VelocityEvaluateSink() {
exists(MethodAccess m |
m.getCallee() instanceof MethodVelocityEvaluate and
m.getArgument([0, 3]) = this.getExpr()
)
}
}

/**
* An argument to Velocity template engine's `evaluate` method call is a sink for `Configuration`.
*/
class VelocityEvaluateSink extends Sink {
VelocityEvaluateSink() {
exists(MethodAccess m |
m.getCallee() instanceof MethodVelocityEvaluate and
m.getArgument([0, 3]) = this.getExpr()
)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/* Definitions related to the FreeMarker Templating library. */
import semmle.code.java.Type

/** Models FreeMarker Template Engine's `Template` class */
class TypeFreeMarkerTemplate extends Class {
TypeFreeMarkerTemplate() { this.hasQualifiedName("freemarker.template", "Template") }
}

/** Models `process` method of FreeMarker Template Engine's `Template` class */
class MethodFreeMarkerTemplateProcess extends Method {
MethodFreeMarkerTemplateProcess() {
getDeclaringType() instanceof TypeFreeMarkerTemplate and
hasName("process")
}
}

/** Models FreeMarker Template Engine's `StringTemplateLoader` class */
class TypeFreeMarkerStringLoader extends Class {
TypeFreeMarkerStringLoader() { this.hasQualifiedName("freemarker.cache", "StringTemplateLoader") }
}

/** Models `process` method of FreeMarker Template Engine's `StringTemplateLoader` class */
class MethodFreeMarkerStringTemplateLoaderPutTemplate extends Method {
MethodFreeMarkerStringTemplateLoaderPutTemplate() {
getDeclaringType() instanceof TypeFreeMarkerStringLoader and
hasName("putTemplate")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/* Definitions related to the Jinjava Tempalting library. */
import semmle.code.java.Type

/** Models `Jinjava` class of Jinjava Templating Engine. */
class TypeJinjava extends Class {
TypeJinjava() { hasQualifiedName("com.hubspot.jinjava", "JinJava") }
}

/** Models `render` method of Jinjava Templating Engine. */
class MethodJinjavaRender extends Method {
MethodJinjavaRender() {
getDeclaringType() instanceof TypeJinjava and
hasName("render")
}
}

/** Models `render` method of Jinjava Templating Engine. */
class MethodJinjavaRenderForResult extends Method {
MethodJinjavaRenderForResult() {
getDeclaringType() instanceof TypeJinjava and
hasName("renderForResult")
}
}
15 changes: 15 additions & 0 deletions java/ql/src/experimental/semmle/code/java/frameworks/Pebble.qll
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/* Definitions related to the Pebble Tempalting library. */
import semmle.code.java.Type

/** Models `PebbleEngine` class of Pebble Templating Engine. */
class TypePebbleEngine extends Class {
TypePebbleEngine() { hasQualifiedName("com.mitchellbosecke.pebble", "PebbleEngine") }
}

/** Models `getTemplate` method of Pebble Templating Engine. */
class MethodPebbleGetTemplate extends Method {
MethodPebbleGetTemplate() {
getDeclaringType() instanceof TypePebbleEngine and
hasName("getTemplate")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/* Definitions related to the Thymeleaf Tempalting library. */
import semmle.code.java.Type

/** Models `TemplateEngine` class of Thymeleaf Templating Engine. */
class TypeThymeleafTemplateEngine extends Class {
TypeThymeleafTemplateEngine() { hasQualifiedName("org.thymeleaf", "TemplateEngine") }
}

/** Models `IResourceResolver` class of Thymeleaf Templating Engine. */
class TypeThymeleafIResourceResolver extends Class {
TypeThymeleafIResourceResolver() {
hasQualifiedName("org.thymeleaf.resourceresolver", "IResourceResolver")
}
}

/** Models `process` method of Thymeleaf Templating Engine. */
class MethodThymeleafProcess extends Method {
MethodThymeleafProcess() {
getDeclaringType() instanceof TypeThymeleafTemplateEngine and
hasName("process")
}
}

/** Models `getResourceAsStream` method of Thymeleaf Templating Engine. */
class MethodThymeleafGetResourceAsStream extends Method {
MethodThymeleafGetResourceAsStream() {
getDeclaringType() instanceof TypeThymeleafIResourceResolver and
hasName("getResourceAsStream")
}
}
131 changes: 131 additions & 0 deletions java/ql/src/experimental/semmle/code/java/frameworks/Velocity.qll
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
/* Definitions related to the Apache Velocity Tempalting library. */
import semmle.code.java.Type

/** Models `org.apache.velocity.VelocityContext` class of Velocity Templating Engine. */
class TypeVelocityContext extends Class {
TypeVelocityContext() { hasQualifiedName("org.apache.velocity", "VelocityContext") }
}

/** Models `org.apache.velocity.context.AbstractContext` class of Velocity Templating Engine. */
class TypeVelocityAbstractContext extends Class {
TypeVelocityAbstractContext() {
hasQualifiedName("org.apache.velocity.context", "AbstractContext")
}
}

/** Models `org.apache.velocity.runtime.RuntimeServices` class of Velocity Templating Engine. */
class TypeVelocityRuntimeRuntimeServices extends Class {
TypeVelocityRuntimeRuntimeServices() {
hasQualifiedName("org.apache.velocity.runtime", "RuntimeServices")
}
}

/** Models `org.apache.velocity.runtime.RuntimeSingleton` class of Velocity Templating Engine. */
class TypeVelocityRuntimeRuntimeSingleton extends Class {
TypeVelocityRuntimeRuntimeSingleton() {
hasQualifiedName("org.apache.velocity.runtime", "RuntimeSingleton")
}
}

/** Models `org.apache.velocity.VelocityEngine` class of Velocity Templating Engine. */
class TypeVelocityVelocityEngine extends Class {
TypeVelocityVelocityEngine() { hasQualifiedName("org.apache.velocity", "VelocityEngine") }
}

/** Models `org.apache.velocity.app.VelocityEngine` class of Velocity Templating Engine. */
class TypeVelocityAppVelocityEngine extends Class {
TypeVelocityAppVelocityEngine() { hasQualifiedName("org.apache.velocity.app", "VelocityEngine") }
}

/** Models `org.apache.velocity.app.Velocity` class of Velocity Templating Engine. */
class TypeVelocityAppVelocity extends Class {
TypeVelocityAppVelocity() { hasQualifiedName("org.apache.velocity.app", "Velocity") }
}

/**
* Models `org.apache.velocity.runtime.resource.util.StringResourceRepository` class
* of Velocity Templating Engine.
*/
class TypeVelocityStringResourceRepo extends Class {
TypeVelocityStringResourceRepo() {
hasQualifiedName("org.apache.velocity.runtime.resource.util", "StringResourceRepository")
}
}

/** Models `internalPut` and `put` methods of Velocity Templating Engine. */
class MethodVelocityContextPut extends Method {
MethodVelocityContextPut() {
getDeclaringType().getASupertype*() instanceof TypeVelocityAbstractContext and
(hasName("put") or hasName("internalPut"))
}
}

/** Models `internalPut` method of Velocity Templating Engine. */
class MethodVelocityContextInternalPut extends Method {
MethodVelocityContextInternalPut() {
getDeclaringType().getASupertype*() instanceof TypeVelocityContext and
hasName("internalPut")
}
}

/** Models `evaluate` method of Velocity Templating Engine. */
class MethodVelocityEvaluate extends Method {
MethodVelocityEvaluate() {
// static boolean evaluate(Context context, Writer out, String logTag, String instring)
// static boolean evaluate(Context context, Writer writer, String logTag, Reader reader)
(
getDeclaringType() instanceof TypeVelocityAppVelocity or
getDeclaringType() instanceof TypeVelocityAppVelocityEngine or
getDeclaringType().getASupertype*() instanceof TypeVelocityRuntimeRuntimeServices
) and
hasName("evaluate")
}
}

/** Models `mergeTemplate` method of Velocity Templating Engine. */
class MethodVelocityMergeTemplate extends Method {
MethodVelocityMergeTemplate() {
// static boolean mergeTemplate(String templateName, String encoding, Context context, Writer writer)
getDeclaringType() instanceof TypeVelocityAppVelocity and
hasName("mergeTemplate")
}
}

/** Models `attachEventCartridge` method of Velocity Templating Engine. */
class MethodVelocityAttachEventCartridge extends Method {
MethodVelocityAttachEventCartridge() {
// EventCartridge attachEventCartridge(EventCartridge ec)
getDeclaringType() instanceof TypeVelocityContext and
hasName("attachEventCartridge")
}
}

/** Models `parse` method of Velocity Templating Engine. */
class MethodVelocityParse extends Method {
MethodVelocityParse() {
(
getDeclaringType().getASupertype*() instanceof TypeVelocityRuntimeRuntimeSingleton or
getDeclaringType().getASupertype*() instanceof TypeVelocityRuntimeRuntimeServices
) and
hasName("parse")
}
}

/** Models `putStringResource` method of Velocity Templating Engine. */
class MethodVelocityPutStringResource extends Method {
MethodVelocityPutStringResource() {
getDeclaringType().getASupertype*() instanceof TypeVelocityStringResourceRepo and
hasName("putStringResource")
}
}

/** Models `addVelocimacro` method of Velocity Templating Engine. */
class MethodVelocityAddVelocimacro extends Method {
MethodVelocityAddVelocimacro() {
(
getDeclaringType().getASupertype*() instanceof TypeVelocityRuntimeRuntimeSingleton or
getDeclaringType().getASupertype*() instanceof TypeVelocityRuntimeRuntimeServices
) and
hasName("addVelocimacro")
}
}