From f412f433bfbf468bd12d8aa877e3188cebdd33a4 Mon Sep 17 00:00:00 2001 From: Tony Torralba Date: Mon, 12 Sep 2022 17:01:16 +0200 Subject: [PATCH] Add thymeleaf steps --- .../code/java/dataflow/ExternalFlow.qll | 1 + .../semmle/code/java/frameworks/Thymeleaf.qll | 16 +++++ .../frameworks/thymeleaf/Test.java | 61 +++++++++++++++++++ .../frameworks/thymeleaf/options | 1 + .../frameworks/thymeleaf/test.expected | 0 .../frameworks/thymeleaf/test.ql | 2 + .../security/CWE-094/PebbleSSTI.java | 10 ++- .../security/CWE-094/ThymeleafSSTI.java | 17 ++++-- 8 files changed, 97 insertions(+), 11 deletions(-) create mode 100644 java/ql/lib/semmle/code/java/frameworks/Thymeleaf.qll create mode 100644 java/ql/test/library-tests/frameworks/thymeleaf/Test.java create mode 100644 java/ql/test/library-tests/frameworks/thymeleaf/options create mode 100644 java/ql/test/library-tests/frameworks/thymeleaf/test.expected create mode 100644 java/ql/test/library-tests/frameworks/thymeleaf/test.ql diff --git a/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll b/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll index 57c7af0ca4f..6c02f3a5790 100644 --- a/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll +++ b/java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll @@ -117,6 +117,7 @@ private module Frameworks { private import semmle.code.java.frameworks.Retrofit private import semmle.code.java.frameworks.Stream private import semmle.code.java.frameworks.Strings + private import semmle.code.java.frameworks.Thymeleaf private import semmle.code.java.frameworks.ratpack.Ratpack private import semmle.code.java.frameworks.ratpack.RatpackExec private import semmle.code.java.frameworks.spring.SpringCache diff --git a/java/ql/lib/semmle/code/java/frameworks/Thymeleaf.qll b/java/ql/lib/semmle/code/java/frameworks/Thymeleaf.qll new file mode 100644 index 00000000000..3c550d5441c --- /dev/null +++ b/java/ql/lib/semmle/code/java/frameworks/Thymeleaf.qll @@ -0,0 +1,16 @@ +/** + * Provides classes and predicates for working with the Thymeleaf template engine. + */ + +import java +private import semmle.code.java.dataflow.ExternalFlow + +private class ThymeleafSummaryModels extends SummaryModelCsv { + override predicate row(string row) { + row = + [ + "org.thymeleaf;TemplateSpec;false;TemplateSpec;;;Argument[0];Argument[-1];taint;manual", + "org.thymeleaf;TemplateSpec;false;getTemplate;;;Argument[-1];ReturnValue;taint;manual", + ] + } +} diff --git a/java/ql/test/library-tests/frameworks/thymeleaf/Test.java b/java/ql/test/library-tests/frameworks/thymeleaf/Test.java new file mode 100644 index 00000000000..7d0d193715f --- /dev/null +++ b/java/ql/test/library-tests/frameworks/thymeleaf/Test.java @@ -0,0 +1,61 @@ +package generatedtest; + +import java.util.Map; +import java.util.Set; +import org.thymeleaf.TemplateSpec; +import org.thymeleaf.templatemode.TemplateMode; + +// Test case generated by GenerateFlowTestCase.ql +public class Test { + + Object source() { return null; } + void sink(Object o) { } + + public void test() throws Exception { + + { + // "org.thymeleaf;TemplateSpec;false;TemplateSpec;;;Argument[0];Argument[-1];taint;manual" + TemplateSpec out = null; + String in = (String)source(); + out = new TemplateSpec(in, (Map)null); + sink(out); // $ hasTaintFlow + } + { + // "org.thymeleaf;TemplateSpec;false;TemplateSpec;;;Argument[0];Argument[-1];taint;manual" + TemplateSpec out = null; + String in = (String)source(); + out = new TemplateSpec(in, (Set)null, (String)null, (Map)null); + sink(out); // $ hasTaintFlow + } + { + // "org.thymeleaf;TemplateSpec;false;TemplateSpec;;;Argument[0];Argument[-1];taint;manual" + TemplateSpec out = null; + String in = (String)source(); + out = new TemplateSpec(in, (Set)null, (TemplateMode)null, (Map)null); + sink(out); // $ hasTaintFlow + } + { + // "org.thymeleaf;TemplateSpec;false;TemplateSpec;;;Argument[0];Argument[-1];taint;manual" + TemplateSpec out = null; + String in = (String)source(); + out = new TemplateSpec(in, (String)null); + sink(out); // $ hasTaintFlow + } + { + // "org.thymeleaf;TemplateSpec;false;TemplateSpec;;;Argument[0];Argument[-1];taint;manual" + TemplateSpec out = null; + String in = (String)source(); + out = new TemplateSpec(in, (TemplateMode)null); + sink(out); // $ hasTaintFlow + } + { + // "org.thymeleaf;TemplateSpec;false;getTemplate;;;Argument[-1];ReturnValue;taint;manual" + String out = null; + TemplateSpec in = (TemplateSpec)source(); + out = in.getTemplate(); + sink(out); // $ hasTaintFlow + } + + } + +} \ No newline at end of file diff --git a/java/ql/test/library-tests/frameworks/thymeleaf/options b/java/ql/test/library-tests/frameworks/thymeleaf/options new file mode 100644 index 00000000000..061e53d9ece --- /dev/null +++ b/java/ql/test/library-tests/frameworks/thymeleaf/options @@ -0,0 +1 @@ +//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/thymeleaf-3.0.14 \ No newline at end of file diff --git a/java/ql/test/library-tests/frameworks/thymeleaf/test.expected b/java/ql/test/library-tests/frameworks/thymeleaf/test.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/java/ql/test/library-tests/frameworks/thymeleaf/test.ql b/java/ql/test/library-tests/frameworks/thymeleaf/test.ql new file mode 100644 index 00000000000..5d91e4e8e26 --- /dev/null +++ b/java/ql/test/library-tests/frameworks/thymeleaf/test.ql @@ -0,0 +1,2 @@ +import java +import TestUtilities.InlineFlowTest diff --git a/java/ql/test/query-tests/security/CWE-094/PebbleSSTI.java b/java/ql/test/query-tests/security/CWE-094/PebbleSSTI.java index 05ddc157ae1..c026f98645b 100644 --- a/java/ql/test/query-tests/security/CWE-094/PebbleSSTI.java +++ b/java/ql/test/query-tests/security/CWE-094/PebbleSSTI.java @@ -15,17 +15,15 @@ public class PebbleSSTI { @GetMapping(value = "bad1") public void bad1(HttpServletRequest request) { - String code = request.getParameter("code"); + String templateName = request.getParameter("templateName"); PebbleEngine engine = new PebbleEngine.Builder().build(); - // public PebbleTemplate getTemplate(String templateName) - PebbleTemplate compiledTemplate = engine.getTemplate(code); // $hasTemplateInjection + PebbleTemplate compiledTemplate = engine.getTemplate(templateName); // $hasTemplateInjection } @GetMapping(value = "bad2") public void bad2(HttpServletRequest request) { - String code = request.getParameter("code"); + String templateName = request.getParameter("templateName"); PebbleEngine engine = new PebbleEngine.Builder().build(); - // public PebbleTemplate getLiteralTemplate(String templateName) - PebbleTemplate compiledTemplate = engine.getLiteralTemplate(code); // $hasTemplateInjection + PebbleTemplate compiledTemplate = engine.getLiteralTemplate(templateName); // $hasTemplateInjection } } diff --git a/java/ql/test/query-tests/security/CWE-094/ThymeleafSSTI.java b/java/ql/test/query-tests/security/CWE-094/ThymeleafSSTI.java index b70266130b1..4b390668948 100644 --- a/java/ql/test/query-tests/security/CWE-094/ThymeleafSSTI.java +++ b/java/ql/test/query-tests/security/CWE-094/ThymeleafSSTI.java @@ -9,22 +9,29 @@ import java.io.FileWriter; import java.io.Reader; import java.io.StringReader; import java.io.Writer; +import java.util.Set; 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); // $hasTemplateInjection + templateEngine.process(code, (Set) null, (Context) null); // $hasTemplateInjection + templateEngine.process(code, (Set) null, (Context) null, (Writer) null); // $hasTemplateInjection + templateEngine.process(code, (Context) null); // $hasTemplateInjection + templateEngine.process(code, (Context) null, (Writer) null); // $hasTemplateInjection + templateEngine.processThrottled(code, (Set) null, (Context) null); // $hasTemplateInjection + templateEngine.processThrottled(code, (Context) null); // $hasTemplateInjection + + TemplateSpec spec = new TemplateSpec(code, ""); + templateEngine.process(spec, (Context) null); // $hasTemplateInjection + templateEngine.process(spec, (Context) null, (Writer) null); // $hasTemplateInjection + templateEngine.processThrottled(spec, (Context) null); // $hasTemplateInjection } catch (Exception e) { } }