From e536628a66f88e33fe13f3eab8b611f152fd4400 Mon Sep 17 00:00:00 2001 From: Porcuiney Hairs Date: Fri, 21 May 2021 02:09:30 +0530 Subject: [PATCH 1/6] Java : Add SSTI query --- .../Security/CWE/CWE-094/SSTIBad.java | 19 ++ .../Security/CWE/CWE-094/SSTIGood.java | 17 ++ .../CWE/CWE-094/TemplateInjection.qhelp | 31 +++ .../Security/CWE/CWE-094/TemplateInjection.ql | 18 ++ .../CWE/CWE-094/TemplateInjection.qll | 209 ++++++++++++++++++ .../code/java/frameworks/FreeMarker.qll | 29 +++ .../semmle/code/java/frameworks/JinJava.qll | 24 ++ .../semmle/code/java/frameworks/Pebble.qll | 16 ++ .../semmle/code/java/frameworks/Thymeleaf.qll | 25 +++ .../semmle/code/java/frameworks/Velocity.qll | 119 ++++++++++ .../security/CWE-094/FreemarkerSSTI.java | 132 +++++++++++ .../security/CWE-094/JinJavaSSTI.java | 48 ++++ .../security/CWE-094/PebbleSSTI.java | 30 +++ .../CWE-094/TemplateInjection.expected | 24 ++ .../security/CWE-094/TemplateInjection.qlref | 1 + .../security/CWE-094/ThymeleafSSTI.java | 31 +++ .../security/CWE-094/VelocitySSTI.java | 126 +++++++++++ .../query-tests/security/CWE-094/options | 2 +- .../cache/StringTemplateLoader.java | 7 + .../freemarker/template/Configuration.java | 9 + .../freemarker/template/ObjectWrapper.java | 3 + .../template/ParserConfiguration.java | 3 + .../freemarker/template/Template.java | 55 +++++ .../template/TemplateNodeModel.java | 3 + .../org/apache/velocity/Template.java | 13 ++ .../org/apache/velocity/VelocityContext.java | 10 + .../org/apache/velocity/VelocityEngine.java | 20 ++ .../org/apache/velocity/app/Velocity.java | 15 ++ .../apache/velocity/app/VelocityEngine.java | 20 ++ .../velocity/context/AbstractContext.java | 14 ++ .../org/apache/velocity/context/Context.java | 7 + .../velocity/runtime/RuntimeServices.java | 25 +++ .../velocity/runtime/RuntimeSingleton.java | 8 + .../runtime/parser/node/SimpleNode.java | 5 + .../util/StringResourceRepository.java | 7 + .../util/StringResourceRepositoryImpl.java | 9 + .../com/hubspot/jinjava/Jinjava.java | 24 ++ .../com/hubspot/jinjava/JinjavaConfig.java | 5 + .../jinjava/interpret/RenderResult.java | 6 + .../mitchellbosecke/pebble/PebbleEngine.java | 27 +++ .../pebble/template/PebbleTemplate.java | 3 + .../org/thymeleaf/ITemplateEngine.java | 28 +++ .../IThrottledTemplateProcessor.java | 5 + .../org/thymeleaf/TemplateEngine.java | 51 +++++ .../org/thymeleaf/TemplateSpec.java | 5 + .../org/thymeleaf/context/Context.java | 7 + .../org/thymeleaf/context/IContext.java | 5 + 47 files changed, 1299 insertions(+), 1 deletion(-) create mode 100644 java/ql/src/experimental/Security/CWE/CWE-094/SSTIBad.java create mode 100644 java/ql/src/experimental/Security/CWE/CWE-094/SSTIGood.java create mode 100644 java/ql/src/experimental/Security/CWE/CWE-094/TemplateInjection.qhelp create mode 100644 java/ql/src/experimental/Security/CWE/CWE-094/TemplateInjection.ql create mode 100644 java/ql/src/experimental/Security/CWE/CWE-094/TemplateInjection.qll create mode 100644 java/ql/src/experimental/semmle/code/java/frameworks/FreeMarker.qll create mode 100644 java/ql/src/experimental/semmle/code/java/frameworks/JinJava.qll create mode 100644 java/ql/src/experimental/semmle/code/java/frameworks/Pebble.qll create mode 100644 java/ql/src/experimental/semmle/code/java/frameworks/Thymeleaf.qll create mode 100644 java/ql/src/experimental/semmle/code/java/frameworks/Velocity.qll create mode 100644 java/ql/test/experimental/query-tests/security/CWE-094/FreemarkerSSTI.java create mode 100644 java/ql/test/experimental/query-tests/security/CWE-094/JinJavaSSTI.java create mode 100644 java/ql/test/experimental/query-tests/security/CWE-094/PebbleSSTI.java create mode 100644 java/ql/test/experimental/query-tests/security/CWE-094/TemplateInjection.expected create mode 100644 java/ql/test/experimental/query-tests/security/CWE-094/TemplateInjection.qlref create mode 100644 java/ql/test/experimental/query-tests/security/CWE-094/ThymeleafSSTI.java create mode 100644 java/ql/test/experimental/query-tests/security/CWE-094/VelocitySSTI.java create mode 100644 java/ql/test/experimental/stubs/apache-freemarker-2.3.31/freemarker/cache/StringTemplateLoader.java create mode 100644 java/ql/test/experimental/stubs/apache-freemarker-2.3.31/freemarker/template/Configuration.java create mode 100644 java/ql/test/experimental/stubs/apache-freemarker-2.3.31/freemarker/template/ObjectWrapper.java create mode 100644 java/ql/test/experimental/stubs/apache-freemarker-2.3.31/freemarker/template/ParserConfiguration.java create mode 100644 java/ql/test/experimental/stubs/apache-freemarker-2.3.31/freemarker/template/Template.java create mode 100644 java/ql/test/experimental/stubs/apache-freemarker-2.3.31/freemarker/template/TemplateNodeModel.java create mode 100644 java/ql/test/experimental/stubs/apache-velocity-2.3/org/apache/velocity/Template.java create mode 100644 java/ql/test/experimental/stubs/apache-velocity-2.3/org/apache/velocity/VelocityContext.java create mode 100644 java/ql/test/experimental/stubs/apache-velocity-2.3/org/apache/velocity/VelocityEngine.java create mode 100644 java/ql/test/experimental/stubs/apache-velocity-2.3/org/apache/velocity/app/Velocity.java create mode 100644 java/ql/test/experimental/stubs/apache-velocity-2.3/org/apache/velocity/app/VelocityEngine.java create mode 100644 java/ql/test/experimental/stubs/apache-velocity-2.3/org/apache/velocity/context/AbstractContext.java create mode 100644 java/ql/test/experimental/stubs/apache-velocity-2.3/org/apache/velocity/context/Context.java create mode 100644 java/ql/test/experimental/stubs/apache-velocity-2.3/org/apache/velocity/runtime/RuntimeServices.java create mode 100644 java/ql/test/experimental/stubs/apache-velocity-2.3/org/apache/velocity/runtime/RuntimeSingleton.java create mode 100644 java/ql/test/experimental/stubs/apache-velocity-2.3/org/apache/velocity/runtime/parser/node/SimpleNode.java create mode 100644 java/ql/test/experimental/stubs/apache-velocity-2.3/org/apache/velocity/runtime/resource/util/StringResourceRepository.java create mode 100644 java/ql/test/experimental/stubs/apache-velocity-2.3/org/apache/velocity/runtime/resource/util/StringResourceRepositoryImpl.java create mode 100644 java/ql/test/experimental/stubs/jinjava-2.6.0/com/hubspot/jinjava/Jinjava.java create mode 100644 java/ql/test/experimental/stubs/jinjava-2.6.0/com/hubspot/jinjava/JinjavaConfig.java create mode 100644 java/ql/test/experimental/stubs/jinjava-2.6.0/com/hubspot/jinjava/interpret/RenderResult.java create mode 100644 java/ql/test/experimental/stubs/pebble-3.1.5/com/mitchellbosecke/pebble/PebbleEngine.java create mode 100644 java/ql/test/experimental/stubs/pebble-3.1.5/com/mitchellbosecke/pebble/template/PebbleTemplate.java create mode 100644 java/ql/test/experimental/stubs/thymeleaf-3.0.14/org/thymeleaf/ITemplateEngine.java create mode 100644 java/ql/test/experimental/stubs/thymeleaf-3.0.14/org/thymeleaf/IThrottledTemplateProcessor.java create mode 100644 java/ql/test/experimental/stubs/thymeleaf-3.0.14/org/thymeleaf/TemplateEngine.java create mode 100644 java/ql/test/experimental/stubs/thymeleaf-3.0.14/org/thymeleaf/TemplateSpec.java create mode 100644 java/ql/test/experimental/stubs/thymeleaf-3.0.14/org/thymeleaf/context/Context.java create mode 100644 java/ql/test/experimental/stubs/thymeleaf-3.0.14/org/thymeleaf/context/IContext.java diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/SSTIBad.java b/java/ql/src/experimental/Security/CWE/CWE-094/SSTIBad.java new file mode 100644 index 000000000000..33210448e189 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-094/SSTIBad.java @@ -0,0 +1,19 @@ +@Controller +public class VelocitySSTI { + + @GetMapping(value = "bad") + public void bad(HttpServletRequest request) { + Velocity.init(); + + String code = request.getParameter("code"); + + VelocityContext context = new VelocityContext(); + + context.put("name", "Velocity"); + context.put("project", "Jakarta"); + + StringWriter w = new StringWriter(); + // evaluate( Context context, Writer out, String logTag, String instring ) + Velocity.evaluate(context, w, "mystring", code); + } +} diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/SSTIGood.java b/java/ql/src/experimental/Security/CWE/CWE-094/SSTIGood.java new file mode 100644 index 000000000000..be4120539d5c --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-094/SSTIGood.java @@ -0,0 +1,17 @@ +@Controller +public class VelocitySSTI { + + @GetMapping(value = "good") + public void good(HttpServletRequest request) { + Velocity.init(); + VelocityContext context = new VelocityContext(); + + context.put("name", "Velocity"); + context.put("project", "Jakarta"); + + String s = "We are using $project $name to render this."; + StringWriter w = new StringWriter(); + Velocity.evaluate(context, w, "mystring", s); + System.out.println(" string : " + w); + } +} diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/TemplateInjection.qhelp b/java/ql/src/experimental/Security/CWE/CWE-094/TemplateInjection.qhelp new file mode 100644 index 000000000000..86d821b85205 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-094/TemplateInjection.qhelp @@ -0,0 +1,31 @@ + + + +

+ Template Injection occurs when user input is embedded in a template in an unsafe manner. + An attacker can use native template syntax to inject a malicious payload into a template, which is then executed server-side. This permits the attacker to run arbitrary code in the server's context.

+
+ +

+ To fix this, ensure that an untrusted value is not used as a template. If the application requirements do not allow this, use a sandboxed environment where access to unsafe attributes and methods is prohibited. +

+
+ +

+ In the example given below, an untrusted HTTP parameter + code + is used as a Velocity template string. This can lead to remote code execution. +

+ + +

+ In the next example the problem is avoided by using a fixed template string + s + . Since, the template is not attacker controlled in this case, we prevent untrusted code execution. +

+ +
+ +
  • Portswigger : [Server Side Template Injection](https://portswigger.net/web-security/server-side-template-injection)
  • +
    +
    \ No newline at end of file diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/TemplateInjection.ql b/java/ql/src/experimental/Security/CWE/CWE-094/TemplateInjection.ql new file mode 100644 index 000000000000..d4dc0c3952ef --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-094/TemplateInjection.ql @@ -0,0 +1,18 @@ +/** + * @name Server Side Template Injection + * @description Untrusted input used as a template parameter can lead to remote code execution. + * @kind path-problem + * @problem.severity error + * @precision high + * @id java/server-side-template-injection + * @tags security + * external/cwe/cwe-094 + */ + +import java +import TemplateInjection + +from TemplateInjectionFlowConfig config, DataFlow::PathNode source, DataFlow::PathNode sink +where config.hasFlowPath(source, sink) +select sink.getNode(), source, sink, "Potential arbitrary code execution due to $@.", + source.getNode(), "a template value loaded from a remote source." diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/TemplateInjection.qll b/java/ql/src/experimental/Security/CWE/CWE-094/TemplateInjection.qll new file mode 100644 index 000000000000..2f3113123aac --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-094/TemplateInjection.qll @@ -0,0 +1,209 @@ +/** Definitions related to the Server Side Template Injection (SSTI) query. */ + +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 + +/** A taint tracking configuration to reason about Server Side Template Injection (SSTI) vulnerabilities */ +class TemplateInjectionFlowConfig extends TaintTracking::Configuration { + TemplateInjectionFlowConfig() { this = "TemplateInjectionFlowConfig" } + + override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource } + + 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)) + } +} + +/** + * A data flow sink for Server Side Template Injection (SSTI) vulnerabilities + */ +abstract private class Sink extends DataFlow::ExprNode { } + +/** + * A data flow step for Server Side Template Injection (SSTI) vulnerabilities + */ +private class AdditionalFlowStep extends Unit { + abstract predicate isAdditionalTaintStep(DataFlow::Node prev, DataFlow::Node succ); +} + +/** + * An argument to FreeMarker template engine's `process` method call. + */ +private 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. + */ +private 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 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, Expr e | + cc.getConstructor().getDeclaringType() instanceof TypeFreeMarkerTemplate and + e = cc.getAnArgument() and + ( + e.getType().(RefType).hasQualifiedName("java.io", "Reader") and + this.asExpr() = e + ) + ) + or + exists(ConstructorCall cc | + cc.getConstructor().getDeclaringType() instanceof TypeFreeMarkerTemplate and + // Template(java.lang.String name, java.lang.String sourceCode, Configuration cfg) + cc.getNumArgument() = 3 and + cc.getArgument(1).getType() instanceof TypeString and + this.asExpr() = cc.getArgument(1) + ) + } +} + +/** + * An argument to FreeMarker template engine's `putTemplate` method call. + */ +private class FreeMarkerStringTemplateLoaderPutTemplateSink extends Sink { + FreeMarkerStringTemplateLoaderPutTemplateSink() { + exists(MethodAccess ma | + this.asExpr() = ma.getArgument(1) and + ma.getMethod() instanceof MethodFreeMarkerStringTemplateLoaderPutTemplate + ) + } +} + +/** + * An argument to Pebble template engine's `getLiteralTemplate` or `getTemplate` method call. + */ +private class PebbleGetTemplateSinkTemplateSink extends Sink { + PebbleGetTemplateSinkTemplateSink() { + exists(MethodAccess ma | + this.asExpr() = ma.getArgument(0) and + ma.getMethod() instanceof MethodPebbleGetTemplate + ) + } +} + +/** + * An argument to JinJava template engine's `render` or `renderForResult` method call. + */ +private class JinjavaRenderSink extends Sink { + JinjavaRenderSink() { + exists(MethodAccess ma | + this.asExpr() = ma.getArgument(0) and + ( + ma.getMethod() instanceof MethodJinjavaRenderForResult + or + ma.getMethod() instanceof MethodJinjavaRender + ) + ) + } +} + +/** + * An argument to ThymeLeaf template engine's `process` method call. + */ +private class ThymeLeafRenderSink extends Sink { + ThymeLeafRenderSink() { + exists(MethodAccess ma | + this.asExpr() = ma.getArgument(0) and + ma.getMethod() instanceof MethodThymeleafProcess + ) + } +} + +/** + * Tainted data flowing into a Velocity Context through `put` method taints the context. + */ +private class VelocityContextFlow extends AdditionalFlowStep { + 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.getQualifier() + ) + } +} + +/** + * An argument to Velocity template engine's `mergeTemplate` method call. + */ +private 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 `mergeTemplate` method call. + */ +private class VelocityMergeSink extends Sink { + VelocityMergeSink() { + exists(MethodAccess m | + m.getCallee() instanceof MethodVelocityMerge and + // public void merge(Context context, Writer writer) + // public void merge(Context context, Writer writer, List macroLibraries) + m.getArgument(0) = this.getExpr() + ) + } +} + +/** + * An argument to Velocity template engine's `evaluate` method call. + */ +private 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 `parse` method call. + */ +private class VelocityParseSink extends Sink { + VelocityParseSink() { + exists(MethodAccess ma | + this.asExpr() = ma.getArgument(0) and + ma.getMethod() instanceof MethodVelocityParse + ) + } +} + +/** + * An argument to Velocity template engine's `putStringResource` method call. + */ +private class VelocityPutStringResSink extends Sink { + VelocityPutStringResSink() { + exists(MethodAccess ma | + this.asExpr() = ma.getArgument(1) and + ma.getMethod() instanceof MethodVelocityPutStringResource + ) + } +} diff --git a/java/ql/src/experimental/semmle/code/java/frameworks/FreeMarker.qll b/java/ql/src/experimental/semmle/code/java/frameworks/FreeMarker.qll new file mode 100644 index 000000000000..84cea7f013ef --- /dev/null +++ b/java/ql/src/experimental/semmle/code/java/frameworks/FreeMarker.qll @@ -0,0 +1,29 @@ +/** Definitions related to the FreeMarker Templating library. */ + +import java + +/** The `Template` class of the FreeMarker Template Engine */ +class TypeFreeMarkerTemplate extends Class { + TypeFreeMarkerTemplate() { this.hasQualifiedName("freemarker.template", "Template") } +} + +/** The `process` method of the FreeMarker Template Engine's `Template` class */ +class MethodFreeMarkerTemplateProcess extends Method { + MethodFreeMarkerTemplateProcess() { + this.getDeclaringType() instanceof TypeFreeMarkerTemplate and + this.hasName("process") + } +} + +/** The `StringTemplateLoader` class of the FreeMarker Template Engine */ +class TypeFreeMarkerStringLoader extends Class { + TypeFreeMarkerStringLoader() { this.hasQualifiedName("freemarker.cache", "StringTemplateLoader") } +} + +/** The `process` method of the FreeMarker Template Engine's `StringTemplateLoader` class */ +class MethodFreeMarkerStringTemplateLoaderPutTemplate extends Method { + MethodFreeMarkerStringTemplateLoaderPutTemplate() { + this.getDeclaringType() instanceof TypeFreeMarkerStringLoader and + this.hasName("putTemplate") + } +} diff --git a/java/ql/src/experimental/semmle/code/java/frameworks/JinJava.qll b/java/ql/src/experimental/semmle/code/java/frameworks/JinJava.qll new file mode 100644 index 000000000000..f0f3bcf603bd --- /dev/null +++ b/java/ql/src/experimental/semmle/code/java/frameworks/JinJava.qll @@ -0,0 +1,24 @@ +/** Definitions related to the Jinjava Templating library. */ + +import java + +/** The `Jinjava` class of the Jinjava Templating Engine. */ +class TypeJinjava extends Class { + TypeJinjava() { this.hasQualifiedName("com.hubspot.jinjava", "Jinjava") } +} + +/** The `render` method of the Jinjava Templating Engine. */ +class MethodJinjavaRender extends Method { + MethodJinjavaRender() { + this.getDeclaringType() instanceof TypeJinjava and + this.hasName("render") + } +} + +/** The `render` method of the Jinjava Templating Engine. */ +class MethodJinjavaRenderForResult extends Method { + MethodJinjavaRenderForResult() { + this.getDeclaringType() instanceof TypeJinjava and + this.hasName("renderForResult") + } +} diff --git a/java/ql/src/experimental/semmle/code/java/frameworks/Pebble.qll b/java/ql/src/experimental/semmle/code/java/frameworks/Pebble.qll new file mode 100644 index 000000000000..9850e5dbf4d9 --- /dev/null +++ b/java/ql/src/experimental/semmle/code/java/frameworks/Pebble.qll @@ -0,0 +1,16 @@ +/** Definitions related to the Pebble Templating library. */ + +import java + +/** The `PebbleEngine` class of the Pebble Templating Engine. */ +class TypePebbleEngine extends Class { + TypePebbleEngine() { this.hasQualifiedName("com.mitchellbosecke.pebble", "PebbleEngine") } +} + +/** The `getTemplate` method of the Pebble Templating Engine. */ +class MethodPebbleGetTemplate extends Method { + MethodPebbleGetTemplate() { + this.getDeclaringType() instanceof TypePebbleEngine and + this.hasName(["getTemplate", "getLiteralTemplate"]) + } +} diff --git a/java/ql/src/experimental/semmle/code/java/frameworks/Thymeleaf.qll b/java/ql/src/experimental/semmle/code/java/frameworks/Thymeleaf.qll new file mode 100644 index 000000000000..18235257be1d --- /dev/null +++ b/java/ql/src/experimental/semmle/code/java/frameworks/Thymeleaf.qll @@ -0,0 +1,25 @@ +/** Definitions related to the Thymeleaf Templating library. */ + +import java + +/** + * A class implementing the `ITemplateEngine` interface of the Thymeleaf + * Templating Engine such as the `TemplateEngine` class. + * */ +class TypeThymeleafTemplateEngine extends Class { + TypeThymeleafTemplateEngine() { + this.hasQualifiedName("org.thymeleaf", "TemplateEngine") + or + exists(Type t | this.getASupertype*().extendsOrImplements(t) | + t.hasName("org.thymeleaf.ITemplateEngine") + ) + } +} + +/** The `process` or `processThrottled` method of the Thymeleaf Templating Engine. */ +class MethodThymeleafProcess extends Method { + MethodThymeleafProcess() { + this.getDeclaringType() instanceof TypeThymeleafTemplateEngine and + this.hasName(["process", "processThrottled"]) + } +} diff --git a/java/ql/src/experimental/semmle/code/java/frameworks/Velocity.qll b/java/ql/src/experimental/semmle/code/java/frameworks/Velocity.qll new file mode 100644 index 000000000000..f2d298833c6a --- /dev/null +++ b/java/ql/src/experimental/semmle/code/java/frameworks/Velocity.qll @@ -0,0 +1,119 @@ +/** Definitions related to the Apache Velocity Templating library. */ + +import java + +/** The `org.apache.velocity.context.AbstractContext` class of the Velocity Templating Engine. */ +class TypeVelocityAbstractContext extends Class { + TypeVelocityAbstractContext() { + this.hasQualifiedName("org.apache.velocity.context", "AbstractContext") + } +} + +/** The `org.apache.velocity.runtime.RuntimeServices` class of the Velocity Templating Engine. */ +class TypeVelocityRuntimeRuntimeServices extends Class { + TypeVelocityRuntimeRuntimeServices() { + this.hasQualifiedName("org.apache.velocity.runtime", "RuntimeServices") + } +} + +/** The `org.apache.velocity.Template` class of the Velocity Templating Engine. */ +class TypeVelocityTemplate extends Class { + TypeVelocityTemplate() { this.hasQualifiedName("org.apache.velocity", "Template") } +} + +/** The `org.apache.velocity.runtime.RuntimeSingleton` classTemplating Engine. */ +class TypeVelocityRuntimeRuntimeSingleton extends Class { + TypeVelocityRuntimeRuntimeSingleton() { + this.hasQualifiedName("org.apache.velocity.runtime", "RuntimeSingleton") + } +} + +/** The `org.apache.velocity.VelocityEngine` class of the Velocity Templating Engine. */ +class TypeVelocityVelocityEngine extends Class { + TypeVelocityVelocityEngine() { this.hasQualifiedName("org.apache.velocity", "VelocityEngine") } +} + +/** The `org.apache.velocity.app.VelocityEngine` class of the Velocity Templating Engine. */ +class TypeVelocityAppVelocityEngine extends RefType { + TypeVelocityAppVelocityEngine() { + this.hasQualifiedName("org.apache.velocity.app", "VelocityEngine") + } +} + +/** The `org.apache.velocity.app.Velocity` class of the Velocity Templating Engine. */ +class TypeVelocityAppVelocity extends RefType { + TypeVelocityAppVelocity() { this.hasQualifiedName("org.apache.velocity.app", "Velocity") } +} + +/** + * The `org.apache.velocity.runtime.resource.util.StringResourceRepository` interface + * of the Velocity Templating Engine. + */ +class TypeVelocityStringResourceRepo extends RefType { + TypeVelocityStringResourceRepo() { + this.hasQualifiedName("org.apache.velocity.runtime.resource.util", "StringResourceRepository") + } +} + +/** The `internalPut` and `put` methods of the Velocity Templating Engine. */ +class MethodVelocityContextPut extends Method { + MethodVelocityContextPut() { + this.getDeclaringType().getASupertype*() instanceof TypeVelocityAbstractContext and + this.hasName(["put", "internalPut"]) + } +} + +/** The `evaluate` method of the 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) + ( + this.getDeclaringType() instanceof TypeVelocityAppVelocity or + this.getDeclaringType() instanceof TypeVelocityAppVelocityEngine or + this.getDeclaringType().getASupertype*() instanceof TypeVelocityRuntimeRuntimeServices + ) and + this.hasName("evaluate") + } +} + +/** The `mergeTemplate` method of the Velocity Templating Engine. */ +class MethodVelocityMergeTemplate extends Method { + MethodVelocityMergeTemplate() { + // static boolean mergeTemplate(String templateName, String encoding, Context context, Writer writer) + ( + this.getDeclaringType() instanceof TypeVelocityAppVelocity or + this.getDeclaringType() instanceof TypeVelocityAppVelocityEngine + ) and + this.hasName("mergeTemplate") + } +} + +/** The `merge` method of the Velocity Templating Engine. */ +class MethodVelocityMerge extends Method { + MethodVelocityMerge() { + // void merge(Context context, Writer writer) + // void merge(Context context, Writer writer, List macroLibraries) + this.getDeclaringType() instanceof TypeVelocityTemplate and + this.hasName("merge") + } +} + +/** The `parse` method of the Velocity Templating Engine. */ +class MethodVelocityParse extends Method { + MethodVelocityParse() { + ( + this.getDeclaringType().getASupertype*() instanceof TypeVelocityRuntimeRuntimeSingleton or + this.getDeclaringType().getASupertype*() instanceof TypeVelocityRuntimeRuntimeServices + ) and + this.hasName("parse") + } +} + +/** The `putStringResource` method of the Velocity Templating Engine. */ +class MethodVelocityPutStringResource extends Method { + MethodVelocityPutStringResource() { + this.getDeclaringType().getASupertype*() instanceof TypeVelocityStringResourceRepo and + this.hasName("putStringResource") + } +} diff --git a/java/ql/test/experimental/query-tests/security/CWE-094/FreemarkerSSTI.java b/java/ql/test/experimental/query-tests/security/CWE-094/FreemarkerSSTI.java new file mode 100644 index 000000000000..3ac93749616f --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-094/FreemarkerSSTI.java @@ -0,0 +1,132 @@ +import javax.servlet.http.HttpServletRequest; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; + +import java.lang.String; +import java.io.Reader; +import java.io.StringReader; +import java.io.OutputStreamWriter; +import java.util.HashMap; + +import freemarker.template.Template; +import freemarker.template.Configuration; +import freemarker.cache.StringTemplateLoader; +import freemarker.template.ParserConfiguration; + +@Controller +public class FreemarkerSSTI { + String sourceName = "sourceName"; + + @GetMapping(value = "bad1") + public void bad1(HttpServletRequest request) { + String name = "ttemplate"; + String code = request.getParameter("code"); + Reader reader = new StringReader(code); + + // Template(java.lang.String name, java.io.Reader reader) + Template t = new Template(name, reader); + } + + @GetMapping(value = "bad2") + public void bad2(HttpServletRequest request) { + String name = "ttemplate"; + String code = request.getParameter("code"); + Reader reader = new StringReader(code); + Configuration cfg = new Configuration(); + + // Template(java.lang.String name, java.io.Reader reader, Configuration cfg) + Template t = new Template(name, reader, cfg); + } + + @GetMapping(value = "bad3") + public void bad3(HttpServletRequest request) { + String name = "ttemplate"; + String code = request.getParameter("code"); + Reader reader = new StringReader(code); + Configuration cfg = new Configuration(); + + // Template(java.lang.String name, java.io.Reader reader, Configuration cfg, + // java.lang.String encoding) + Template t = new Template(name, reader, cfg, "UTF-8"); + } + + @GetMapping(value = "bad4") + public void bad4(HttpServletRequest request) { + String name = "ttemplate"; + String sourceCode = request.getParameter("sourceCode"); + Configuration cfg = new Configuration(); + + // Template(java.lang.String name, java.lang.String sourceCode, Configuration + // cfg) + Template t = new Template(name, sourceCode, cfg); + } + + @GetMapping(value = "bad5") + public void bad5(HttpServletRequest request) { + String name = "ttemplate"; + String code = request.getParameter("code"); + Configuration cfg = new Configuration(); + Reader reader = new StringReader(code); + + // Template(java.lang.String name, java.lang.String sourceName, java.io.Reader + // reader, Configuration cfg) + Template t = new Template(name, sourceName, reader, cfg); + } + + @GetMapping(value = "bad6") + public void bad6(HttpServletRequest request) { + String name = "ttemplate"; + String code = request.getParameter("code"); + Configuration cfg = new Configuration(); + ParserConfiguration customParserConfiguration = new Configuration(); + Reader reader = new StringReader(code); + + // Template(java.lang.String name, java.lang.String sourceName, java.io.Reader + // reader, Configuration cfg, ParserConfiguration customParserConfiguration, + // java.lang.String encoding) + Template t = new Template(name, sourceName, reader, cfg, customParserConfiguration, "UTF-8"); + } + + @GetMapping(value = "bad7") + public void bad7(HttpServletRequest request) { + String name = "ttemplate"; + String code = request.getParameter("code"); + Configuration cfg = new Configuration(); + ParserConfiguration customParserConfiguration = new Configuration(); + Reader reader = new StringReader(code); + + // Template(java.lang.String name, java.lang.String sourceName, java.io.Reader + // reader, Configuration cfg, java.lang.String encoding) + Template t = new Template(name, sourceName, reader, cfg, "UTF-8"); + } + + @GetMapping(value = "bad8") + public void bad8(HttpServletRequest request) { + String code = request.getParameter("code"); + StringTemplateLoader stringLoader = new StringTemplateLoader(); + + // void putTemplate(java.lang.String name, java.lang.String templateContent) + stringLoader.putTemplate("myTemplate", code); + } + + @GetMapping(value = "bad9") + public void bad9(HttpServletRequest request) { + String code = request.getParameter("code"); + StringTemplateLoader stringLoader = new StringTemplateLoader(); + + // void putTemplate(java.lang.String name, java.lang.String templateContent, + // long lastModified) + stringLoader.putTemplate("myTemplate", code, 0); + } + + @GetMapping(value = "bad10") + public void bad10(HttpServletRequest request) { + HashMap root = new HashMap(); + String code = request.getParameter("code"); + root.put("code", code); + Configuration cfg = new Configuration(); + Template temp = cfg.getTemplate("test.ftlh"); + OutputStreamWriter out = new OutputStreamWriter(System.out); + temp.process(root, out); + } +} diff --git a/java/ql/test/experimental/query-tests/security/CWE-094/JinJavaSSTI.java b/java/ql/test/experimental/query-tests/security/CWE-094/JinJavaSSTI.java new file mode 100644 index 000000000000..5f0d932678d7 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-094/JinJavaSSTI.java @@ -0,0 +1,48 @@ +import javax.servlet.http.HttpServletRequest; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; + +import java.lang.String; +import java.io.Reader; +import java.io.StringReader; +import java.util.HashMap; +import java.util.Map; + +import com.hubspot.jinjava.*; +import com.hubspot.jinjava.JinjavaConfig; +import com.hubspot.jinjava.interpret.*; + +@Controller +public class JinJavaSSTI { + String sourceName = "sourceName"; + + @GetMapping(value = "bad1") + public void bad1(HttpServletRequest request) { + String template = request.getParameter("template"); + Jinjava jinjava = new Jinjava(); + Map context = new HashMap<>(); + // String render​(String template, Map bindings) + String renderedTemplate = jinjava.render(template, context); + } + + @GetMapping(value = "bad2") + public void bad2(HttpServletRequest request) { + String template = request.getParameter("template"); + Jinjava jinjava = new Jinjava(); + Map bindings = new HashMap<>(); + // RenderResult renderForResult​(String template, Map bindings) + RenderResult renderResult = jinjava.renderForResult(template, bindings); + } + + @GetMapping(value = "bad3") + public void bad3(HttpServletRequest request) { + String template = request.getParameter("template"); + Jinjava jinjava = new Jinjava(); + Map bindings = new HashMap<>(); + JinjavaConfig renderConfig = new JinjavaConfig(); + + // RenderResult renderForResult​(String template, Map bindings, + // JinjavaConfig renderConfig) + RenderResult renderResult = jinjava.renderForResult(template, bindings, renderConfig); + } +} diff --git a/java/ql/test/experimental/query-tests/security/CWE-094/PebbleSSTI.java b/java/ql/test/experimental/query-tests/security/CWE-094/PebbleSSTI.java new file mode 100644 index 000000000000..13ed42a9b261 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-094/PebbleSSTI.java @@ -0,0 +1,30 @@ +import javax.servlet.http.HttpServletRequest; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; + +import java.lang.String; +import java.io.Reader; +import java.io.StringReader; + +import com.mitchellbosecke.pebble.PebbleEngine; +import com.mitchellbosecke.pebble.template.*; + +@Controller +public class PebbleSSTI { + String sourceName = "sourceName"; + + @GetMapping(value = "bad1") + public void bad1(HttpServletRequest request) { + String code = request.getParameter("code"); + PebbleEngine engine = new PebbleEngine.Builder().build(); + // public PebbleTemplate getTemplate(String templateName) + PebbleTemplate compiledTemplate = engine.getTemplate(code); + } + @GetMapping(value = "bad2") + public void bad2(HttpServletRequest request) { + String code = request.getParameter("code"); + PebbleEngine engine = new PebbleEngine.Builder().build(); + // public PebbleTemplate getLiteralTemplate(String templateName) + PebbleTemplate compiledTemplate = engine.getLiteralTemplate(code); + } +} diff --git a/java/ql/test/experimental/query-tests/security/CWE-094/TemplateInjection.expected b/java/ql/test/experimental/query-tests/security/CWE-094/TemplateInjection.expected new file mode 100644 index 000000000000..dc884612625e --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-094/TemplateInjection.expected @@ -0,0 +1,24 @@ +| FreemarkerSSTI.java:27:35:27:40 | reader | FreemarkerSSTI.java:23:17:23:44 | getParameter(...) : String | FreemarkerSSTI.java:27:35:27:40 | reader | Potential arbitrary code execution due to $@. | FreemarkerSSTI.java:23:17:23:44 | getParameter(...) | a template value loaded from a remote source. | +| FreemarkerSSTI.java:38:35:38:40 | reader | FreemarkerSSTI.java:33:17:33:44 | getParameter(...) : String | FreemarkerSSTI.java:38:35:38:40 | reader | Potential arbitrary code execution due to $@. | FreemarkerSSTI.java:33:17:33:44 | getParameter(...) | a template value loaded from a remote source. | +| FreemarkerSSTI.java:50:35:50:40 | reader | FreemarkerSSTI.java:44:17:44:44 | getParameter(...) : String | FreemarkerSSTI.java:50:35:50:40 | reader | Potential arbitrary code execution due to $@. | FreemarkerSSTI.java:44:17:44:44 | getParameter(...) | a template value loaded from a remote source. | +| FreemarkerSSTI.java:61:35:61:44 | sourceCode | FreemarkerSSTI.java:56:23:56:56 | getParameter(...) : String | FreemarkerSSTI.java:61:35:61:44 | sourceCode | Potential arbitrary code execution due to $@. | FreemarkerSSTI.java:56:23:56:56 | getParameter(...) | a template value loaded from a remote source. | +| FreemarkerSSTI.java:73:47:73:52 | reader | FreemarkerSSTI.java:67:17:67:44 | getParameter(...) : String | FreemarkerSSTI.java:73:47:73:52 | reader | Potential arbitrary code execution due to $@. | FreemarkerSSTI.java:67:17:67:44 | getParameter(...) | a template value loaded from a remote source. | +| FreemarkerSSTI.java:87:47:87:52 | reader | FreemarkerSSTI.java:79:17:79:44 | getParameter(...) : String | FreemarkerSSTI.java:87:47:87:52 | reader | Potential arbitrary code execution due to $@. | FreemarkerSSTI.java:79:17:79:44 | getParameter(...) | a template value loaded from a remote source. | +| FreemarkerSSTI.java:100:47:100:52 | reader | FreemarkerSSTI.java:93:17:93:44 | getParameter(...) : String | FreemarkerSSTI.java:100:47:100:52 | reader | Potential arbitrary code execution due to $@. | FreemarkerSSTI.java:93:17:93:44 | getParameter(...) | a template value loaded from a remote source. | +| FreemarkerSSTI.java:109:42:109:45 | code | FreemarkerSSTI.java:105:17:105:44 | getParameter(...) : String | FreemarkerSSTI.java:109:42:109:45 | code | Potential arbitrary code execution due to $@. | FreemarkerSSTI.java:105:17:105:44 | getParameter(...) | a template value loaded from a remote source. | +| FreemarkerSSTI.java:119:42:119:45 | code | FreemarkerSSTI.java:114:17:114:44 | getParameter(...) : String | FreemarkerSSTI.java:119:42:119:45 | code | Potential arbitrary code execution due to $@. | FreemarkerSSTI.java:114:17:114:44 | getParameter(...) | a template value loaded from a remote source. | +| FreemarkerSSTI.java:130:22:130:25 | root | FreemarkerSSTI.java:125:17:125:44 | getParameter(...) : String | FreemarkerSSTI.java:130:22:130:25 | root | Potential arbitrary code execution due to $@. | FreemarkerSSTI.java:125:17:125:44 | getParameter(...) | a template value loaded from a remote source. | +| JinJavaSSTI.java:25:44:25:51 | template | JinJavaSSTI.java:21:21:21:52 | getParameter(...) : String | JinJavaSSTI.java:25:44:25:51 | template | Potential arbitrary code execution due to $@. | JinJavaSSTI.java:21:21:21:52 | getParameter(...) | a template value loaded from a remote source. | +| JinJavaSSTI.java:34:55:34:62 | template | JinJavaSSTI.java:30:21:30:52 | getParameter(...) : String | JinJavaSSTI.java:34:55:34:62 | template | Potential arbitrary code execution due to $@. | JinJavaSSTI.java:30:21:30:52 | getParameter(...) | a template value loaded from a remote source. | +| JinJavaSSTI.java:46:55:46:62 | template | JinJavaSSTI.java:39:21:39:52 | getParameter(...) : String | JinJavaSSTI.java:46:55:46:62 | template | Potential arbitrary code execution due to $@. | JinJavaSSTI.java:39:21:39:52 | getParameter(...) | a template value loaded from a remote source. | +| PebbleSSTI.java:21:56:21:59 | code | PebbleSSTI.java:18:17:18:44 | getParameter(...) : String | PebbleSSTI.java:21:56:21:59 | code | Potential arbitrary code execution due to $@. | PebbleSSTI.java:18:17:18:44 | getParameter(...) | a template value loaded from a remote source. | +| PebbleSSTI.java:28:63:28:66 | code | PebbleSSTI.java:25:17:25:44 | getParameter(...) : String | PebbleSSTI.java:28:63:28:66 | code | Potential arbitrary code execution due to $@. | PebbleSSTI.java:25:17:25:44 | getParameter(...) | a template value loaded from a remote source. | +| ThymeleafSSTI.java:27:27:27:30 | code | ThymeleafSSTI.java:22:17:22:44 | getParameter(...) : String | ThymeleafSSTI.java:27:27:27:30 | code | Potential arbitrary code execution due to $@. | ThymeleafSSTI.java:22:17:22:44 | getParameter(...) | a template value loaded from a remote source. | +| VelocitySSTI.java:38:45:38:48 | code | VelocitySSTI.java:31:17:31:44 | getParameter(...) : String | VelocitySSTI.java:38:45:38:48 | code | Potential arbitrary code execution due to $@. | VelocitySSTI.java:31:17:31:44 | getParameter(...) | a template value loaded from a remote source. | +| VelocitySSTI.java:53:45:53:50 | reader | VelocitySSTI.java:44:17:44:44 | getParameter(...) : String | VelocitySSTI.java:53:45:53:50 | reader | Potential arbitrary code execution due to $@. | VelocitySSTI.java:44:17:44:44 | getParameter(...) | a template value loaded from a remote source. | +| VelocitySSTI.java:63:25:63:30 | reader | VelocitySSTI.java:59:17:59:44 | getParameter(...) : String | VelocitySSTI.java:63:25:63:30 | reader | Potential arbitrary code execution due to $@. | VelocitySSTI.java:59:17:59:44 | getParameter(...) | a template value loaded from a remote source. | +| VelocitySSTI.java:77:21:77:27 | context | VelocitySSTI.java:69:17:69:44 | getParameter(...) : String | VelocitySSTI.java:77:21:77:27 | context | Potential arbitrary code execution due to $@. | VelocitySSTI.java:69:17:69:44 | getParameter(...) | a template value loaded from a remote source. | +| VelocitySSTI.java:89:60:89:66 | context | VelocitySSTI.java:83:17:83:44 | getParameter(...) : String | VelocitySSTI.java:89:60:89:66 | context | Potential arbitrary code execution due to $@. | VelocitySSTI.java:83:17:83:44 | getParameter(...) | a template value loaded from a remote source. | +| VelocitySSTI.java:102:11:102:17 | context | VelocitySSTI.java:95:17:95:44 | getParameter(...) : String | VelocitySSTI.java:102:11:102:17 | context | Potential arbitrary code execution due to $@. | VelocitySSTI.java:95:17:95:44 | getParameter(...) | a template value loaded from a remote source. | +| VelocitySSTI.java:115:11:115:17 | context | VelocitySSTI.java:108:17:108:44 | getParameter(...) : String | VelocitySSTI.java:115:11:115:17 | context | Potential arbitrary code execution due to $@. | VelocitySSTI.java:108:17:108:44 | getParameter(...) | a template value loaded from a remote source. | +| VelocitySSTI.java:123:37:123:40 | code | VelocitySSTI.java:120:17:120:44 | getParameter(...) : String | VelocitySSTI.java:123:37:123:40 | code | Potential arbitrary code execution due to $@. | VelocitySSTI.java:120:17:120:44 | getParameter(...) | a template value loaded from a remote source. | diff --git a/java/ql/test/experimental/query-tests/security/CWE-094/TemplateInjection.qlref b/java/ql/test/experimental/query-tests/security/CWE-094/TemplateInjection.qlref new file mode 100644 index 000000000000..2febc9b780f6 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-094/TemplateInjection.qlref @@ -0,0 +1 @@ +experimental/Security/CWE/CWE-094/TemplateInjection.ql \ No newline at end of file diff --git a/java/ql/test/experimental/query-tests/security/CWE-094/ThymeleafSSTI.java b/java/ql/test/experimental/query-tests/security/CWE-094/ThymeleafSSTI.java new file mode 100644 index 000000000000..2b32a4603c79 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-094/ThymeleafSSTI.java @@ -0,0 +1,31 @@ +import javax.imageio.stream.FileImageInputStream; +import javax.servlet.http.HttpServletRequest; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; + +import java.lang.String; +import java.io.File; +import java.io.FileWriter; +import java.io.Reader; +import java.io.StringReader; +import java.io.Writer; + +import org.thymeleaf.*; +import org.thymeleaf.context.Context; + +@Controller +public class ThymeleafSSTI { + String sourceName = "sourceName"; + + @GetMapping(value = "bad1") + public void bad1(HttpServletRequest request) { + String code = request.getParameter("code"); + Context ctx = new Context(); + try { + FileWriter fw = new FileWriter(new File("as")); + TemplateEngine templateEngine = new TemplateEngine(); + templateEngine.process(code, ctx, fw); + } catch (Exception e) { + } + } +} diff --git a/java/ql/test/experimental/query-tests/security/CWE-094/VelocitySSTI.java b/java/ql/test/experimental/query-tests/security/CWE-094/VelocitySSTI.java new file mode 100644 index 000000000000..c35dd9b0aae9 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-094/VelocitySSTI.java @@ -0,0 +1,126 @@ +import javax.servlet.http.HttpServletRequest; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; + +import java.lang.String; +import java.io.Reader; +import java.io.StringReader; +import java.io.OutputStreamWriter; +import java.io.InputStream; +import java.io.StringWriter; +import java.util.HashMap; +import java.util.LinkedList; + +import org.apache.velocity.VelocityContext; +import org.apache.velocity.context.AbstractContext; +import org.apache.velocity.context.Context; +import org.apache.velocity.Template; +import org.apache.velocity.app.Velocity; +import org.apache.velocity.app.VelocityEngine; +import org.apache.velocity.runtime.RuntimeServices; +import org.apache.velocity.runtime.resource.util.StringResourceRepository; +import org.apache.velocity.runtime.resource.util.StringResourceRepositoryImpl; + +@Controller +public class VelocitySSTI { + String sourceName = "sourceName"; + + @GetMapping(value = "bad1") + public void bad1(HttpServletRequest request) { + String name = "ttemplate"; + String code = request.getParameter("code"); + + VelocityContext context = null; + + String s = "We are using $project $name to render this."; + StringWriter w = new StringWriter(); + // evaluate( Context context, Writer out, String logTag, String instring ) + Velocity.evaluate(context, w, "mystring", code); + } + + @GetMapping(value = "bad2") + public void bad2(HttpServletRequest request) { + String name = "ttemplate"; + String code = request.getParameter("code"); + + VelocityContext context = null; + + String s = "We are using $project $name to render this."; + StringWriter w = new StringWriter(); + StringReader reader = new StringReader(code); + + // evaluate(Context context, Writer writer, String logTag, Reader reader) + Velocity.evaluate(context, w, "mystring", reader); + } + + @GetMapping(value = "bad3") + public void bad3(HttpServletRequest request) { + String name = "ttemplate"; + String code = request.getParameter("code"); + + RuntimeServices runtimeServices = new RuntimeServices(); + StringReader reader = new StringReader(code); + runtimeServices.parse(reader, new Template()); + } + + @GetMapping(value = "bad4") + public void bad4(HttpServletRequest request) { + String name = "ttemplate"; + String code = request.getParameter("code"); + + VelocityContext context = new VelocityContext(); + context.put("code", code); + + StringWriter w = new StringWriter(); + StringReader reader = new StringReader("test"); + + Velocity.evaluate(context, w, "mystring", reader); + } + + @GetMapping(value = "bad5") + public void bad5(HttpServletRequest request) { + String name = "ttemplate"; + String code = request.getParameter("code"); + + VelocityContext context = new VelocityContext(); + context.put("code", code); + + StringWriter w = new StringWriter(); + VelocityEngine.mergeTemplate("testtemplate.vm", "UTF-8", context, w); + } + + @GetMapping(value = "bad6") + public void bad6(HttpServletRequest request) { + String name = "ttemplate"; + String code = request.getParameter("code"); + + VelocityContext context = new VelocityContext(); + context.put("code", code); + + StringWriter w = new StringWriter(); + Template t = new Template(); + t.merge(context, w); + } + + @GetMapping(value = "bad7") + public void bad7(HttpServletRequest request) { + String name = "ttemplate"; + String code = request.getParameter("code"); + + VelocityContext context = new VelocityContext(); + context.put("code", code); + + StringWriter w = new StringWriter(); + Template t = new Template(); + t.merge(context, w, new LinkedList()); + } + + @GetMapping(value = "bad8") + public void bad8(HttpServletRequest request) { + String code = request.getParameter("code"); + + StringResourceRepository repo = new StringResourceRepositoryImpl(); + repo.putStringResource("woogie2", code); + + } +} diff --git a/java/ql/test/experimental/query-tests/security/CWE-094/options b/java/ql/test/experimental/query-tests/security/CWE-094/options index 606b83a6dcc9..d527e41cc4db 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-094/options +++ b/java/ql/test/experimental/query-tests/security/CWE-094/options @@ -1 +1 @@ -//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/springframework-5.3.8:${testdir}/../../../../stubs/jsr223-api:${testdir}/../../../../stubs/scriptengine:${testdir}/../../../../stubs/java-ee-el:${testdir}/../../../../stubs/juel-2.2:${testdir}/../../../../stubs/servlet-api-2.4:${testdir}/../../../../stubs/jython-2.7.2:${testdir}/../../../../experimental/stubs/rhino-1.7.13:${testdir}/../../../../stubs/bsh-2.0b5:${testdir}/../../../../experimental/stubs/jshell +//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/springframework-5.3.8:${testdir}/../../../../stubs/jsr223-api:${testdir}/../../../../stubs/scriptengine:${testdir}/../../../../stubs/java-ee-el:${testdir}/../../../../stubs/juel-2.2:${testdir}/../../../../stubs/servlet-api-2.4:${testdir}/../../../../stubs/jython-2.7.2:${testdir}/../../../../experimental/stubs/rhino-1.7.13:${testdir}/../../../../stubs/bsh-2.0b5:${testdir}/../../../../experimental/stubs/jshell:${testdir}/../../../../experimental/stubs/apache-freemarker-2.3.31:${testdir}/../../../../experimental/stubs/jinjava-2.6.0:${testdir}/../../../../experimental/stubs/pebble-3.1.5:${testdir}/../../../../experimental/stubs/thymeleaf-3.0.14:${testdir}/../../../../experimental/stubs/apache-velocity-2.3 \ No newline at end of file diff --git a/java/ql/test/experimental/stubs/apache-freemarker-2.3.31/freemarker/cache/StringTemplateLoader.java b/java/ql/test/experimental/stubs/apache-freemarker-2.3.31/freemarker/cache/StringTemplateLoader.java new file mode 100644 index 000000000000..1dd644063c10 --- /dev/null +++ b/java/ql/test/experimental/stubs/apache-freemarker-2.3.31/freemarker/cache/StringTemplateLoader.java @@ -0,0 +1,7 @@ +package freemarker.cache; + +public class StringTemplateLoader { + public StringTemplateLoader() {} + public void putTemplate(java.lang.String name, java.lang.String templateContent){} + public void putTemplate(java.lang.String name, java.lang.String templateContent, long lastModified){} +} \ No newline at end of file diff --git a/java/ql/test/experimental/stubs/apache-freemarker-2.3.31/freemarker/template/Configuration.java b/java/ql/test/experimental/stubs/apache-freemarker-2.3.31/freemarker/template/Configuration.java new file mode 100644 index 000000000000..3c4b9190e949 --- /dev/null +++ b/java/ql/test/experimental/stubs/apache-freemarker-2.3.31/freemarker/template/Configuration.java @@ -0,0 +1,9 @@ +package freemarker.template; + +import freemarker.template.Template; + +public class Configuration implements ParserConfiguration { + + public Configuration() {} + public Template getTemplate(java.lang.String name){return null;} +} diff --git a/java/ql/test/experimental/stubs/apache-freemarker-2.3.31/freemarker/template/ObjectWrapper.java b/java/ql/test/experimental/stubs/apache-freemarker-2.3.31/freemarker/template/ObjectWrapper.java new file mode 100644 index 000000000000..53eece8a9f42 --- /dev/null +++ b/java/ql/test/experimental/stubs/apache-freemarker-2.3.31/freemarker/template/ObjectWrapper.java @@ -0,0 +1,3 @@ +package freemarker.template; + +public interface ObjectWrapper {} diff --git a/java/ql/test/experimental/stubs/apache-freemarker-2.3.31/freemarker/template/ParserConfiguration.java b/java/ql/test/experimental/stubs/apache-freemarker-2.3.31/freemarker/template/ParserConfiguration.java new file mode 100644 index 000000000000..83e646f39c6a --- /dev/null +++ b/java/ql/test/experimental/stubs/apache-freemarker-2.3.31/freemarker/template/ParserConfiguration.java @@ -0,0 +1,3 @@ +package freemarker.template; + +public interface ParserConfiguration {} diff --git a/java/ql/test/experimental/stubs/apache-freemarker-2.3.31/freemarker/template/Template.java b/java/ql/test/experimental/stubs/apache-freemarker-2.3.31/freemarker/template/Template.java new file mode 100644 index 000000000000..ff72e8747c48 --- /dev/null +++ b/java/ql/test/experimental/stubs/apache-freemarker-2.3.31/freemarker/template/Template.java @@ -0,0 +1,55 @@ +package freemarker.template; + +import java.io.Reader; +import java.lang.String; + +public class Template { + + public Template(String name, Reader reader) { + } + + public Template(String name, Reader reader, Configuration cfg) { + } + + public Template(String name, Reader reader, Configuration cfg, String encoding) { + } + + public Template(String name, String sourceCode, Configuration cfg) { + } + + public Template(String name, String sourceName, Reader reader, Configuration cfg) { + } + + public Template( + String name, + String sourceName, + Reader reader, + Configuration cfg, + ParserConfiguration customParserConfiguration, + String encoding) { + } + + public Template( + String name, + String sourceName, + Reader reader, + Configuration cfg, + String encoding) { + } + + public void process(java.lang.Object dataModel, java.io.Writer out) { + } + + public void process( + java.lang.Object dataModel, + java.io.Writer out, + ObjectWrapper wrapper) { + } + + public void process( + java.lang.Object dataModel, + java.io.Writer out, + ObjectWrapper wrapper, + TemplateNodeModel rootNode) { + } +} diff --git a/java/ql/test/experimental/stubs/apache-freemarker-2.3.31/freemarker/template/TemplateNodeModel.java b/java/ql/test/experimental/stubs/apache-freemarker-2.3.31/freemarker/template/TemplateNodeModel.java new file mode 100644 index 000000000000..4b4c14ad11db --- /dev/null +++ b/java/ql/test/experimental/stubs/apache-freemarker-2.3.31/freemarker/template/TemplateNodeModel.java @@ -0,0 +1,3 @@ +package freemarker.template; + +public interface TemplateNodeModel {} diff --git a/java/ql/test/experimental/stubs/apache-velocity-2.3/org/apache/velocity/Template.java b/java/ql/test/experimental/stubs/apache-velocity-2.3/org/apache/velocity/Template.java new file mode 100644 index 000000000000..933006f59444 --- /dev/null +++ b/java/ql/test/experimental/stubs/apache-velocity-2.3/org/apache/velocity/Template.java @@ -0,0 +1,13 @@ +package org.apache.velocity; + +import org.apache.velocity.context.Context; +import java.io.Writer; +import java.util.List; + +public class Template { + public void merge(Context context, Writer writer) { + } + + public void merge(Context context, Writer writer, List macroLibraries) { + } +} diff --git a/java/ql/test/experimental/stubs/apache-velocity-2.3/org/apache/velocity/VelocityContext.java b/java/ql/test/experimental/stubs/apache-velocity-2.3/org/apache/velocity/VelocityContext.java new file mode 100644 index 000000000000..3f28c3edf5e7 --- /dev/null +++ b/java/ql/test/experimental/stubs/apache-velocity-2.3/org/apache/velocity/VelocityContext.java @@ -0,0 +1,10 @@ +package org.apache.velocity; + +import org.apache.velocity.context.AbstractContext; +import org.apache.velocity.context.Context; +import java.io.Writer; + +public class VelocityContext extends AbstractContext implements Context { + public VelocityContext() { + } +} diff --git a/java/ql/test/experimental/stubs/apache-velocity-2.3/org/apache/velocity/VelocityEngine.java b/java/ql/test/experimental/stubs/apache-velocity-2.3/org/apache/velocity/VelocityEngine.java new file mode 100644 index 000000000000..b9f758fc2292 --- /dev/null +++ b/java/ql/test/experimental/stubs/apache-velocity-2.3/org/apache/velocity/VelocityEngine.java @@ -0,0 +1,20 @@ +package org.apache.velocity; + +import org.apache.velocity.context; +import java.io.Writer; +import java.lang.String; +import java.io.Reader; + +public class VelocityEngine { + public static boolean evaluate(Context context, Writer out, String logTag, String instring) { + return true; + } + + public static boolean evaluate(Context context, Writer writer, String logTag, Reader reader) { + return true; + } + + public static boolean mergeTemplate(String templateName, String encoding, Context context, Writer writer) { + return true; + } +} diff --git a/java/ql/test/experimental/stubs/apache-velocity-2.3/org/apache/velocity/app/Velocity.java b/java/ql/test/experimental/stubs/apache-velocity-2.3/org/apache/velocity/app/Velocity.java new file mode 100644 index 000000000000..d1d38019dbe5 --- /dev/null +++ b/java/ql/test/experimental/stubs/apache-velocity-2.3/org/apache/velocity/app/Velocity.java @@ -0,0 +1,15 @@ +package org.apache.velocity.app; + +import org.apache.velocity.context.Context; +import java.io.Reader; +import java.io.Writer; + +public class Velocity { + public static boolean evaluate(Context context, Writer out, String logTag, String instring) { + return true; + } + + public static boolean evaluate(Context context, Writer writer, String logTag, Reader reader) { + return true; + } +} diff --git a/java/ql/test/experimental/stubs/apache-velocity-2.3/org/apache/velocity/app/VelocityEngine.java b/java/ql/test/experimental/stubs/apache-velocity-2.3/org/apache/velocity/app/VelocityEngine.java new file mode 100644 index 000000000000..f68b1ca19d55 --- /dev/null +++ b/java/ql/test/experimental/stubs/apache-velocity-2.3/org/apache/velocity/app/VelocityEngine.java @@ -0,0 +1,20 @@ +package org.apache.velocity.app; + +import org.apache.velocity.context.Context; +import java.io.Writer; +import java.lang.String; +import java.io.Reader; + +public class VelocityEngine { + public static boolean evaluate(Context context, Writer out, String logTag, String instring) { + return true; + } + + public static boolean evaluate(Context context, Writer writer, String logTag, Reader reader) { + return true; + } + + public static boolean mergeTemplate(String templateName, String encoding, Context context, Writer writer) { + return true; + } +} diff --git a/java/ql/test/experimental/stubs/apache-velocity-2.3/org/apache/velocity/context/AbstractContext.java b/java/ql/test/experimental/stubs/apache-velocity-2.3/org/apache/velocity/context/AbstractContext.java new file mode 100644 index 000000000000..bdb94850e256 --- /dev/null +++ b/java/ql/test/experimental/stubs/apache-velocity-2.3/org/apache/velocity/context/AbstractContext.java @@ -0,0 +1,14 @@ +package org.apache.velocity.context; + +import org.apache.velocity.context.Context; +import java.io.Writer; + +public class AbstractContext implements Context { + public Object put(String key, Object value) { + return null; + } + + public Object internalPut(String key, Object value) { + return null; + } +} diff --git a/java/ql/test/experimental/stubs/apache-velocity-2.3/org/apache/velocity/context/Context.java b/java/ql/test/experimental/stubs/apache-velocity-2.3/org/apache/velocity/context/Context.java new file mode 100644 index 000000000000..c32f4308d398 --- /dev/null +++ b/java/ql/test/experimental/stubs/apache-velocity-2.3/org/apache/velocity/context/Context.java @@ -0,0 +1,7 @@ +package org.apache.velocity.context; + +public interface Context { + public Object put(String key, Object value); + + public Object internalPut(String key, Object value); +} diff --git a/java/ql/test/experimental/stubs/apache-velocity-2.3/org/apache/velocity/runtime/RuntimeServices.java b/java/ql/test/experimental/stubs/apache-velocity-2.3/org/apache/velocity/runtime/RuntimeServices.java new file mode 100644 index 000000000000..bdf61a72a520 --- /dev/null +++ b/java/ql/test/experimental/stubs/apache-velocity-2.3/org/apache/velocity/runtime/RuntimeServices.java @@ -0,0 +1,25 @@ +package org.apache.velocity.runtime; + +import org.apache.velocity.runtime.parser.node.*; + +import org.apache.velocity.context.Context; +import java.io.Reader; +import java.io.Writer; +import org.apache.velocity.Template; + +public class RuntimeServices { + public RuntimeServices() { + } + + public static SimpleNode parse(Reader reader, Template template) { + return null; + } + + public static boolean evaluate(Context context, Writer out, String logTag, String instring) { + return true; + } + + public static boolean evaluate(Context context, Writer writer, String logTag, Reader reader) { + return true; + } +} diff --git a/java/ql/test/experimental/stubs/apache-velocity-2.3/org/apache/velocity/runtime/RuntimeSingleton.java b/java/ql/test/experimental/stubs/apache-velocity-2.3/org/apache/velocity/runtime/RuntimeSingleton.java new file mode 100644 index 000000000000..4b89c59e2ca0 --- /dev/null +++ b/java/ql/test/experimental/stubs/apache-velocity-2.3/org/apache/velocity/runtime/RuntimeSingleton.java @@ -0,0 +1,8 @@ +package org.apache.velocity.runtime; + +import org.apache.velocity.runtime.parser.node.*; + +public class RuntimeSingleton { + public static SimpleNode parse(Reader reader, Template template) { + } +} diff --git a/java/ql/test/experimental/stubs/apache-velocity-2.3/org/apache/velocity/runtime/parser/node/SimpleNode.java b/java/ql/test/experimental/stubs/apache-velocity-2.3/org/apache/velocity/runtime/parser/node/SimpleNode.java new file mode 100644 index 000000000000..5e8a3695ba51 --- /dev/null +++ b/java/ql/test/experimental/stubs/apache-velocity-2.3/org/apache/velocity/runtime/parser/node/SimpleNode.java @@ -0,0 +1,5 @@ +package org.apache.velocity.runtime.parser.node; + +public class SimpleNode { + +} diff --git a/java/ql/test/experimental/stubs/apache-velocity-2.3/org/apache/velocity/runtime/resource/util/StringResourceRepository.java b/java/ql/test/experimental/stubs/apache-velocity-2.3/org/apache/velocity/runtime/resource/util/StringResourceRepository.java new file mode 100644 index 000000000000..8043d4b7136f --- /dev/null +++ b/java/ql/test/experimental/stubs/apache-velocity-2.3/org/apache/velocity/runtime/resource/util/StringResourceRepository.java @@ -0,0 +1,7 @@ +package org.apache.velocity.runtime.resource.util; + +public interface StringResourceRepository { + public void putStringResource(String name, String body); + + public void putStringResource(String name, String body, String encoding); +} diff --git a/java/ql/test/experimental/stubs/apache-velocity-2.3/org/apache/velocity/runtime/resource/util/StringResourceRepositoryImpl.java b/java/ql/test/experimental/stubs/apache-velocity-2.3/org/apache/velocity/runtime/resource/util/StringResourceRepositoryImpl.java new file mode 100644 index 000000000000..01845deed974 --- /dev/null +++ b/java/ql/test/experimental/stubs/apache-velocity-2.3/org/apache/velocity/runtime/resource/util/StringResourceRepositoryImpl.java @@ -0,0 +1,9 @@ +package org.apache.velocity.runtime.resource.util; + +public class StringResourceRepositoryImpl implements StringResourceRepository { + public void putStringResource(String name, String body) { + } + + public void putStringResource(String name, String body, String encoding) { + } +} diff --git a/java/ql/test/experimental/stubs/jinjava-2.6.0/com/hubspot/jinjava/Jinjava.java b/java/ql/test/experimental/stubs/jinjava-2.6.0/com/hubspot/jinjava/Jinjava.java new file mode 100644 index 000000000000..8f00ee19b796 --- /dev/null +++ b/java/ql/test/experimental/stubs/jinjava-2.6.0/com/hubspot/jinjava/Jinjava.java @@ -0,0 +1,24 @@ +package com.hubspot.jinjava; + +import com.hubspot.jinjava.JinjavaConfig; +import com.hubspot.jinjava.interpret.RenderResult; + +import java.lang.String; +import java.util.Map; + +public class Jinjava { + public Jinjava() { + } + + public String render(String template, Map bindings) { + return "test"; + }; + + public RenderResult renderForResult(String template, Map bindings) { + return new RenderResult("result"); + } + + public RenderResult renderForResult(String template, Map bindings, JinjavaConfig renderConfig) { + return new RenderResult("result"); + } +} diff --git a/java/ql/test/experimental/stubs/jinjava-2.6.0/com/hubspot/jinjava/JinjavaConfig.java b/java/ql/test/experimental/stubs/jinjava-2.6.0/com/hubspot/jinjava/JinjavaConfig.java new file mode 100644 index 000000000000..6b6fc076cc3c --- /dev/null +++ b/java/ql/test/experimental/stubs/jinjava-2.6.0/com/hubspot/jinjava/JinjavaConfig.java @@ -0,0 +1,5 @@ +package com.hubspot.jinjava; + +public class JinjavaConfig { + +} diff --git a/java/ql/test/experimental/stubs/jinjava-2.6.0/com/hubspot/jinjava/interpret/RenderResult.java b/java/ql/test/experimental/stubs/jinjava-2.6.0/com/hubspot/jinjava/interpret/RenderResult.java new file mode 100644 index 000000000000..c9a9b2265d7d --- /dev/null +++ b/java/ql/test/experimental/stubs/jinjava-2.6.0/com/hubspot/jinjava/interpret/RenderResult.java @@ -0,0 +1,6 @@ +package com.hubspot.jinjava.interpret; + +public class RenderResult { + public RenderResult(String result) { + } +} diff --git a/java/ql/test/experimental/stubs/pebble-3.1.5/com/mitchellbosecke/pebble/PebbleEngine.java b/java/ql/test/experimental/stubs/pebble-3.1.5/com/mitchellbosecke/pebble/PebbleEngine.java new file mode 100644 index 000000000000..60506ce81d4e --- /dev/null +++ b/java/ql/test/experimental/stubs/pebble-3.1.5/com/mitchellbosecke/pebble/PebbleEngine.java @@ -0,0 +1,27 @@ +package com.mitchellbosecke.pebble; + +import com.mitchellbosecke.pebble.template.*; + +public class PebbleEngine { + public static class Builder { + public Builder() { + }; + + public PebbleEngine build() { + return new PebbleEngine(); + } + }; + + PebbleEngine() { + } + + public PebbleTemplate getLiteralTemplate(String templateName) { + return new PebbleTemplate() { + }; + } + + public PebbleTemplate getTemplate(String templateName) { + return new PebbleTemplate() { + }; + } +} diff --git a/java/ql/test/experimental/stubs/pebble-3.1.5/com/mitchellbosecke/pebble/template/PebbleTemplate.java b/java/ql/test/experimental/stubs/pebble-3.1.5/com/mitchellbosecke/pebble/template/PebbleTemplate.java new file mode 100644 index 000000000000..3f7ff70aec98 --- /dev/null +++ b/java/ql/test/experimental/stubs/pebble-3.1.5/com/mitchellbosecke/pebble/template/PebbleTemplate.java @@ -0,0 +1,3 @@ +package com.mitchellbosecke.pebble.template; + +public interface PebbleTemplate {} \ No newline at end of file diff --git a/java/ql/test/experimental/stubs/thymeleaf-3.0.14/org/thymeleaf/ITemplateEngine.java b/java/ql/test/experimental/stubs/thymeleaf-3.0.14/org/thymeleaf/ITemplateEngine.java new file mode 100644 index 000000000000..0ffad058ee19 --- /dev/null +++ b/java/ql/test/experimental/stubs/thymeleaf-3.0.14/org/thymeleaf/ITemplateEngine.java @@ -0,0 +1,28 @@ +package org.thymeleaf; + +import java.io.Writer; +import java.lang.String; +import java.util.Set; +import org.thymeleaf.context.IContext; +import org.thymeleaf.*; + +public interface ITemplateEngine { + + public String process(String template, Set templateSelectors, IContext context); + + public void process(String template, Set templateSelectors, IContext context, Writer writer); + + public String process(String template, IContext context); + + public void process(String template, IContext context, Writer writer); + + public String process(TemplateSpec templateSpec, IContext context); + + public void process(TemplateSpec templateSpec, IContext context, Writer writer); + + public IThrottledTemplateProcessor processThrottled(String template, Set templateSelectors, IContext context); + + public IThrottledTemplateProcessor processThrottled(String template, IContext context); + + public IThrottledTemplateProcessor processThrottled(TemplateSpec templateSpec, IContext context); +} diff --git a/java/ql/test/experimental/stubs/thymeleaf-3.0.14/org/thymeleaf/IThrottledTemplateProcessor.java b/java/ql/test/experimental/stubs/thymeleaf-3.0.14/org/thymeleaf/IThrottledTemplateProcessor.java new file mode 100644 index 000000000000..d1bcd3e7c401 --- /dev/null +++ b/java/ql/test/experimental/stubs/thymeleaf-3.0.14/org/thymeleaf/IThrottledTemplateProcessor.java @@ -0,0 +1,5 @@ +package org.thymeleaf; + +public interface IThrottledTemplateProcessor { + +} diff --git a/java/ql/test/experimental/stubs/thymeleaf-3.0.14/org/thymeleaf/TemplateEngine.java b/java/ql/test/experimental/stubs/thymeleaf-3.0.14/org/thymeleaf/TemplateEngine.java new file mode 100644 index 000000000000..3c51d321ddf4 --- /dev/null +++ b/java/ql/test/experimental/stubs/thymeleaf-3.0.14/org/thymeleaf/TemplateEngine.java @@ -0,0 +1,51 @@ +package org.thymeleaf; + +import java.io.Writer; +import java.lang.String; +import java.util.Set; +import org.thymeleaf.context.IContext; +import org.thymeleaf.TemplateSpec; +import org.thymeleaf.ITemplateEngine; +import org.thymeleaf.IThrottledTemplateProcessor; + +public class TemplateEngine implements ITemplateEngine { + + public String process(String template, Set templateSelectors, IContext context) { + return ""; + } + + public void process(String template, Set templateSelectors, IContext context, Writer writer) { + } + + public String process(String template, IContext context) { + return ""; + } + + public void process(String template, IContext context, Writer writer) { + } + + public String process(TemplateSpec templateSpec, IContext context) { + return ""; + } + + public void process(TemplateSpec templateSpec, IContext context, Writer writer) { + } + + public IThrottledTemplateProcessor processThrottled(String template, Set templateSelectors, + IContext context) { + return new IThrottledTemplateProcessor() { + }; + } + + public IThrottledTemplateProcessor processThrottled(String template, IContext context) { + return new IThrottledTemplateProcessor() { + }; + + } + + public IThrottledTemplateProcessor processThrottled(TemplateSpec templateSpec, IContext context) { + return new IThrottledTemplateProcessor() { + }; + + } +} diff --git a/java/ql/test/experimental/stubs/thymeleaf-3.0.14/org/thymeleaf/TemplateSpec.java b/java/ql/test/experimental/stubs/thymeleaf-3.0.14/org/thymeleaf/TemplateSpec.java new file mode 100644 index 000000000000..59687892527a --- /dev/null +++ b/java/ql/test/experimental/stubs/thymeleaf-3.0.14/org/thymeleaf/TemplateSpec.java @@ -0,0 +1,5 @@ +package org.thymeleaf; + +public class TemplateSpec { + +} diff --git a/java/ql/test/experimental/stubs/thymeleaf-3.0.14/org/thymeleaf/context/Context.java b/java/ql/test/experimental/stubs/thymeleaf-3.0.14/org/thymeleaf/context/Context.java new file mode 100644 index 000000000000..afba6712ad7a --- /dev/null +++ b/java/ql/test/experimental/stubs/thymeleaf-3.0.14/org/thymeleaf/context/Context.java @@ -0,0 +1,7 @@ +package org.thymeleaf.context; + +import org.thymeleaf.context.IContext; + +public class Context implements IContext { + +} diff --git a/java/ql/test/experimental/stubs/thymeleaf-3.0.14/org/thymeleaf/context/IContext.java b/java/ql/test/experimental/stubs/thymeleaf-3.0.14/org/thymeleaf/context/IContext.java new file mode 100644 index 000000000000..131de89067d4 --- /dev/null +++ b/java/ql/test/experimental/stubs/thymeleaf-3.0.14/org/thymeleaf/context/IContext.java @@ -0,0 +1,5 @@ +package org.thymeleaf.context; + +public interface IContext { + +} From c81d85f32185e91adabcbe3729bc01d077c360e4 Mon Sep 17 00:00:00 2001 From: Porcupiney Hairs Date: Tue, 22 Feb 2022 23:07:34 +0530 Subject: [PATCH 2/6] Include suggestions from review --- .../experimental/Security/CWE/CWE-094/TemplateInjection.qhelp | 4 ++-- .../query-tests/security/CWE-094/JinJavaSSTI.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/TemplateInjection.qhelp b/java/ql/src/experimental/Security/CWE/CWE-094/TemplateInjection.qhelp index 86d821b85205..882e9cecab1b 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-094/TemplateInjection.qhelp +++ b/java/ql/src/experimental/Security/CWE/CWE-094/TemplateInjection.qhelp @@ -16,14 +16,14 @@ code is used as a Velocity template string. This can lead to remote code execution.

    - +

    In the next example the problem is avoided by using a fixed template string s . Since, the template is not attacker controlled in this case, we prevent untrusted code execution.

    - +
  • Portswigger : [Server Side Template Injection](https://portswigger.net/web-security/server-side-template-injection)
  • diff --git a/java/ql/test/experimental/query-tests/security/CWE-094/JinJavaSSTI.java b/java/ql/test/experimental/query-tests/security/CWE-094/JinJavaSSTI.java index 5f0d932678d7..0a2f5a4fe04b 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-094/JinJavaSSTI.java +++ b/java/ql/test/experimental/query-tests/security/CWE-094/JinJavaSSTI.java @@ -21,7 +21,7 @@ public void bad1(HttpServletRequest request) { String template = request.getParameter("template"); Jinjava jinjava = new Jinjava(); Map context = new HashMap<>(); - // String render​(String template, Map bindings) + // String render(String template, Map bindings) String renderedTemplate = jinjava.render(template, context); } From 476997a599e737c091f07da3ade1efd4e6d226af Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Wed, 23 Feb 2022 11:02:17 +0000 Subject: [PATCH 3/6] Replace more non-breaking spaces --- .../query-tests/security/CWE-094/JinJavaSSTI.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/java/ql/test/experimental/query-tests/security/CWE-094/JinJavaSSTI.java b/java/ql/test/experimental/query-tests/security/CWE-094/JinJavaSSTI.java index 0a2f5a4fe04b..a5791ae1d570 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-094/JinJavaSSTI.java +++ b/java/ql/test/experimental/query-tests/security/CWE-094/JinJavaSSTI.java @@ -21,7 +21,7 @@ public void bad1(HttpServletRequest request) { String template = request.getParameter("template"); Jinjava jinjava = new Jinjava(); Map context = new HashMap<>(); - // String render(String template, Map bindings) + // String render(String template, Map bindings) String renderedTemplate = jinjava.render(template, context); } @@ -30,7 +30,7 @@ public void bad2(HttpServletRequest request) { String template = request.getParameter("template"); Jinjava jinjava = new Jinjava(); Map bindings = new HashMap<>(); - // RenderResult renderForResult​(String template, Map bindings) + // RenderResult renderForResult (String template, Map bindings) RenderResult renderResult = jinjava.renderForResult(template, bindings); } @@ -41,7 +41,7 @@ public void bad3(HttpServletRequest request) { Map bindings = new HashMap<>(); JinjavaConfig renderConfig = new JinjavaConfig(); - // RenderResult renderForResult​(String template, Map bindings, + // RenderResult renderForResult (String template, Map bindings, // JinjavaConfig renderConfig) RenderResult renderResult = jinjava.renderForResult(template, bindings, renderConfig); } From 50d99456252125e862676fc10ce754f09f32816d Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Wed, 23 Feb 2022 11:41:23 +0000 Subject: [PATCH 4/6] Autoformat --- .../semmle/code/java/frameworks/Thymeleaf.qll | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/java/ql/src/experimental/semmle/code/java/frameworks/Thymeleaf.qll b/java/ql/src/experimental/semmle/code/java/frameworks/Thymeleaf.qll index 18235257be1d..e93f2739be1a 100644 --- a/java/ql/src/experimental/semmle/code/java/frameworks/Thymeleaf.qll +++ b/java/ql/src/experimental/semmle/code/java/frameworks/Thymeleaf.qll @@ -2,10 +2,10 @@ import java -/** - * A class implementing the `ITemplateEngine` interface of the Thymeleaf - * Templating Engine such as the `TemplateEngine` class. - * */ +/** + * A class implementing the `ITemplateEngine` interface of the Thymeleaf + * Templating Engine such as the `TemplateEngine` class. + */ class TypeThymeleafTemplateEngine extends Class { TypeThymeleafTemplateEngine() { this.hasQualifiedName("org.thymeleaf", "TemplateEngine") From a8fe10f3535e079a215db4afecb54ec07452ce9d Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Wed, 23 Feb 2022 13:47:24 +0000 Subject: [PATCH 5/6] Java template injection query: import pathgraph --- .../src/experimental/Security/CWE/CWE-094/TemplateInjection.ql | 1 + 1 file changed, 1 insertion(+) diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/TemplateInjection.ql b/java/ql/src/experimental/Security/CWE/CWE-094/TemplateInjection.ql index d4dc0c3952ef..18e47d2c6b35 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-094/TemplateInjection.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-094/TemplateInjection.ql @@ -11,6 +11,7 @@ import java import TemplateInjection +import DataFlow::PathGraph from TemplateInjectionFlowConfig config, DataFlow::PathNode source, DataFlow::PathNode sink where config.hasFlowPath(source, sink) From 7b425a80bc4b143fd0f3d0501b4b6da99b514a94 Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Wed, 23 Feb 2022 16:02:54 +0000 Subject: [PATCH 6/6] Note path query expectations --- .../CWE-094/TemplateInjection.expected | 112 ++++++++++++++++++ 1 file changed, 112 insertions(+) diff --git a/java/ql/test/experimental/query-tests/security/CWE-094/TemplateInjection.expected b/java/ql/test/experimental/query-tests/security/CWE-094/TemplateInjection.expected index dc884612625e..9b739f8d1daa 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-094/TemplateInjection.expected +++ b/java/ql/test/experimental/query-tests/security/CWE-094/TemplateInjection.expected @@ -1,3 +1,115 @@ +edges +| FreemarkerSSTI.java:23:17:23:44 | getParameter(...) : String | FreemarkerSSTI.java:24:36:24:39 | code : String | +| FreemarkerSSTI.java:24:19:24:40 | new StringReader(...) : StringReader | FreemarkerSSTI.java:27:35:27:40 | reader | +| FreemarkerSSTI.java:24:36:24:39 | code : String | FreemarkerSSTI.java:24:19:24:40 | new StringReader(...) : StringReader | +| FreemarkerSSTI.java:33:17:33:44 | getParameter(...) : String | FreemarkerSSTI.java:34:36:34:39 | code : String | +| FreemarkerSSTI.java:34:19:34:40 | new StringReader(...) : StringReader | FreemarkerSSTI.java:38:35:38:40 | reader | +| FreemarkerSSTI.java:34:36:34:39 | code : String | FreemarkerSSTI.java:34:19:34:40 | new StringReader(...) : StringReader | +| FreemarkerSSTI.java:44:17:44:44 | getParameter(...) : String | FreemarkerSSTI.java:45:36:45:39 | code : String | +| FreemarkerSSTI.java:45:19:45:40 | new StringReader(...) : StringReader | FreemarkerSSTI.java:50:35:50:40 | reader | +| FreemarkerSSTI.java:45:36:45:39 | code : String | FreemarkerSSTI.java:45:19:45:40 | new StringReader(...) : StringReader | +| FreemarkerSSTI.java:56:23:56:56 | getParameter(...) : String | FreemarkerSSTI.java:61:35:61:44 | sourceCode | +| FreemarkerSSTI.java:67:17:67:44 | getParameter(...) : String | FreemarkerSSTI.java:69:36:69:39 | code : String | +| FreemarkerSSTI.java:69:19:69:40 | new StringReader(...) : StringReader | FreemarkerSSTI.java:73:47:73:52 | reader | +| FreemarkerSSTI.java:69:36:69:39 | code : String | FreemarkerSSTI.java:69:19:69:40 | new StringReader(...) : StringReader | +| FreemarkerSSTI.java:79:17:79:44 | getParameter(...) : String | FreemarkerSSTI.java:82:36:82:39 | code : String | +| FreemarkerSSTI.java:82:19:82:40 | new StringReader(...) : StringReader | FreemarkerSSTI.java:87:47:87:52 | reader | +| FreemarkerSSTI.java:82:36:82:39 | code : String | FreemarkerSSTI.java:82:19:82:40 | new StringReader(...) : StringReader | +| FreemarkerSSTI.java:93:17:93:44 | getParameter(...) : String | FreemarkerSSTI.java:96:36:96:39 | code : String | +| FreemarkerSSTI.java:96:19:96:40 | new StringReader(...) : StringReader | FreemarkerSSTI.java:100:47:100:52 | reader | +| FreemarkerSSTI.java:96:36:96:39 | code : String | FreemarkerSSTI.java:96:19:96:40 | new StringReader(...) : StringReader | +| FreemarkerSSTI.java:105:17:105:44 | getParameter(...) : String | FreemarkerSSTI.java:109:42:109:45 | code | +| FreemarkerSSTI.java:114:17:114:44 | getParameter(...) : String | FreemarkerSSTI.java:119:42:119:45 | code | +| FreemarkerSSTI.java:125:17:125:44 | getParameter(...) : String | FreemarkerSSTI.java:126:26:126:29 | code : String | +| FreemarkerSSTI.java:126:9:126:12 | root [post update] [] : String | FreemarkerSSTI.java:130:22:130:25 | root | +| FreemarkerSSTI.java:126:26:126:29 | code : String | FreemarkerSSTI.java:126:9:126:12 | root [post update] [] : String | +| JinJavaSSTI.java:21:21:21:52 | getParameter(...) : String | JinJavaSSTI.java:25:44:25:51 | template | +| JinJavaSSTI.java:30:21:30:52 | getParameter(...) : String | JinJavaSSTI.java:34:55:34:62 | template | +| JinJavaSSTI.java:39:21:39:52 | getParameter(...) : String | JinJavaSSTI.java:46:55:46:62 | template | +| PebbleSSTI.java:18:17:18:44 | getParameter(...) : String | PebbleSSTI.java:21:56:21:59 | code | +| PebbleSSTI.java:25:17:25:44 | getParameter(...) : String | PebbleSSTI.java:28:63:28:66 | code | +| ThymeleafSSTI.java:22:17:22:44 | getParameter(...) : String | ThymeleafSSTI.java:27:27:27:30 | code | +| VelocitySSTI.java:31:17:31:44 | getParameter(...) : String | VelocitySSTI.java:38:45:38:48 | code | +| VelocitySSTI.java:44:17:44:44 | getParameter(...) : String | VelocitySSTI.java:50:42:50:45 | code : String | +| VelocitySSTI.java:50:25:50:46 | new StringReader(...) : StringReader | VelocitySSTI.java:53:45:53:50 | reader | +| VelocitySSTI.java:50:42:50:45 | code : String | VelocitySSTI.java:50:25:50:46 | new StringReader(...) : StringReader | +| VelocitySSTI.java:59:17:59:44 | getParameter(...) : String | VelocitySSTI.java:62:42:62:45 | code : String | +| VelocitySSTI.java:62:25:62:46 | new StringReader(...) : StringReader | VelocitySSTI.java:63:25:63:30 | reader | +| VelocitySSTI.java:62:42:62:45 | code : String | VelocitySSTI.java:62:25:62:46 | new StringReader(...) : StringReader | +| VelocitySSTI.java:69:17:69:44 | getParameter(...) : String | VelocitySSTI.java:77:21:77:27 | context | +| VelocitySSTI.java:83:17:83:44 | getParameter(...) : String | VelocitySSTI.java:89:60:89:66 | context | +| VelocitySSTI.java:95:17:95:44 | getParameter(...) : String | VelocitySSTI.java:102:11:102:17 | context | +| VelocitySSTI.java:108:17:108:44 | getParameter(...) : String | VelocitySSTI.java:115:11:115:17 | context | +| VelocitySSTI.java:120:17:120:44 | getParameter(...) : String | VelocitySSTI.java:123:37:123:40 | code | +nodes +| FreemarkerSSTI.java:23:17:23:44 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| FreemarkerSSTI.java:24:19:24:40 | new StringReader(...) : StringReader | semmle.label | new StringReader(...) : StringReader | +| FreemarkerSSTI.java:24:36:24:39 | code : String | semmle.label | code : String | +| FreemarkerSSTI.java:27:35:27:40 | reader | semmle.label | reader | +| FreemarkerSSTI.java:33:17:33:44 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| FreemarkerSSTI.java:34:19:34:40 | new StringReader(...) : StringReader | semmle.label | new StringReader(...) : StringReader | +| FreemarkerSSTI.java:34:36:34:39 | code : String | semmle.label | code : String | +| FreemarkerSSTI.java:38:35:38:40 | reader | semmle.label | reader | +| FreemarkerSSTI.java:44:17:44:44 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| FreemarkerSSTI.java:45:19:45:40 | new StringReader(...) : StringReader | semmle.label | new StringReader(...) : StringReader | +| FreemarkerSSTI.java:45:36:45:39 | code : String | semmle.label | code : String | +| FreemarkerSSTI.java:50:35:50:40 | reader | semmle.label | reader | +| FreemarkerSSTI.java:56:23:56:56 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| FreemarkerSSTI.java:61:35:61:44 | sourceCode | semmle.label | sourceCode | +| FreemarkerSSTI.java:67:17:67:44 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| FreemarkerSSTI.java:69:19:69:40 | new StringReader(...) : StringReader | semmle.label | new StringReader(...) : StringReader | +| FreemarkerSSTI.java:69:36:69:39 | code : String | semmle.label | code : String | +| FreemarkerSSTI.java:73:47:73:52 | reader | semmle.label | reader | +| FreemarkerSSTI.java:79:17:79:44 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| FreemarkerSSTI.java:82:19:82:40 | new StringReader(...) : StringReader | semmle.label | new StringReader(...) : StringReader | +| FreemarkerSSTI.java:82:36:82:39 | code : String | semmle.label | code : String | +| FreemarkerSSTI.java:87:47:87:52 | reader | semmle.label | reader | +| FreemarkerSSTI.java:93:17:93:44 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| FreemarkerSSTI.java:96:19:96:40 | new StringReader(...) : StringReader | semmle.label | new StringReader(...) : StringReader | +| FreemarkerSSTI.java:96:36:96:39 | code : String | semmle.label | code : String | +| FreemarkerSSTI.java:100:47:100:52 | reader | semmle.label | reader | +| FreemarkerSSTI.java:105:17:105:44 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| FreemarkerSSTI.java:109:42:109:45 | code | semmle.label | code | +| FreemarkerSSTI.java:114:17:114:44 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| FreemarkerSSTI.java:119:42:119:45 | code | semmle.label | code | +| FreemarkerSSTI.java:125:17:125:44 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| FreemarkerSSTI.java:126:9:126:12 | root [post update] [] : String | semmle.label | root [post update] [] : String | +| FreemarkerSSTI.java:126:26:126:29 | code : String | semmle.label | code : String | +| FreemarkerSSTI.java:130:22:130:25 | root | semmle.label | root | +| JinJavaSSTI.java:21:21:21:52 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JinJavaSSTI.java:25:44:25:51 | template | semmle.label | template | +| JinJavaSSTI.java:30:21:30:52 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JinJavaSSTI.java:34:55:34:62 | template | semmle.label | template | +| JinJavaSSTI.java:39:21:39:52 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| JinJavaSSTI.java:46:55:46:62 | template | semmle.label | template | +| PebbleSSTI.java:18:17:18:44 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| PebbleSSTI.java:21:56:21:59 | code | semmle.label | code | +| PebbleSSTI.java:25:17:25:44 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| PebbleSSTI.java:28:63:28:66 | code | semmle.label | code | +| ThymeleafSSTI.java:22:17:22:44 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| ThymeleafSSTI.java:27:27:27:30 | code | semmle.label | code | +| VelocitySSTI.java:31:17:31:44 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| VelocitySSTI.java:38:45:38:48 | code | semmle.label | code | +| VelocitySSTI.java:44:17:44:44 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| VelocitySSTI.java:50:25:50:46 | new StringReader(...) : StringReader | semmle.label | new StringReader(...) : StringReader | +| VelocitySSTI.java:50:42:50:45 | code : String | semmle.label | code : String | +| VelocitySSTI.java:53:45:53:50 | reader | semmle.label | reader | +| VelocitySSTI.java:59:17:59:44 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| VelocitySSTI.java:62:25:62:46 | new StringReader(...) : StringReader | semmle.label | new StringReader(...) : StringReader | +| VelocitySSTI.java:62:42:62:45 | code : String | semmle.label | code : String | +| VelocitySSTI.java:63:25:63:30 | reader | semmle.label | reader | +| VelocitySSTI.java:69:17:69:44 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| VelocitySSTI.java:77:21:77:27 | context | semmle.label | context | +| VelocitySSTI.java:83:17:83:44 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| VelocitySSTI.java:89:60:89:66 | context | semmle.label | context | +| VelocitySSTI.java:95:17:95:44 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| VelocitySSTI.java:102:11:102:17 | context | semmle.label | context | +| VelocitySSTI.java:108:17:108:44 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| VelocitySSTI.java:115:11:115:17 | context | semmle.label | context | +| VelocitySSTI.java:120:17:120:44 | getParameter(...) : String | semmle.label | getParameter(...) : String | +| VelocitySSTI.java:123:37:123:40 | code | semmle.label | code | +subpaths +#select | FreemarkerSSTI.java:27:35:27:40 | reader | FreemarkerSSTI.java:23:17:23:44 | getParameter(...) : String | FreemarkerSSTI.java:27:35:27:40 | reader | Potential arbitrary code execution due to $@. | FreemarkerSSTI.java:23:17:23:44 | getParameter(...) | a template value loaded from a remote source. | | FreemarkerSSTI.java:38:35:38:40 | reader | FreemarkerSSTI.java:33:17:33:44 | getParameter(...) : String | FreemarkerSSTI.java:38:35:38:40 | reader | Potential arbitrary code execution due to $@. | FreemarkerSSTI.java:33:17:33:44 | getParameter(...) | a template value loaded from a remote source. | | FreemarkerSSTI.java:50:35:50:40 | reader | FreemarkerSSTI.java:44:17:44:44 | getParameter(...) : String | FreemarkerSSTI.java:50:35:50:40 | reader | Potential arbitrary code execution due to $@. | FreemarkerSSTI.java:44:17:44:44 | getParameter(...) | a template value loaded from a remote source. |