From c6c4c2c99b91e0d04b2b00acd24a28665c7154c3 Mon Sep 17 00:00:00 2001 From: Artem Smotrakov Date: Thu, 23 Apr 2020 09:09:28 +0200 Subject: [PATCH 01/10] Java: Add a query for MVEL injections - Added experimental/Security/CWE/CWE-094/MvelInjection.ql - Added experimental/Security/CWE/CWE-094/MvelInjectionLib.qll - Added a qhelp file with an example of vulnerable code - Added tests and stubs for mvel2-2.4.7 --- .../Security/CWE/CWE-094/MvelInjection.qhelp | 37 +++++ .../Security/CWE/CWE-094/MvelInjection.ql | 19 +++ .../Security/CWE/CWE-094/MvelInjectionLib.qll | 131 ++++++++++++++++++ .../UnsafeMvelExpressionEvaluation.java | 8 ++ .../CWE/CWE-094/MvelInjection.expected | 15 ++ .../Security/CWE/CWE-094/MvelInjection.java | 41 ++++++ .../Security/CWE/CWE-094/MvelInjection.qlref | 1 + .../experimental/Security/CWE/CWE-094/options | 2 +- .../stubs/mvel2-2.4.7/org/mvel2/MVEL.java | 9 ++ .../mvel2/compiler/ExecutableStatement.java | 7 + .../mvel2/compiler/ExpressionCompiler.java | 6 + .../integration/VariableResolverFactory.java | 5 + .../impl/ImmutableDefaultFactory.java | 5 + 13 files changed, 285 insertions(+), 1 deletion(-) create mode 100644 java/ql/src/experimental/Security/CWE/CWE-094/MvelInjection.qhelp create mode 100644 java/ql/src/experimental/Security/CWE/CWE-094/MvelInjection.ql create mode 100644 java/ql/src/experimental/Security/CWE/CWE-094/MvelInjectionLib.qll create mode 100644 java/ql/src/experimental/Security/CWE/CWE-094/UnsafeMvelExpressionEvaluation.java create mode 100644 java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.expected create mode 100644 java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.java create mode 100644 java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.qlref create mode 100644 java/ql/test/stubs/mvel2-2.4.7/org/mvel2/MVEL.java create mode 100644 java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/ExecutableStatement.java create mode 100644 java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/ExpressionCompiler.java create mode 100644 java/ql/test/stubs/mvel2-2.4.7/org/mvel2/integration/VariableResolverFactory.java create mode 100644 java/ql/test/stubs/mvel2-2.4.7/org/mvel2/integration/impl/ImmutableDefaultFactory.java diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjection.qhelp b/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjection.qhelp new file mode 100644 index 000000000000..1055847020f6 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjection.qhelp @@ -0,0 +1,37 @@ + + + + +

+MVEL is an expression language based on Java-syntax. +The language offers many features +including invocation of methods available in the JVM. +If a MVEL expression is built using attacker-controlled data, +and then evaluated, then it may allow the attacker to run arbitrary code. +

+
+ + +

+Including user input in a MVEL expression should be avoided. +

+
+ + +

+The following example uses untrusted data to build a MVEL expression +and then runs it in the default powerfull context. +

+ + + +
  • + MVEL Documentation: + Language Guide for 2.0. +
  • +
  • + OWASP: + Expression Language Injection. +
  • +
    +
    \ No newline at end of file diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjection.ql b/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjection.ql new file mode 100644 index 000000000000..d32c33c343c3 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjection.ql @@ -0,0 +1,19 @@ +/** + * @name Expression language injection (MVEL) + * @description Evaluation of a user-controlled MVEL expression + * may lead to remote code execution. + * @kind path-problem + * @problem.severity error + * @precision high + * @id java/mvel-expression-injection + * @tags security + * external/cwe/cwe-094 + */ + +import java +import MvelInjectionLib +import DataFlow::PathGraph + +from DataFlow::PathNode source, DataFlow::PathNode sink, MvelInjectionConfig conf +where conf.hasFlowPath(source, sink) +select sink.getNode(), source, sink, "MVEL injection from $@.", source.getNode(), "this user input" diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjectionLib.qll b/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjectionLib.qll new file mode 100644 index 000000000000..be457d9534ec --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjectionLib.qll @@ -0,0 +1,131 @@ +import java +import semmle.code.java.dataflow.FlowSources +import semmle.code.java.dataflow.TaintTracking +import DataFlow::PathGraph + +/** + * A taint-tracking configuration for unsafe user input + * that is used to construct and evaluate a MVEL expression. + */ +class MvelInjectionConfig extends TaintTracking::Configuration { + MvelInjectionConfig() { this = "MvelInjectionConfig" } + + override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource } + + override predicate isSink(DataFlow::Node sink) { sink instanceof MvelEvaluationSink } + + override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { + expressionCompilationStep(node1, node2) or + createExpressionCompilerStep(node1, node2) or + expressionCompilerCompileStep(node1, node2) + } +} + +/** + * A sink for EL injection vulnerabilities via MVEL, + * i.e. methods that run evaluation of a MVEL expression. + */ +class MvelEvaluationSink extends DataFlow::ExprNode { + MvelEvaluationSink() { + exists(StaticMethodAccess ma, Method m | m = ma.getMethod() | + m instanceof MvelEvalMethod and + ma.getAnArgument() = asExpr() + ) + or + exists(MethodAccess ma, Method m | m = ma.getMethod() | + m instanceof ExecutableStatementEvaluationMethod and + (ma = asExpr() or ma.getQualifier() = asExpr()) + ) + } +} + +/** + * Holds if `node1` to `node2` is a dataflow step that compiles a MVEL expression + * by callilng `MVEL.compileExpression(tainted)`. + */ +predicate expressionCompilationStep(DataFlow::Node node1, DataFlow::Node node2) { + exists(StaticMethodAccess ma, Method m | ma.getMethod() = m | + m.getDeclaringType() instanceof MVEL and + m.hasName("compileExpression") and + ma.getAnArgument() = node1.asExpr() and + (node2.asExpr() = ma.getQualifier() or node2.asExpr() = ma) + ) +} + +/** + * Holds if `node1` to `node2` is a dataflow step creates `ExpressionCompiler`, + * i.e. `new ExpressionCompiler(tainted)`. + */ +predicate createExpressionCompilerStep(DataFlow::Node node1, DataFlow::Node node2) { + exists(ConstructorCall cc | + cc.getConstructedType() instanceof ExpressionCompiler and + (cc = node2.asExpr() or cc.getQualifier() = node2.asExpr()) and + cc.getArgument(0) = node1.asExpr() + ) +} + +/** + * Holds if `node1` to `node2` is a dataflow step that compiles a MVEL expression + * by calling `ExpressionCompiler.compile()`. + */ +predicate expressionCompilerCompileStep(DataFlow::Node node1, DataFlow::Node node2) { + exists(MethodAccess ma, Method m | ma.getMethod() = m | + m.getDeclaringType() instanceof ExpressionCompiler and + m.hasName("compile") and + ma = node2.asExpr() and + ma.getQualifier() = node1.asExpr() + ) +} + +/** + * Methods in the MVEL class that evaluate a MVEL expression. + */ +class MvelEvalMethod extends Method { + MvelEvalMethod() { + getDeclaringType() instanceof MVEL and + ( + hasName("eval") or + hasName("executeExpression") or + hasName("evalToBoolean") or + hasName("evalToString") or + hasName("executeAllExpression") or + hasName("executeSetExpression") + ) + } +} + +/** + * Methods in `MVEL` class that compile a MVEL expression. + */ +class MvelCompileExpressionMethod extends Method { + MvelCompileExpressionMethod() { + getDeclaringType() instanceof MVEL and + ( + hasName("compileExpression") or + hasName("compileGetExpression") or + hasName("compileSetExpression") + ) + } +} + +/** + * Methods in `ExecutableStatement` that trigger evaluating a MVEL expression. + */ +class ExecutableStatementEvaluationMethod extends Method { + ExecutableStatementEvaluationMethod() { + getDeclaringType() instanceof ExecutableStatement and + hasName("getValue") + } +} + +class MVEL extends RefType { + MVEL() { hasQualifiedName("org.mvel2", "MVEL") } +} + +class ExpressionCompiler extends RefType { + ExpressionCompiler() { hasQualifiedName("org.mvel2.compiler", "ExpressionCompiler") } +} + +class ExecutableStatement extends RefType { + ExecutableStatement() { hasQualifiedName("org.mvel2.compiler", "ExecutableStatement") } +} diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/UnsafeMvelExpressionEvaluation.java b/java/ql/src/experimental/Security/CWE/CWE-094/UnsafeMvelExpressionEvaluation.java new file mode 100644 index 000000000000..4942bee79f6d --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-094/UnsafeMvelExpressionEvaluation.java @@ -0,0 +1,8 @@ +public void evaluate(Socket socket) throws IOException { + try (BufferedReader reader = new BufferedReader( + new InputStreamReader(socket.getInputStream()))) { + + String expression = reader.readLine(); + MVEL.eval(expression); + } +} \ No newline at end of file diff --git a/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.expected b/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.expected new file mode 100644 index 000000000000..837cee1e3a1e --- /dev/null +++ b/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.expected @@ -0,0 +1,15 @@ +edges +| MvelInjection.java:13:27:13:49 | getInputStream(...) : InputStream | MvelInjection.java:17:17:17:21 | input | +| MvelInjection.java:22:27:22:49 | getInputStream(...) : InputStream | MvelInjection.java:27:30:27:39 | expression | +| MvelInjection.java:32:27:32:49 | getInputStream(...) : InputStream | MvelInjection.java:38:7:38:15 | statement | +nodes +| MvelInjection.java:13:27:13:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:17:17:17:21 | input | semmle.label | input | +| MvelInjection.java:22:27:22:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:27:30:27:39 | expression | semmle.label | expression | +| MvelInjection.java:32:27:32:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:38:7:38:15 | statement | semmle.label | statement | +#select +| MvelInjection.java:17:17:17:21 | input | MvelInjection.java:13:27:13:49 | getInputStream(...) : InputStream | MvelInjection.java:17:17:17:21 | input | MVEL injection from $@. | MvelInjection.java:13:27:13:49 | getInputStream(...) | this user input | +| MvelInjection.java:27:30:27:39 | expression | MvelInjection.java:22:27:22:49 | getInputStream(...) : InputStream | MvelInjection.java:27:30:27:39 | expression | MVEL injection from $@. | MvelInjection.java:22:27:22:49 | getInputStream(...) | this user input | +| MvelInjection.java:38:7:38:15 | statement | MvelInjection.java:32:27:32:49 | getInputStream(...) : InputStream | MvelInjection.java:38:7:38:15 | statement | MVEL injection from $@. | MvelInjection.java:32:27:32:49 | getInputStream(...) | this user input | \ No newline at end of file diff --git a/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.java b/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.java new file mode 100644 index 000000000000..6c5ceb957b66 --- /dev/null +++ b/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.java @@ -0,0 +1,41 @@ +import java.io.IOException; +import java.io.InputStream; +import java.io.Serializable; +import java.net.Socket; +import org.mvel2.MVEL; +import org.mvel2.compiler.ExecutableStatement; +import org.mvel2.compiler.ExpressionCompiler; +import org.mvel2.integration.impl.ImmutableDefaultFactory; + +public class MvelInjection { + + public static void testWithMvelEval(Socket socket) throws IOException { + try (InputStream in = socket.getInputStream()) { + byte[] bytes = new byte[1024]; + int n = in.read(bytes); + String input = new String(bytes, 0, n); + MVEL.eval(input); + } + } + + public static void testWithMvelCompileAndExecute(Socket socket) throws IOException { + try (InputStream in = socket.getInputStream()) { + byte[] bytes = new byte[1024]; + int n = in.read(bytes); + String input = new String(bytes, 0, n); + Serializable expression = MVEL.compileExpression(input); + MVEL.executeExpression(expression); + } + } + + public static void testWithExpressionCompiler(Socket socket) throws IOException { + try (InputStream in = socket.getInputStream()) { + byte[] bytes = new byte[1024]; + int n = in.read(bytes); + String input = new String(bytes, 0, n); + ExpressionCompiler compiler = new ExpressionCompiler(input); + ExecutableStatement statement = compiler.compile(); + statement.getValue(new Object(), new ImmutableDefaultFactory()); + } + } +} diff --git a/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.qlref b/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.qlref new file mode 100644 index 000000000000..13d7cbd22950 --- /dev/null +++ b/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.qlref @@ -0,0 +1 @@ +experimental/Security/CWE/CWE-094/MvelInjection.ql \ No newline at end of file diff --git a/java/ql/test/experimental/Security/CWE/CWE-094/options b/java/ql/test/experimental/Security/CWE/CWE-094/options index 31b8e3f69351..2048ced65b40 100644 --- a/java/ql/test/experimental/Security/CWE/CWE-094/options +++ b/java/ql/test/experimental/Security/CWE/CWE-094/options @@ -1 +1 @@ -//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/springframework-5.2.3 \ No newline at end of file +//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/springframework-5.2.3:${testdir}/../../../../stubs/mvel2-2.4.7 diff --git a/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/MVEL.java b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/MVEL.java new file mode 100644 index 000000000000..3d0c39e724ff --- /dev/null +++ b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/MVEL.java @@ -0,0 +1,9 @@ +package org.mvel2; + +import java.io.Serializable; + +public class MVEL { + public static Object eval(String expression) { return null; } + public static Serializable compileExpression(String expression) { return null; } + public static Object executeExpression(Object compiledExpression) { return null; } +} \ No newline at end of file diff --git a/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/ExecutableStatement.java b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/ExecutableStatement.java new file mode 100644 index 000000000000..cdd510035fe5 --- /dev/null +++ b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/ExecutableStatement.java @@ -0,0 +1,7 @@ +package org.mvel2.compiler; + +import org.mvel2.integration.VariableResolverFactory; + +public interface ExecutableStatement { + public Object getValue(Object staticContext, VariableResolverFactory factory); +} \ No newline at end of file diff --git a/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/ExpressionCompiler.java b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/ExpressionCompiler.java new file mode 100644 index 000000000000..204bd5e283fd --- /dev/null +++ b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/ExpressionCompiler.java @@ -0,0 +1,6 @@ +package org.mvel2.compiler; + +public class ExpressionCompiler { + public ExpressionCompiler(String expression) {} + public ExecutableStatement compile() { return null; } +} \ No newline at end of file diff --git a/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/integration/VariableResolverFactory.java b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/integration/VariableResolverFactory.java new file mode 100644 index 000000000000..1fb643374b68 --- /dev/null +++ b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/integration/VariableResolverFactory.java @@ -0,0 +1,5 @@ +package org.mvel2.integration; + +import java.io.Serializable; + +public interface VariableResolverFactory extends Serializable {} \ No newline at end of file diff --git a/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/integration/impl/ImmutableDefaultFactory.java b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/integration/impl/ImmutableDefaultFactory.java new file mode 100644 index 000000000000..97463a9e9d3d --- /dev/null +++ b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/integration/impl/ImmutableDefaultFactory.java @@ -0,0 +1,5 @@ +package org.mvel2.integration.impl; + +import org.mvel2.integration.VariableResolverFactory; + +public class ImmutableDefaultFactory implements VariableResolverFactory {} \ No newline at end of file From 32ff5ad4967efdfffc48be28181fbe75355daeaa Mon Sep 17 00:00:00 2001 From: Artem Smotrakov Date: Fri, 24 Apr 2020 22:06:20 +0200 Subject: [PATCH 02/10] Java: Added CompiledExpression sink for MVEL injections --- .../Security/CWE/CWE-094/MvelInjectionLib.qll | 19 +++++++++++++ .../CWE/CWE-094/MvelInjection.expected | 28 +++++++++++-------- .../Security/CWE/CWE-094/MvelInjection.java | 12 ++++++++ .../mvel2/compiler/CompiledExpression.java | 8 ++++++ .../mvel2/compiler/ExecutableStatement.java | 2 +- .../mvel2/compiler/ExpressionCompiler.java | 2 +- 6 files changed, 57 insertions(+), 14 deletions(-) create mode 100644 java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/CompiledExpression.java diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjectionLib.qll b/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjectionLib.qll index be457d9534ec..04833b8537e8 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjectionLib.qll +++ b/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjectionLib.qll @@ -36,6 +36,11 @@ class MvelEvaluationSink extends DataFlow::ExprNode { m instanceof ExecutableStatementEvaluationMethod and (ma = asExpr() or ma.getQualifier() = asExpr()) ) + or + exists(MethodAccess ma, Method m | m = ma.getMethod() | + m instanceof CompiledExpressionEvaluationMethod and + (ma = asExpr() or ma.getQualifier() = asExpr()) + ) } } @@ -118,6 +123,16 @@ class ExecutableStatementEvaluationMethod extends Method { } } +/** + * Methods in `CompiledExpression` that trigger evaluating a MVEL expression. + */ +class CompiledExpressionEvaluationMethod extends Method { + CompiledExpressionEvaluationMethod() { + getDeclaringType() instanceof CompiledExpression and + hasName("getDirectValue") + } +} + class MVEL extends RefType { MVEL() { hasQualifiedName("org.mvel2", "MVEL") } } @@ -129,3 +144,7 @@ class ExpressionCompiler extends RefType { class ExecutableStatement extends RefType { ExecutableStatement() { hasQualifiedName("org.mvel2.compiler", "ExecutableStatement") } } + +class CompiledExpression extends RefType { + CompiledExpression() { hasQualifiedName("org.mvel2.compiler", "CompiledExpression") } +} diff --git a/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.expected b/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.expected index 837cee1e3a1e..399ab3fe6acf 100644 --- a/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.expected +++ b/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.expected @@ -1,15 +1,19 @@ edges -| MvelInjection.java:13:27:13:49 | getInputStream(...) : InputStream | MvelInjection.java:17:17:17:21 | input | -| MvelInjection.java:22:27:22:49 | getInputStream(...) : InputStream | MvelInjection.java:27:30:27:39 | expression | -| MvelInjection.java:32:27:32:49 | getInputStream(...) : InputStream | MvelInjection.java:38:7:38:15 | statement | +| MvelInjection.java:14:27:14:49 | getInputStream(...) : InputStream | MvelInjection.java:18:17:18:21 | input | +| MvelInjection.java:23:27:23:49 | getInputStream(...) : InputStream | MvelInjection.java:28:30:28:39 | expression | +| MvelInjection.java:33:27:33:49 | getInputStream(...) : InputStream | MvelInjection.java:39:7:39:15 | statement | +| MvelInjection.java:44:27:44:49 | getInputStream(...) : InputStream | MvelInjection.java:50:7:50:16 | expression | nodes -| MvelInjection.java:13:27:13:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| MvelInjection.java:17:17:17:21 | input | semmle.label | input | -| MvelInjection.java:22:27:22:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| MvelInjection.java:27:30:27:39 | expression | semmle.label | expression | -| MvelInjection.java:32:27:32:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| MvelInjection.java:38:7:38:15 | statement | semmle.label | statement | +| MvelInjection.java:14:27:14:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:18:17:18:21 | input | semmle.label | input | +| MvelInjection.java:23:27:23:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:28:30:28:39 | expression | semmle.label | expression | +| MvelInjection.java:33:27:33:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:39:7:39:15 | statement | semmle.label | statement | +| MvelInjection.java:44:27:44:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:50:7:50:16 | expression | semmle.label | expression | #select -| MvelInjection.java:17:17:17:21 | input | MvelInjection.java:13:27:13:49 | getInputStream(...) : InputStream | MvelInjection.java:17:17:17:21 | input | MVEL injection from $@. | MvelInjection.java:13:27:13:49 | getInputStream(...) | this user input | -| MvelInjection.java:27:30:27:39 | expression | MvelInjection.java:22:27:22:49 | getInputStream(...) : InputStream | MvelInjection.java:27:30:27:39 | expression | MVEL injection from $@. | MvelInjection.java:22:27:22:49 | getInputStream(...) | this user input | -| MvelInjection.java:38:7:38:15 | statement | MvelInjection.java:32:27:32:49 | getInputStream(...) : InputStream | MvelInjection.java:38:7:38:15 | statement | MVEL injection from $@. | MvelInjection.java:32:27:32:49 | getInputStream(...) | this user input | \ No newline at end of file +| MvelInjection.java:18:17:18:21 | input | MvelInjection.java:14:27:14:49 | getInputStream(...) : InputStream | MvelInjection.java:18:17:18:21 | input | MVEL injection from $@. | MvelInjection.java:14:27:14:49 | getInputStream(...) | this user input | +| MvelInjection.java:28:30:28:39 | expression | MvelInjection.java:23:27:23:49 | getInputStream(...) : InputStream | MvelInjection.java:28:30:28:39 | expression | MVEL injection from $@. | MvelInjection.java:23:27:23:49 | getInputStream(...) | this user input | +| MvelInjection.java:39:7:39:15 | statement | MvelInjection.java:33:27:33:49 | getInputStream(...) : InputStream | MvelInjection.java:39:7:39:15 | statement | MVEL injection from $@. | MvelInjection.java:33:27:33:49 | getInputStream(...) | this user input | +| MvelInjection.java:50:7:50:16 | expression | MvelInjection.java:44:27:44:49 | getInputStream(...) : InputStream | MvelInjection.java:50:7:50:16 | expression | MVEL injection from $@. | MvelInjection.java:44:27:44:49 | getInputStream(...) | this user input | diff --git a/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.java b/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.java index 6c5ceb957b66..c5199b272c46 100644 --- a/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.java +++ b/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.java @@ -3,6 +3,7 @@ import java.io.Serializable; import java.net.Socket; import org.mvel2.MVEL; +import org.mvel2.compiler.CompiledExpression; import org.mvel2.compiler.ExecutableStatement; import org.mvel2.compiler.ExpressionCompiler; import org.mvel2.integration.impl.ImmutableDefaultFactory; @@ -38,4 +39,15 @@ public static void testWithExpressionCompiler(Socket socket) throws IOException statement.getValue(new Object(), new ImmutableDefaultFactory()); } } + + public static void testWithCompiledExpressionGetDirectValue(Socket socket) throws IOException { + try (InputStream in = socket.getInputStream()) { + byte[] bytes = new byte[1024]; + int n = in.read(bytes); + String input = new String(bytes, 0, n); + ExpressionCompiler compiler = new ExpressionCompiler(input); + CompiledExpression expression = compiler.compile(); + expression.getDirectValue(new Object(), new ImmutableDefaultFactory()); + } + } } diff --git a/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/CompiledExpression.java b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/CompiledExpression.java new file mode 100644 index 000000000000..234900b0fa32 --- /dev/null +++ b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/CompiledExpression.java @@ -0,0 +1,8 @@ +package org.mvel2.compiler; + +import org.mvel2.integration.VariableResolverFactory; + +public class CompiledExpression implements ExecutableStatement { + public Object getDirectValue(Object staticContext, VariableResolverFactory factory) { return null; } + public Object getValue(Object staticContext, VariableResolverFactory factory) { return null; } +} \ No newline at end of file diff --git a/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/ExecutableStatement.java b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/ExecutableStatement.java index cdd510035fe5..1e15b8e6678e 100644 --- a/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/ExecutableStatement.java +++ b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/ExecutableStatement.java @@ -3,5 +3,5 @@ import org.mvel2.integration.VariableResolverFactory; public interface ExecutableStatement { - public Object getValue(Object staticContext, VariableResolverFactory factory); + public Object getValue(Object staticContext, VariableResolverFactory factory); } \ No newline at end of file diff --git a/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/ExpressionCompiler.java b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/ExpressionCompiler.java index 204bd5e283fd..3f22268b891b 100644 --- a/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/ExpressionCompiler.java +++ b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/ExpressionCompiler.java @@ -2,5 +2,5 @@ public class ExpressionCompiler { public ExpressionCompiler(String expression) {} - public ExecutableStatement compile() { return null; } + public CompiledExpression compile() { return null; } } \ No newline at end of file From 12e0234d4094205ee33c5dcafad38d6434d83728 Mon Sep 17 00:00:00 2001 From: Artem Smotrakov Date: Fri, 24 Apr 2020 23:17:52 +0200 Subject: [PATCH 03/10] Java: Added CompiledAccExpression sink for MVEL injections --- .../Security/CWE/CWE-094/MvelInjectionLib.qll | 46 +++++++++++++++---- .../CWE/CWE-094/MvelInjection.expected | 36 ++++++++------- .../Security/CWE/CWE-094/MvelInjection.java | 12 +++++ .../mvel2-2.4.7/org/mvel2/ParserContext.java | 3 ++ .../mvel2/compiler/CompiledAccExpression.java | 10 ++++ 5 files changed, 83 insertions(+), 24 deletions(-) create mode 100644 java/ql/test/stubs/mvel2-2.4.7/org/mvel2/ParserContext.java create mode 100644 java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/CompiledAccExpression.java diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjectionLib.qll b/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjectionLib.qll index 04833b8537e8..1790a2d54b22 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjectionLib.qll +++ b/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjectionLib.qll @@ -17,7 +17,8 @@ class MvelInjectionConfig extends TaintTracking::Configuration { override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { expressionCompilationStep(node1, node2) or createExpressionCompilerStep(node1, node2) or - expressionCompilerCompileStep(node1, node2) + expressionCompilerCompileStep(node1, node2) or + createCompiledAccExpressionStep(node1, node2) } } @@ -33,12 +34,11 @@ class MvelEvaluationSink extends DataFlow::ExprNode { ) or exists(MethodAccess ma, Method m | m = ma.getMethod() | - m instanceof ExecutableStatementEvaluationMethod and - (ma = asExpr() or ma.getQualifier() = asExpr()) - ) - or - exists(MethodAccess ma, Method m | m = ma.getMethod() | - m instanceof CompiledExpressionEvaluationMethod and + ( + m instanceof ExecutableStatementEvaluationMethod or + m instanceof CompiledExpressionEvaluationMethod or + m instanceof CompiledAccExpressionEvaluationMethod + ) and (ma = asExpr() or ma.getQualifier() = asExpr()) ) } @@ -69,6 +69,22 @@ predicate createExpressionCompilerStep(DataFlow::Node node1, DataFlow::Node node ) } +/** + * Holds if `node1` to `node2` is a dataflow step creates `CompiledAccExpression`, + * i.e. `new CompiledAccExpression(tainted, ...)`. + */ +predicate createCompiledAccExpressionStep(DataFlow::Node node1, DataFlow::Node node2) { + exists(ConstructorCall cc | + cc.getConstructedType() instanceof CompiledAccExpression and + (cc = node2.asExpr() or cc.getQualifier() = node2.asExpr()) and + cc.getArgument(0) = node1.asExpr() + ) +} + +predicate test() { + exists(ConstructorCall cc | cc.getConstructedType() instanceof CompiledAccExpression) +} + /** * Holds if `node1` to `node2` is a dataflow step that compiles a MVEL expression * by calling `ExpressionCompiler.compile()`. @@ -133,6 +149,16 @@ class CompiledExpressionEvaluationMethod extends Method { } } +/** + * Methods in `CompiledAccExpression` that trigger evaluating a MVEL expression. + */ +class CompiledAccExpressionEvaluationMethod extends Method { + CompiledAccExpressionEvaluationMethod() { + getDeclaringType() instanceof CompiledAccExpression and + hasName("getValue") + } +} + class MVEL extends RefType { MVEL() { hasQualifiedName("org.mvel2", "MVEL") } } @@ -146,5 +172,9 @@ class ExecutableStatement extends RefType { } class CompiledExpression extends RefType { - CompiledExpression() { hasQualifiedName("org.mvel2.compiler", "CompiledExpression") } + CompiledExpression() { hasQualifiedName("org.mvel2.compiler", "CompiledExpression") } +} + +class CompiledAccExpression extends RefType { + CompiledAccExpression() { hasQualifiedName("org.mvel2.compiler", "CompiledAccExpression") } } diff --git a/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.expected b/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.expected index 399ab3fe6acf..9ce66a171221 100644 --- a/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.expected +++ b/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.expected @@ -1,19 +1,23 @@ edges -| MvelInjection.java:14:27:14:49 | getInputStream(...) : InputStream | MvelInjection.java:18:17:18:21 | input | -| MvelInjection.java:23:27:23:49 | getInputStream(...) : InputStream | MvelInjection.java:28:30:28:39 | expression | -| MvelInjection.java:33:27:33:49 | getInputStream(...) : InputStream | MvelInjection.java:39:7:39:15 | statement | -| MvelInjection.java:44:27:44:49 | getInputStream(...) : InputStream | MvelInjection.java:50:7:50:16 | expression | +| MvelInjection.java:16:27:16:49 | getInputStream(...) : InputStream | MvelInjection.java:20:17:20:21 | input | +| MvelInjection.java:25:27:25:49 | getInputStream(...) : InputStream | MvelInjection.java:30:30:30:39 | expression | +| MvelInjection.java:35:27:35:49 | getInputStream(...) : InputStream | MvelInjection.java:41:7:41:15 | statement | +| MvelInjection.java:46:27:46:49 | getInputStream(...) : InputStream | MvelInjection.java:52:7:52:16 | expression | +| MvelInjection.java:57:27:57:49 | getInputStream(...) : InputStream | MvelInjection.java:62:7:62:16 | expression | nodes -| MvelInjection.java:14:27:14:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| MvelInjection.java:18:17:18:21 | input | semmle.label | input | -| MvelInjection.java:23:27:23:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| MvelInjection.java:28:30:28:39 | expression | semmle.label | expression | -| MvelInjection.java:33:27:33:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| MvelInjection.java:39:7:39:15 | statement | semmle.label | statement | -| MvelInjection.java:44:27:44:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| MvelInjection.java:50:7:50:16 | expression | semmle.label | expression | +| MvelInjection.java:16:27:16:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:20:17:20:21 | input | semmle.label | input | +| MvelInjection.java:25:27:25:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:30:30:30:39 | expression | semmle.label | expression | +| MvelInjection.java:35:27:35:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:41:7:41:15 | statement | semmle.label | statement | +| MvelInjection.java:46:27:46:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:52:7:52:16 | expression | semmle.label | expression | +| MvelInjection.java:57:27:57:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:62:7:62:16 | expression | semmle.label | expression | #select -| MvelInjection.java:18:17:18:21 | input | MvelInjection.java:14:27:14:49 | getInputStream(...) : InputStream | MvelInjection.java:18:17:18:21 | input | MVEL injection from $@. | MvelInjection.java:14:27:14:49 | getInputStream(...) | this user input | -| MvelInjection.java:28:30:28:39 | expression | MvelInjection.java:23:27:23:49 | getInputStream(...) : InputStream | MvelInjection.java:28:30:28:39 | expression | MVEL injection from $@. | MvelInjection.java:23:27:23:49 | getInputStream(...) | this user input | -| MvelInjection.java:39:7:39:15 | statement | MvelInjection.java:33:27:33:49 | getInputStream(...) : InputStream | MvelInjection.java:39:7:39:15 | statement | MVEL injection from $@. | MvelInjection.java:33:27:33:49 | getInputStream(...) | this user input | -| MvelInjection.java:50:7:50:16 | expression | MvelInjection.java:44:27:44:49 | getInputStream(...) : InputStream | MvelInjection.java:50:7:50:16 | expression | MVEL injection from $@. | MvelInjection.java:44:27:44:49 | getInputStream(...) | this user input | +| MvelInjection.java:20:17:20:21 | input | MvelInjection.java:16:27:16:49 | getInputStream(...) : InputStream | MvelInjection.java:20:17:20:21 | input | MVEL injection from $@. | MvelInjection.java:16:27:16:49 | getInputStream(...) | this user input | +| MvelInjection.java:30:30:30:39 | expression | MvelInjection.java:25:27:25:49 | getInputStream(...) : InputStream | MvelInjection.java:30:30:30:39 | expression | MVEL injection from $@. | MvelInjection.java:25:27:25:49 | getInputStream(...) | this user input | +| MvelInjection.java:41:7:41:15 | statement | MvelInjection.java:35:27:35:49 | getInputStream(...) : InputStream | MvelInjection.java:41:7:41:15 | statement | MVEL injection from $@. | MvelInjection.java:35:27:35:49 | getInputStream(...) | this user input | +| MvelInjection.java:52:7:52:16 | expression | MvelInjection.java:46:27:46:49 | getInputStream(...) : InputStream | MvelInjection.java:52:7:52:16 | expression | MVEL injection from $@. | MvelInjection.java:46:27:46:49 | getInputStream(...) | this user input | +| MvelInjection.java:62:7:62:16 | expression | MvelInjection.java:57:27:57:49 | getInputStream(...) : InputStream | MvelInjection.java:62:7:62:16 | expression | MVEL injection from $@. | MvelInjection.java:57:27:57:49 | getInputStream(...) | this user input | diff --git a/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.java b/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.java index c5199b272c46..23218e3cfcb2 100644 --- a/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.java +++ b/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.java @@ -3,6 +3,8 @@ import java.io.Serializable; import java.net.Socket; import org.mvel2.MVEL; +import org.mvel2.ParserContext; +import org.mvel2.compiler.CompiledAccExpression; import org.mvel2.compiler.CompiledExpression; import org.mvel2.compiler.ExecutableStatement; import org.mvel2.compiler.ExpressionCompiler; @@ -50,4 +52,14 @@ public static void testWithCompiledExpressionGetDirectValue(Socket socket) throw expression.getDirectValue(new Object(), new ImmutableDefaultFactory()); } } + + public static void testCompiledAccExpressionGetValue(Socket socket) throws IOException { + try (InputStream in = socket.getInputStream()) { + byte[] bytes = new byte[1024]; + int n = in.read(bytes); + String input = new String(bytes, 0, n); + CompiledAccExpression expression = new CompiledAccExpression(input.toCharArray(), Object.class, new ParserContext()); + expression.getValue(new Object(), new ImmutableDefaultFactory()); + } + } } diff --git a/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/ParserContext.java b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/ParserContext.java new file mode 100644 index 000000000000..ce160eec2288 --- /dev/null +++ b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/ParserContext.java @@ -0,0 +1,3 @@ +package org.mvel2; + +public class ParserContext {} \ No newline at end of file diff --git a/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/CompiledAccExpression.java b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/CompiledAccExpression.java new file mode 100644 index 000000000000..88630888e67e --- /dev/null +++ b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/CompiledAccExpression.java @@ -0,0 +1,10 @@ +package org.mvel2.compiler; + +import org.mvel2.ParserContext; +import org.mvel2.integration.VariableResolverFactory; + +public class CompiledAccExpression implements ExecutableStatement { + public CompiledAccExpression(char[] expression, Class ingressType, ParserContext context) {} + public Object getValue(Object staticContext, VariableResolverFactory factory) { return null; } + public Object getValue(Object ctx, Object elCtx, VariableResolverFactory variableFactory) { return null; } +} From 6a6c805048fd09b0030eaddfd06a4dab6d2c63dc Mon Sep 17 00:00:00 2001 From: Artem Smotrakov Date: Fri, 24 Apr 2020 23:49:19 +0200 Subject: [PATCH 04/10] Java: Added Accessor sink for MVEL injections --- .../Security/CWE/CWE-094/MvelInjectionLib.qll | 17 ++++++++++++++++- .../CWE/CWE-094/MvelInjection.expected | 19 +++++++++++-------- .../Security/CWE/CWE-094/MvelInjection.java | 1 + .../org/mvel2/compiler/Accessor.java | 7 +++++++ .../mvel2/compiler/CompiledExpression.java | 1 + .../mvel2/compiler/ExecutableStatement.java | 2 +- 6 files changed, 37 insertions(+), 10 deletions(-) create mode 100644 java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/Accessor.java diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjectionLib.qll b/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjectionLib.qll index 1790a2d54b22..0e1d6d38fdc0 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjectionLib.qll +++ b/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjectionLib.qll @@ -37,7 +37,8 @@ class MvelEvaluationSink extends DataFlow::ExprNode { ( m instanceof ExecutableStatementEvaluationMethod or m instanceof CompiledExpressionEvaluationMethod or - m instanceof CompiledAccExpressionEvaluationMethod + m instanceof CompiledAccExpressionEvaluationMethod or + m instanceof AccessorEvaluationMethod ) and (ma = asExpr() or ma.getQualifier() = asExpr()) ) @@ -159,6 +160,16 @@ class CompiledAccExpressionEvaluationMethod extends Method { } } +/** + * Methods in `Accessor` that trigger evaluating a MVEL expression. + */ +class AccessorEvaluationMethod extends Method { + AccessorEvaluationMethod() { + getDeclaringType() instanceof Accessor and + hasName("getValue") + } +} + class MVEL extends RefType { MVEL() { hasQualifiedName("org.mvel2", "MVEL") } } @@ -178,3 +189,7 @@ class CompiledExpression extends RefType { class CompiledAccExpression extends RefType { CompiledAccExpression() { hasQualifiedName("org.mvel2.compiler", "CompiledAccExpression") } } + +class Accessor extends RefType { + Accessor() { hasQualifiedName("org.mvel2.compiler", "Accessor") } +} diff --git a/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.expected b/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.expected index 9ce66a171221..2cf20b0d79f2 100644 --- a/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.expected +++ b/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.expected @@ -2,8 +2,9 @@ edges | MvelInjection.java:16:27:16:49 | getInputStream(...) : InputStream | MvelInjection.java:20:17:20:21 | input | | MvelInjection.java:25:27:25:49 | getInputStream(...) : InputStream | MvelInjection.java:30:30:30:39 | expression | | MvelInjection.java:35:27:35:49 | getInputStream(...) : InputStream | MvelInjection.java:41:7:41:15 | statement | -| MvelInjection.java:46:27:46:49 | getInputStream(...) : InputStream | MvelInjection.java:52:7:52:16 | expression | -| MvelInjection.java:57:27:57:49 | getInputStream(...) : InputStream | MvelInjection.java:62:7:62:16 | expression | +| MvelInjection.java:35:27:35:49 | getInputStream(...) : InputStream | MvelInjection.java:42:7:42:15 | statement | +| MvelInjection.java:47:27:47:49 | getInputStream(...) : InputStream | MvelInjection.java:53:7:53:16 | expression | +| MvelInjection.java:58:27:58:49 | getInputStream(...) : InputStream | MvelInjection.java:63:7:63:16 | expression | nodes | MvelInjection.java:16:27:16:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | | MvelInjection.java:20:17:20:21 | input | semmle.label | input | @@ -11,13 +12,15 @@ nodes | MvelInjection.java:30:30:30:39 | expression | semmle.label | expression | | MvelInjection.java:35:27:35:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | | MvelInjection.java:41:7:41:15 | statement | semmle.label | statement | -| MvelInjection.java:46:27:46:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| MvelInjection.java:52:7:52:16 | expression | semmle.label | expression | -| MvelInjection.java:57:27:57:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| MvelInjection.java:62:7:62:16 | expression | semmle.label | expression | +| MvelInjection.java:42:7:42:15 | statement | semmle.label | statement | +| MvelInjection.java:47:27:47:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:53:7:53:16 | expression | semmle.label | expression | +| MvelInjection.java:58:27:58:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:63:7:63:16 | expression | semmle.label | expression | #select | MvelInjection.java:20:17:20:21 | input | MvelInjection.java:16:27:16:49 | getInputStream(...) : InputStream | MvelInjection.java:20:17:20:21 | input | MVEL injection from $@. | MvelInjection.java:16:27:16:49 | getInputStream(...) | this user input | | MvelInjection.java:30:30:30:39 | expression | MvelInjection.java:25:27:25:49 | getInputStream(...) : InputStream | MvelInjection.java:30:30:30:39 | expression | MVEL injection from $@. | MvelInjection.java:25:27:25:49 | getInputStream(...) | this user input | | MvelInjection.java:41:7:41:15 | statement | MvelInjection.java:35:27:35:49 | getInputStream(...) : InputStream | MvelInjection.java:41:7:41:15 | statement | MVEL injection from $@. | MvelInjection.java:35:27:35:49 | getInputStream(...) | this user input | -| MvelInjection.java:52:7:52:16 | expression | MvelInjection.java:46:27:46:49 | getInputStream(...) : InputStream | MvelInjection.java:52:7:52:16 | expression | MVEL injection from $@. | MvelInjection.java:46:27:46:49 | getInputStream(...) | this user input | -| MvelInjection.java:62:7:62:16 | expression | MvelInjection.java:57:27:57:49 | getInputStream(...) : InputStream | MvelInjection.java:62:7:62:16 | expression | MVEL injection from $@. | MvelInjection.java:57:27:57:49 | getInputStream(...) | this user input | +| MvelInjection.java:42:7:42:15 | statement | MvelInjection.java:35:27:35:49 | getInputStream(...) : InputStream | MvelInjection.java:42:7:42:15 | statement | MVEL injection from $@. | MvelInjection.java:35:27:35:49 | getInputStream(...) | this user input | +| MvelInjection.java:53:7:53:16 | expression | MvelInjection.java:47:27:47:49 | getInputStream(...) : InputStream | MvelInjection.java:53:7:53:16 | expression | MVEL injection from $@. | MvelInjection.java:47:27:47:49 | getInputStream(...) | this user input | +| MvelInjection.java:63:7:63:16 | expression | MvelInjection.java:58:27:58:49 | getInputStream(...) : InputStream | MvelInjection.java:63:7:63:16 | expression | MVEL injection from $@. | MvelInjection.java:58:27:58:49 | getInputStream(...) | this user input | diff --git a/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.java b/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.java index 23218e3cfcb2..cf62393ccac2 100644 --- a/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.java +++ b/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.java @@ -39,6 +39,7 @@ public static void testWithExpressionCompiler(Socket socket) throws IOException ExpressionCompiler compiler = new ExpressionCompiler(input); ExecutableStatement statement = compiler.compile(); statement.getValue(new Object(), new ImmutableDefaultFactory()); + statement.getValue(new Object(), new Object(), new ImmutableDefaultFactory()); } } diff --git a/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/Accessor.java b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/Accessor.java new file mode 100644 index 000000000000..5c01ab6366da --- /dev/null +++ b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/Accessor.java @@ -0,0 +1,7 @@ +package org.mvel2.compiler; + +import org.mvel2.integration.VariableResolverFactory; + +public interface Accessor { + public Object getValue(Object ctx, Object elCtx, VariableResolverFactory factory); +} \ No newline at end of file diff --git a/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/CompiledExpression.java b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/CompiledExpression.java index 234900b0fa32..b8a887b4f0db 100644 --- a/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/CompiledExpression.java +++ b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/CompiledExpression.java @@ -5,4 +5,5 @@ public class CompiledExpression implements ExecutableStatement { public Object getDirectValue(Object staticContext, VariableResolverFactory factory) { return null; } public Object getValue(Object staticContext, VariableResolverFactory factory) { return null; } + public Object getValue(Object ctx, Object elCtx, VariableResolverFactory factory) { return null; } } \ No newline at end of file diff --git a/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/ExecutableStatement.java b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/ExecutableStatement.java index 1e15b8e6678e..18f2f94feb06 100644 --- a/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/ExecutableStatement.java +++ b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/ExecutableStatement.java @@ -2,6 +2,6 @@ import org.mvel2.integration.VariableResolverFactory; -public interface ExecutableStatement { +public interface ExecutableStatement extends Accessor { public Object getValue(Object staticContext, VariableResolverFactory factory); } \ No newline at end of file From 8fd72659eca3d1b0f3ede5ddc6f2c5a6c9f30ecb Mon Sep 17 00:00:00 2001 From: Artem Smotrakov Date: Sat, 25 Apr 2020 13:21:41 +0200 Subject: [PATCH 05/10] Java: Added JSR 223 sinks for MVEL injections - Updated MvelInjectionLib.qll - Added tests and stubs for JSR 223 API --- .../Security/CWE/CWE-094/MvelInjectionLib.qll | 99 +++++++++++++++++-- .../CWE/CWE-094/MvelInjection.expected | 57 ++++++----- .../Security/CWE/CWE-094/MvelInjection.java | 33 +++++++ .../experimental/Security/CWE/CWE-094/options | 2 +- .../javax/script/CompiledScript.java | 5 + .../javax/script/ScriptContext.java | 3 + .../javax/script/ScriptException.java | 3 + .../javax/script/SimpleScriptContext.java | 3 + .../mvel2/compiler/ExecutableStatement.java | 3 +- .../org/mvel2/jsr223/MvelCompiledScript.java | 11 +++ .../org/mvel2/jsr223/MvelScriptEngine.java | 12 +++ 11 files changed, 199 insertions(+), 32 deletions(-) create mode 100644 java/ql/test/stubs/jsr223-api/javax/script/CompiledScript.java create mode 100644 java/ql/test/stubs/jsr223-api/javax/script/ScriptContext.java create mode 100644 java/ql/test/stubs/jsr223-api/javax/script/ScriptException.java create mode 100644 java/ql/test/stubs/jsr223-api/javax/script/SimpleScriptContext.java create mode 100644 java/ql/test/stubs/mvel2-2.4.7/org/mvel2/jsr223/MvelCompiledScript.java create mode 100644 java/ql/test/stubs/mvel2-2.4.7/org/mvel2/jsr223/MvelScriptEngine.java diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjectionLib.qll b/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjectionLib.qll index 0e1d6d38fdc0..5db66ea673ea 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjectionLib.qll +++ b/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjectionLib.qll @@ -18,7 +18,9 @@ class MvelInjectionConfig extends TaintTracking::Configuration { expressionCompilationStep(node1, node2) or createExpressionCompilerStep(node1, node2) or expressionCompilerCompileStep(node1, node2) or - createCompiledAccExpressionStep(node1, node2) + createCompiledAccExpressionStep(node1, node2) or + scriptCompileStep(node1, node2) or + createMvelCompiledScriptStep(node1, node2) } } @@ -30,7 +32,12 @@ class MvelEvaluationSink extends DataFlow::ExprNode { MvelEvaluationSink() { exists(StaticMethodAccess ma, Method m | m = ma.getMethod() | m instanceof MvelEvalMethod and - ma.getAnArgument() = asExpr() + ma.getArgument(0) = asExpr() + ) + or + exists(MethodAccess ma, Method m | m = ma.getMethod() | + m instanceof MvelScriptEngineEvaluationMethod and + ma.getArgument(0) = asExpr() ) or exists(MethodAccess ma, Method m | m = ma.getMethod() | @@ -38,7 +45,9 @@ class MvelEvaluationSink extends DataFlow::ExprNode { m instanceof ExecutableStatementEvaluationMethod or m instanceof CompiledExpressionEvaluationMethod or m instanceof CompiledAccExpressionEvaluationMethod or - m instanceof AccessorEvaluationMethod + m instanceof AccessorEvaluationMethod or + m instanceof CompiledScriptEvaluationMethod or + m instanceof MvelCompiledScriptEvaluationMethod ) and (ma = asExpr() or ma.getQualifier() = asExpr()) ) @@ -99,6 +108,30 @@ predicate expressionCompilerCompileStep(DataFlow::Node node1, DataFlow::Node nod ) } +/** + * Holds if `node1` to `node2` is a dataflow step that compiles a script via `MvelScriptEngine`, + * i.e. `engine.compile(tainted)` or `engine.compiledScript(tainted)`. + */ +predicate scriptCompileStep(DataFlow::Node node1, DataFlow::Node node2) { + exists(MethodAccess ma, Method m | ma.getMethod() = m | + m instanceof MvelScriptEngineCompilationnMethod and + (ma = node2.asExpr() or ma.getQualifier() = node2.asExpr()) and + ma.getArgument(0) = node1.asExpr() + ) +} + +/** + * Holds if `node1` to `node2` is a dataflow step creates `MvelCompiledScript`, + * i.e. `new MvelCompiledScript(engine, tainted)`. + */ +predicate createMvelCompiledScriptStep(DataFlow::Node node1, DataFlow::Node node2) { + exists(ConstructorCall cc | + cc.getConstructedType() instanceof MvelCompiledScript and + (cc = node2.asExpr() or cc.getQualifier() = node2.asExpr()) and + cc.getArgument(1) = node1.asExpr() + ) +} + /** * Methods in the MVEL class that evaluate a MVEL expression. */ @@ -131,7 +164,7 @@ class MvelCompileExpressionMethod extends Method { } /** - * Methods in `ExecutableStatement` that trigger evaluating a MVEL expression. + * Methods in `ExecutableStatement` that evaluate a MVEL expression. */ class ExecutableStatementEvaluationMethod extends Method { ExecutableStatementEvaluationMethod() { @@ -141,7 +174,7 @@ class ExecutableStatementEvaluationMethod extends Method { } /** - * Methods in `CompiledExpression` that trigger evaluating a MVEL expression. + * Methods in `CompiledExpression` that evaluate a MVEL expression. */ class CompiledExpressionEvaluationMethod extends Method { CompiledExpressionEvaluationMethod() { @@ -151,7 +184,7 @@ class CompiledExpressionEvaluationMethod extends Method { } /** - * Methods in `CompiledAccExpression` that trigger evaluating a MVEL expression. + * Methods in `CompiledAccExpression` that evaluate a MVEL expression. */ class CompiledAccExpressionEvaluationMethod extends Method { CompiledAccExpressionEvaluationMethod() { @@ -161,7 +194,7 @@ class CompiledAccExpressionEvaluationMethod extends Method { } /** - * Methods in `Accessor` that trigger evaluating a MVEL expression. + * Methods in `Accessor` that evaluate a MVEL expression. */ class AccessorEvaluationMethod extends Method { AccessorEvaluationMethod() { @@ -170,6 +203,46 @@ class AccessorEvaluationMethod extends Method { } } +/** + * Methods in `MvelScriptEngine` that evaluate a MVEL expression. + */ +class MvelScriptEngineEvaluationMethod extends Method { + MvelScriptEngineEvaluationMethod() { + getDeclaringType() instanceof MvelScriptEngine and + (hasName("eval") or hasName("evaluate")) + } +} + +/** + * Methods in `MvelScriptEngine` that compile a MVEL expression. + */ +class MvelScriptEngineCompilationnMethod extends Method { + MvelScriptEngineCompilationnMethod() { + getDeclaringType() instanceof MvelScriptEngine and + (hasName("compile") or hasName("compiledScript")) + } +} + +/** + * Methods in `CompiledScript` that evaluate a MVEL expression. + */ +class CompiledScriptEvaluationMethod extends Method { + CompiledScriptEvaluationMethod() { + getDeclaringType() instanceof CompiledScript and + hasName("eval") + } +} + +/** + * Methods in `MvelCompiledScript` that evaluate a MVEL expression. + */ +class MvelCompiledScriptEvaluationMethod extends Method { + MvelCompiledScriptEvaluationMethod() { + getDeclaringType() instanceof MvelCompiledScript and + hasName("eval") + } +} + class MVEL extends RefType { MVEL() { hasQualifiedName("org.mvel2", "MVEL") } } @@ -193,3 +266,15 @@ class CompiledAccExpression extends RefType { class Accessor extends RefType { Accessor() { hasQualifiedName("org.mvel2.compiler", "Accessor") } } + +class CompiledScript extends RefType { + CompiledScript() { hasQualifiedName("javax.script", "CompiledScript") } +} + +class MvelScriptEngine extends RefType { + MvelScriptEngine() { hasQualifiedName("org.mvel2.jsr223", "MvelScriptEngine") } +} + +class MvelCompiledScript extends RefType { + MvelCompiledScript() { hasQualifiedName("org.mvel2.jsr223", "MvelCompiledScript") } +} diff --git a/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.expected b/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.expected index 2cf20b0d79f2..841d76e4750e 100644 --- a/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.expected +++ b/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.expected @@ -1,26 +1,37 @@ edges -| MvelInjection.java:16:27:16:49 | getInputStream(...) : InputStream | MvelInjection.java:20:17:20:21 | input | -| MvelInjection.java:25:27:25:49 | getInputStream(...) : InputStream | MvelInjection.java:30:30:30:39 | expression | -| MvelInjection.java:35:27:35:49 | getInputStream(...) : InputStream | MvelInjection.java:41:7:41:15 | statement | -| MvelInjection.java:35:27:35:49 | getInputStream(...) : InputStream | MvelInjection.java:42:7:42:15 | statement | -| MvelInjection.java:47:27:47:49 | getInputStream(...) : InputStream | MvelInjection.java:53:7:53:16 | expression | -| MvelInjection.java:58:27:58:49 | getInputStream(...) : InputStream | MvelInjection.java:63:7:63:16 | expression | +| MvelInjection.java:20:27:20:49 | getInputStream(...) : InputStream | MvelInjection.java:24:17:24:21 | input | +| MvelInjection.java:29:27:29:49 | getInputStream(...) : InputStream | MvelInjection.java:34:30:34:39 | expression | +| MvelInjection.java:39:27:39:49 | getInputStream(...) : InputStream | MvelInjection.java:45:7:45:15 | statement | +| MvelInjection.java:39:27:39:49 | getInputStream(...) : InputStream | MvelInjection.java:46:7:46:15 | statement | +| MvelInjection.java:51:27:51:49 | getInputStream(...) : InputStream | MvelInjection.java:57:7:57:16 | expression | +| MvelInjection.java:62:27:62:49 | getInputStream(...) : InputStream | MvelInjection.java:67:7:67:16 | expression | +| MvelInjection.java:72:22:72:44 | getInputStream(...) : InputStream | MvelInjection.java:80:5:80:18 | compiledScript | +| MvelInjection.java:72:22:72:44 | getInputStream(...) : InputStream | MvelInjection.java:83:21:83:26 | script | +| MvelInjection.java:87:22:87:44 | getInputStream(...) : InputStream | MvelInjection.java:97:5:97:10 | script | nodes -| MvelInjection.java:16:27:16:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| MvelInjection.java:20:17:20:21 | input | semmle.label | input | -| MvelInjection.java:25:27:25:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| MvelInjection.java:30:30:30:39 | expression | semmle.label | expression | -| MvelInjection.java:35:27:35:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| MvelInjection.java:41:7:41:15 | statement | semmle.label | statement | -| MvelInjection.java:42:7:42:15 | statement | semmle.label | statement | -| MvelInjection.java:47:27:47:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| MvelInjection.java:53:7:53:16 | expression | semmle.label | expression | -| MvelInjection.java:58:27:58:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| MvelInjection.java:63:7:63:16 | expression | semmle.label | expression | +| MvelInjection.java:20:27:20:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:24:17:24:21 | input | semmle.label | input | +| MvelInjection.java:29:27:29:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:34:30:34:39 | expression | semmle.label | expression | +| MvelInjection.java:39:27:39:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:45:7:45:15 | statement | semmle.label | statement | +| MvelInjection.java:46:7:46:15 | statement | semmle.label | statement | +| MvelInjection.java:51:27:51:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:57:7:57:16 | expression | semmle.label | expression | +| MvelInjection.java:62:27:62:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:67:7:67:16 | expression | semmle.label | expression | +| MvelInjection.java:72:22:72:44 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:80:5:80:18 | compiledScript | semmle.label | compiledScript | +| MvelInjection.java:83:21:83:26 | script | semmle.label | script | +| MvelInjection.java:87:22:87:44 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:97:5:97:10 | script | semmle.label | script | #select -| MvelInjection.java:20:17:20:21 | input | MvelInjection.java:16:27:16:49 | getInputStream(...) : InputStream | MvelInjection.java:20:17:20:21 | input | MVEL injection from $@. | MvelInjection.java:16:27:16:49 | getInputStream(...) | this user input | -| MvelInjection.java:30:30:30:39 | expression | MvelInjection.java:25:27:25:49 | getInputStream(...) : InputStream | MvelInjection.java:30:30:30:39 | expression | MVEL injection from $@. | MvelInjection.java:25:27:25:49 | getInputStream(...) | this user input | -| MvelInjection.java:41:7:41:15 | statement | MvelInjection.java:35:27:35:49 | getInputStream(...) : InputStream | MvelInjection.java:41:7:41:15 | statement | MVEL injection from $@. | MvelInjection.java:35:27:35:49 | getInputStream(...) | this user input | -| MvelInjection.java:42:7:42:15 | statement | MvelInjection.java:35:27:35:49 | getInputStream(...) : InputStream | MvelInjection.java:42:7:42:15 | statement | MVEL injection from $@. | MvelInjection.java:35:27:35:49 | getInputStream(...) | this user input | -| MvelInjection.java:53:7:53:16 | expression | MvelInjection.java:47:27:47:49 | getInputStream(...) : InputStream | MvelInjection.java:53:7:53:16 | expression | MVEL injection from $@. | MvelInjection.java:47:27:47:49 | getInputStream(...) | this user input | -| MvelInjection.java:63:7:63:16 | expression | MvelInjection.java:58:27:58:49 | getInputStream(...) : InputStream | MvelInjection.java:63:7:63:16 | expression | MVEL injection from $@. | MvelInjection.java:58:27:58:49 | getInputStream(...) | this user input | +| MvelInjection.java:24:17:24:21 | input | MvelInjection.java:20:27:20:49 | getInputStream(...) : InputStream | MvelInjection.java:24:17:24:21 | input | MVEL injection from $@. | MvelInjection.java:20:27:20:49 | getInputStream(...) | this user input | +| MvelInjection.java:34:30:34:39 | expression | MvelInjection.java:29:27:29:49 | getInputStream(...) : InputStream | MvelInjection.java:34:30:34:39 | expression | MVEL injection from $@. | MvelInjection.java:29:27:29:49 | getInputStream(...) | this user input | +| MvelInjection.java:45:7:45:15 | statement | MvelInjection.java:39:27:39:49 | getInputStream(...) : InputStream | MvelInjection.java:45:7:45:15 | statement | MVEL injection from $@. | MvelInjection.java:39:27:39:49 | getInputStream(...) | this user input | +| MvelInjection.java:46:7:46:15 | statement | MvelInjection.java:39:27:39:49 | getInputStream(...) : InputStream | MvelInjection.java:46:7:46:15 | statement | MVEL injection from $@. | MvelInjection.java:39:27:39:49 | getInputStream(...) | this user input | +| MvelInjection.java:57:7:57:16 | expression | MvelInjection.java:51:27:51:49 | getInputStream(...) : InputStream | MvelInjection.java:57:7:57:16 | expression | MVEL injection from $@. | MvelInjection.java:51:27:51:49 | getInputStream(...) | this user input | +| MvelInjection.java:67:7:67:16 | expression | MvelInjection.java:62:27:62:49 | getInputStream(...) : InputStream | MvelInjection.java:67:7:67:16 | expression | MVEL injection from $@. | MvelInjection.java:62:27:62:49 | getInputStream(...) | this user input | +| MvelInjection.java:80:5:80:18 | compiledScript | MvelInjection.java:72:22:72:44 | getInputStream(...) : InputStream | MvelInjection.java:80:5:80:18 | compiledScript | MVEL injection from $@. | MvelInjection.java:72:22:72:44 | getInputStream(...) | this user input | +| MvelInjection.java:83:21:83:26 | script | MvelInjection.java:72:22:72:44 | getInputStream(...) : InputStream | MvelInjection.java:83:21:83:26 | script | MVEL injection from $@. | MvelInjection.java:72:22:72:44 | getInputStream(...) | this user input | +| MvelInjection.java:97:5:97:10 | script | MvelInjection.java:87:22:87:44 | getInputStream(...) : InputStream | MvelInjection.java:97:5:97:10 | script | MVEL injection from $@. | MvelInjection.java:87:22:87:44 | getInputStream(...) | this user input | diff --git a/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.java b/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.java index cf62393ccac2..aaa264b3c260 100644 --- a/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.java +++ b/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.java @@ -2,6 +2,8 @@ import java.io.InputStream; import java.io.Serializable; import java.net.Socket; +import javax.script.CompiledScript; +import javax.script.SimpleScriptContext; import org.mvel2.MVEL; import org.mvel2.ParserContext; import org.mvel2.compiler.CompiledAccExpression; @@ -9,6 +11,8 @@ import org.mvel2.compiler.ExecutableStatement; import org.mvel2.compiler.ExpressionCompiler; import org.mvel2.integration.impl.ImmutableDefaultFactory; +import org.mvel2.jsr223.MvelCompiledScript; +import org.mvel2.jsr223.MvelScriptEngine; public class MvelInjection { @@ -63,4 +67,33 @@ public static void testCompiledAccExpressionGetValue(Socket socket) throws IOExc expression.getValue(new Object(), new ImmutableDefaultFactory()); } } + + public static void testMvelScriptEngineCompileAndEvaluate(Socket socket) throws Exception { + InputStream in = socket.getInputStream(); + + byte[] bytes = new byte[1024]; + int n = in.read(bytes); + String input = new String(bytes, 0, n); + + MvelScriptEngine engine = new MvelScriptEngine(); + CompiledScript compiledScript = engine.compile(input); + compiledScript.eval(); + + Serializable script = engine.compiledScript(input); + engine.evaluate(script, new SimpleScriptContext()); + } + + public static void testMvelCompiledScriptCompileAndEvaluate(Socket socket) throws Exception { + InputStream in = socket.getInputStream(); + + byte[] bytes = new byte[1024]; + int n = in.read(bytes); + String input = new String(bytes, 0, n); + + MvelScriptEngine engine = new MvelScriptEngine(); + ExpressionCompiler compiler = new ExpressionCompiler(input); + ExecutableStatement statement = compiler.compile(); + MvelCompiledScript script = new MvelCompiledScript(engine, statement); + script.eval(new SimpleScriptContext()); + } } diff --git a/java/ql/test/experimental/Security/CWE/CWE-094/options b/java/ql/test/experimental/Security/CWE/CWE-094/options index 2048ced65b40..51fae354cec3 100644 --- a/java/ql/test/experimental/Security/CWE/CWE-094/options +++ b/java/ql/test/experimental/Security/CWE/CWE-094/options @@ -1 +1 @@ -//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/springframework-5.2.3:${testdir}/../../../../stubs/mvel2-2.4.7 +//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/springframework-5.2.3:${testdir}/../../../../stubs/mvel2-2.4.7:${testdir}/../../../../stubs/jsr223-api diff --git a/java/ql/test/stubs/jsr223-api/javax/script/CompiledScript.java b/java/ql/test/stubs/jsr223-api/javax/script/CompiledScript.java new file mode 100644 index 000000000000..dba6c9f88d24 --- /dev/null +++ b/java/ql/test/stubs/jsr223-api/javax/script/CompiledScript.java @@ -0,0 +1,5 @@ +package javax.script; + +public class CompiledScript { + public Object eval() throws ScriptException { return null; } +} \ No newline at end of file diff --git a/java/ql/test/stubs/jsr223-api/javax/script/ScriptContext.java b/java/ql/test/stubs/jsr223-api/javax/script/ScriptContext.java new file mode 100644 index 000000000000..1e587a0a9bb5 --- /dev/null +++ b/java/ql/test/stubs/jsr223-api/javax/script/ScriptContext.java @@ -0,0 +1,3 @@ +package javax.script; + +public interface ScriptContext {} \ No newline at end of file diff --git a/java/ql/test/stubs/jsr223-api/javax/script/ScriptException.java b/java/ql/test/stubs/jsr223-api/javax/script/ScriptException.java new file mode 100644 index 000000000000..65d124925c9d --- /dev/null +++ b/java/ql/test/stubs/jsr223-api/javax/script/ScriptException.java @@ -0,0 +1,3 @@ +package javax.script; + +public class ScriptException extends Exception {} diff --git a/java/ql/test/stubs/jsr223-api/javax/script/SimpleScriptContext.java b/java/ql/test/stubs/jsr223-api/javax/script/SimpleScriptContext.java new file mode 100644 index 000000000000..b292cb8b9a6b --- /dev/null +++ b/java/ql/test/stubs/jsr223-api/javax/script/SimpleScriptContext.java @@ -0,0 +1,3 @@ +package javax.script; + +public class SimpleScriptContext implements ScriptContext {} \ No newline at end of file diff --git a/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/ExecutableStatement.java b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/ExecutableStatement.java index 18f2f94feb06..8aed7035aa67 100644 --- a/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/ExecutableStatement.java +++ b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/compiler/ExecutableStatement.java @@ -1,7 +1,8 @@ package org.mvel2.compiler; +import java.io.Serializable; import org.mvel2.integration.VariableResolverFactory; -public interface ExecutableStatement extends Accessor { +public interface ExecutableStatement extends Accessor, Serializable { public Object getValue(Object staticContext, VariableResolverFactory factory); } \ No newline at end of file diff --git a/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/jsr223/MvelCompiledScript.java b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/jsr223/MvelCompiledScript.java new file mode 100644 index 000000000000..a4be37ada323 --- /dev/null +++ b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/jsr223/MvelCompiledScript.java @@ -0,0 +1,11 @@ +package org.mvel2.jsr223; + +import java.io.Serializable; +import javax.script.CompiledScript; +import javax.script.ScriptContext; +import javax.script.ScriptException; + +public class MvelCompiledScript extends CompiledScript { + public MvelCompiledScript(MvelScriptEngine engine, Serializable compiledScript) {} + public Object eval(ScriptContext context) throws ScriptException { return null; } +} \ No newline at end of file diff --git a/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/jsr223/MvelScriptEngine.java b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/jsr223/MvelScriptEngine.java new file mode 100644 index 000000000000..6769a6198a4e --- /dev/null +++ b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/jsr223/MvelScriptEngine.java @@ -0,0 +1,12 @@ +package org.mvel2.jsr223; + +import java.io.Serializable; +import javax.script.CompiledScript; +import javax.script.ScriptContext; +import javax.script.ScriptException; + +public class MvelScriptEngine { + public CompiledScript compile(String script) throws ScriptException { return null; } + public Serializable compiledScript(String script) throws ScriptException { return null; } + public Object evaluate(Serializable expression, ScriptContext context) throws ScriptException { return null; } +} \ No newline at end of file From fa717b2d864afa861f0cef73b2cbefc43734835b Mon Sep 17 00:00:00 2001 From: Artem Smotrakov Date: Fri, 1 May 2020 16:48:20 +0200 Subject: [PATCH 06/10] Java: Added template sinks for MVEL injections --- .../Security/CWE/CWE-094/MvelInjectionLib.qll | 83 +++++++++++++++++-- .../CWE/CWE-094/MvelInjection.expected | 80 ++++++++++-------- .../Security/CWE/CWE-094/MvelInjection.java | 35 ++++++++ .../org/mvel2/templates/CompiledTemplate.java | 3 + .../org/mvel2/templates/TemplateCompiler.java | 7 ++ .../org/mvel2/templates/TemplateRuntime.java | 8 ++ 6 files changed, 177 insertions(+), 39 deletions(-) create mode 100644 java/ql/test/stubs/mvel2-2.4.7/org/mvel2/templates/CompiledTemplate.java create mode 100644 java/ql/test/stubs/mvel2-2.4.7/org/mvel2/templates/TemplateCompiler.java create mode 100644 java/ql/test/stubs/mvel2-2.4.7/org/mvel2/templates/TemplateRuntime.java diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjectionLib.qll b/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjectionLib.qll index 5db66ea673ea..4810aa8e5068 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjectionLib.qll +++ b/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjectionLib.qll @@ -20,7 +20,9 @@ class MvelInjectionConfig extends TaintTracking::Configuration { expressionCompilerCompileStep(node1, node2) or createCompiledAccExpressionStep(node1, node2) or scriptCompileStep(node1, node2) or - createMvelCompiledScriptStep(node1, node2) + createMvelCompiledScriptStep(node1, node2) or + templateCompileStep(node1, node2) or + createTemplateCompilerStep(node1, node2) } } @@ -31,7 +33,10 @@ class MvelInjectionConfig extends TaintTracking::Configuration { class MvelEvaluationSink extends DataFlow::ExprNode { MvelEvaluationSink() { exists(StaticMethodAccess ma, Method m | m = ma.getMethod() | - m instanceof MvelEvalMethod and + ( + m instanceof MvelEvalMethod or + m instanceof TemplateRuntimeEvaluationMethod + ) and ma.getArgument(0) = asExpr() ) or @@ -114,7 +119,7 @@ predicate expressionCompilerCompileStep(DataFlow::Node node1, DataFlow::Node nod */ predicate scriptCompileStep(DataFlow::Node node1, DataFlow::Node node2) { exists(MethodAccess ma, Method m | ma.getMethod() = m | - m instanceof MvelScriptEngineCompilationnMethod and + m instanceof MvelScriptEngineCompilationMethod and (ma = node2.asExpr() or ma.getQualifier() = node2.asExpr()) and ma.getArgument(0) = node1.asExpr() ) @@ -132,6 +137,36 @@ predicate createMvelCompiledScriptStep(DataFlow::Node node1, DataFlow::Node node ) } +/** + * Holds if `node1` to `node2` is a dataflow step creates `TemplateCompiler`, + * i.e. `new TemplateCompiler(tainted)`. + */ +predicate createTemplateCompilerStep(DataFlow::Node node1, DataFlow::Node node2) { + exists(ConstructorCall cc | + cc.getConstructedType() instanceof TemplateCompiler and + (cc = node2.asExpr() or cc.getQualifier() = node2.asExpr()) and + cc.getArgument(0) = node1.asExpr() + ) +} + +/** + * Holds if `node1` to `node2` is a dataflow step that compiles a script via `TemplateCompiler`, + * i.e. `compiler.compile()` or `TemplateCompiler.compileTemplate(tainted)`. + */ +predicate templateCompileStep(DataFlow::Node node1, DataFlow::Node node2) { + exists(MethodAccess ma, Method m | ma.getMethod() = m | + m instanceof TemplateCompilerCompileMethod and + ma.getQualifier() = node1.asExpr() and + ma = node2.asExpr() + ) + or + exists(StaticMethodAccess ma, Method m | ma.getMethod() = m | + m instanceof TemplateCompilerCompileTemplateMethod and + (ma = node2.asExpr() or ma.getQualifier() = node2.asExpr()) and + ma.getArgument(0) = node1.asExpr() + ) +} + /** * Methods in the MVEL class that evaluate a MVEL expression. */ @@ -216,8 +251,8 @@ class MvelScriptEngineEvaluationMethod extends Method { /** * Methods in `MvelScriptEngine` that compile a MVEL expression. */ -class MvelScriptEngineCompilationnMethod extends Method { - MvelScriptEngineCompilationnMethod() { +class MvelScriptEngineCompilationMethod extends Method { + MvelScriptEngineCompilationMethod() { getDeclaringType() instanceof MvelScriptEngine and (hasName("compile") or hasName("compiledScript")) } @@ -233,6 +268,36 @@ class CompiledScriptEvaluationMethod extends Method { } } +/** + * Methods in `TemplateRuntime` that evaluate a MVEL template. + */ +class TemplateRuntimeEvaluationMethod extends Method { + TemplateRuntimeEvaluationMethod() { + getDeclaringType() instanceof TemplateRuntime and + (hasName("eval") or hasName("execute")) + } +} + +/** + * `TemplateCompiler.compile()` method compiles a MVEL template. + */ +class TemplateCompilerCompileMethod extends Method { + TemplateCompilerCompileMethod() { + getDeclaringType() instanceof TemplateCompiler and + hasName("compile") + } +} + +/** + * `TemplateCompiler.compileTemplate(tainted)` static method compiles a MVEL template. + */ +class TemplateCompilerCompileTemplateMethod extends Method { + TemplateCompilerCompileTemplateMethod() { + getDeclaringType() instanceof TemplateCompiler and + hasName("compileTemplate") + } +} + /** * Methods in `MvelCompiledScript` that evaluate a MVEL expression. */ @@ -278,3 +343,11 @@ class MvelScriptEngine extends RefType { class MvelCompiledScript extends RefType { MvelCompiledScript() { hasQualifiedName("org.mvel2.jsr223", "MvelCompiledScript") } } + +class TemplateRuntime extends RefType { + TemplateRuntime() { hasQualifiedName("org.mvel2.templates", "TemplateRuntime") } +} + +class TemplateCompiler extends RefType { + TemplateCompiler() { hasQualifiedName("org.mvel2.templates", "TemplateCompiler") } +} diff --git a/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.expected b/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.expected index 841d76e4750e..c340cd5a19a8 100644 --- a/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.expected +++ b/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.expected @@ -1,37 +1,49 @@ edges -| MvelInjection.java:20:27:20:49 | getInputStream(...) : InputStream | MvelInjection.java:24:17:24:21 | input | -| MvelInjection.java:29:27:29:49 | getInputStream(...) : InputStream | MvelInjection.java:34:30:34:39 | expression | -| MvelInjection.java:39:27:39:49 | getInputStream(...) : InputStream | MvelInjection.java:45:7:45:15 | statement | -| MvelInjection.java:39:27:39:49 | getInputStream(...) : InputStream | MvelInjection.java:46:7:46:15 | statement | -| MvelInjection.java:51:27:51:49 | getInputStream(...) : InputStream | MvelInjection.java:57:7:57:16 | expression | -| MvelInjection.java:62:27:62:49 | getInputStream(...) : InputStream | MvelInjection.java:67:7:67:16 | expression | -| MvelInjection.java:72:22:72:44 | getInputStream(...) : InputStream | MvelInjection.java:80:5:80:18 | compiledScript | -| MvelInjection.java:72:22:72:44 | getInputStream(...) : InputStream | MvelInjection.java:83:21:83:26 | script | -| MvelInjection.java:87:22:87:44 | getInputStream(...) : InputStream | MvelInjection.java:97:5:97:10 | script | +| MvelInjection.java:24:27:24:49 | getInputStream(...) : InputStream | MvelInjection.java:28:17:28:21 | input | +| MvelInjection.java:33:27:33:49 | getInputStream(...) : InputStream | MvelInjection.java:38:30:38:39 | expression | +| MvelInjection.java:43:27:43:49 | getInputStream(...) : InputStream | MvelInjection.java:49:7:49:15 | statement | +| MvelInjection.java:43:27:43:49 | getInputStream(...) : InputStream | MvelInjection.java:50:7:50:15 | statement | +| MvelInjection.java:55:27:55:49 | getInputStream(...) : InputStream | MvelInjection.java:61:7:61:16 | expression | +| MvelInjection.java:66:27:66:49 | getInputStream(...) : InputStream | MvelInjection.java:71:7:71:16 | expression | +| MvelInjection.java:76:22:76:44 | getInputStream(...) : InputStream | MvelInjection.java:84:5:84:18 | compiledScript | +| MvelInjection.java:76:22:76:44 | getInputStream(...) : InputStream | MvelInjection.java:87:21:87:26 | script | +| MvelInjection.java:91:22:91:44 | getInputStream(...) : InputStream | MvelInjection.java:101:5:101:10 | script | +| MvelInjection.java:105:22:105:44 | getInputStream(...) : InputStream | MvelInjection.java:111:26:111:30 | input | +| MvelInjection.java:115:22:115:44 | getInputStream(...) : InputStream | MvelInjection.java:121:29:121:67 | compileTemplate(...) | +| MvelInjection.java:125:22:125:44 | getInputStream(...) : InputStream | MvelInjection.java:132:54:132:71 | compile(...) | nodes -| MvelInjection.java:20:27:20:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| MvelInjection.java:24:17:24:21 | input | semmle.label | input | -| MvelInjection.java:29:27:29:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| MvelInjection.java:34:30:34:39 | expression | semmle.label | expression | -| MvelInjection.java:39:27:39:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| MvelInjection.java:45:7:45:15 | statement | semmle.label | statement | -| MvelInjection.java:46:7:46:15 | statement | semmle.label | statement | -| MvelInjection.java:51:27:51:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| MvelInjection.java:57:7:57:16 | expression | semmle.label | expression | -| MvelInjection.java:62:27:62:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| MvelInjection.java:67:7:67:16 | expression | semmle.label | expression | -| MvelInjection.java:72:22:72:44 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| MvelInjection.java:80:5:80:18 | compiledScript | semmle.label | compiledScript | -| MvelInjection.java:83:21:83:26 | script | semmle.label | script | -| MvelInjection.java:87:22:87:44 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| MvelInjection.java:97:5:97:10 | script | semmle.label | script | +| MvelInjection.java:24:27:24:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:28:17:28:21 | input | semmle.label | input | +| MvelInjection.java:33:27:33:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:38:30:38:39 | expression | semmle.label | expression | +| MvelInjection.java:43:27:43:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:49:7:49:15 | statement | semmle.label | statement | +| MvelInjection.java:50:7:50:15 | statement | semmle.label | statement | +| MvelInjection.java:55:27:55:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:61:7:61:16 | expression | semmle.label | expression | +| MvelInjection.java:66:27:66:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:71:7:71:16 | expression | semmle.label | expression | +| MvelInjection.java:76:22:76:44 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:84:5:84:18 | compiledScript | semmle.label | compiledScript | +| MvelInjection.java:87:21:87:26 | script | semmle.label | script | +| MvelInjection.java:91:22:91:44 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:101:5:101:10 | script | semmle.label | script | +| MvelInjection.java:105:22:105:44 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:111:26:111:30 | input | semmle.label | input | +| MvelInjection.java:115:22:115:44 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:121:29:121:67 | compileTemplate(...) | semmle.label | compileTemplate(...) | +| MvelInjection.java:125:22:125:44 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:132:54:132:71 | compile(...) | semmle.label | compile(...) | #select -| MvelInjection.java:24:17:24:21 | input | MvelInjection.java:20:27:20:49 | getInputStream(...) : InputStream | MvelInjection.java:24:17:24:21 | input | MVEL injection from $@. | MvelInjection.java:20:27:20:49 | getInputStream(...) | this user input | -| MvelInjection.java:34:30:34:39 | expression | MvelInjection.java:29:27:29:49 | getInputStream(...) : InputStream | MvelInjection.java:34:30:34:39 | expression | MVEL injection from $@. | MvelInjection.java:29:27:29:49 | getInputStream(...) | this user input | -| MvelInjection.java:45:7:45:15 | statement | MvelInjection.java:39:27:39:49 | getInputStream(...) : InputStream | MvelInjection.java:45:7:45:15 | statement | MVEL injection from $@. | MvelInjection.java:39:27:39:49 | getInputStream(...) | this user input | -| MvelInjection.java:46:7:46:15 | statement | MvelInjection.java:39:27:39:49 | getInputStream(...) : InputStream | MvelInjection.java:46:7:46:15 | statement | MVEL injection from $@. | MvelInjection.java:39:27:39:49 | getInputStream(...) | this user input | -| MvelInjection.java:57:7:57:16 | expression | MvelInjection.java:51:27:51:49 | getInputStream(...) : InputStream | MvelInjection.java:57:7:57:16 | expression | MVEL injection from $@. | MvelInjection.java:51:27:51:49 | getInputStream(...) | this user input | -| MvelInjection.java:67:7:67:16 | expression | MvelInjection.java:62:27:62:49 | getInputStream(...) : InputStream | MvelInjection.java:67:7:67:16 | expression | MVEL injection from $@. | MvelInjection.java:62:27:62:49 | getInputStream(...) | this user input | -| MvelInjection.java:80:5:80:18 | compiledScript | MvelInjection.java:72:22:72:44 | getInputStream(...) : InputStream | MvelInjection.java:80:5:80:18 | compiledScript | MVEL injection from $@. | MvelInjection.java:72:22:72:44 | getInputStream(...) | this user input | -| MvelInjection.java:83:21:83:26 | script | MvelInjection.java:72:22:72:44 | getInputStream(...) : InputStream | MvelInjection.java:83:21:83:26 | script | MVEL injection from $@. | MvelInjection.java:72:22:72:44 | getInputStream(...) | this user input | -| MvelInjection.java:97:5:97:10 | script | MvelInjection.java:87:22:87:44 | getInputStream(...) : InputStream | MvelInjection.java:97:5:97:10 | script | MVEL injection from $@. | MvelInjection.java:87:22:87:44 | getInputStream(...) | this user input | +| MvelInjection.java:28:17:28:21 | input | MvelInjection.java:24:27:24:49 | getInputStream(...) : InputStream | MvelInjection.java:28:17:28:21 | input | MVEL injection from $@. | MvelInjection.java:24:27:24:49 | getInputStream(...) | this user input | +| MvelInjection.java:38:30:38:39 | expression | MvelInjection.java:33:27:33:49 | getInputStream(...) : InputStream | MvelInjection.java:38:30:38:39 | expression | MVEL injection from $@. | MvelInjection.java:33:27:33:49 | getInputStream(...) | this user input | +| MvelInjection.java:49:7:49:15 | statement | MvelInjection.java:43:27:43:49 | getInputStream(...) : InputStream | MvelInjection.java:49:7:49:15 | statement | MVEL injection from $@. | MvelInjection.java:43:27:43:49 | getInputStream(...) | this user input | +| MvelInjection.java:50:7:50:15 | statement | MvelInjection.java:43:27:43:49 | getInputStream(...) : InputStream | MvelInjection.java:50:7:50:15 | statement | MVEL injection from $@. | MvelInjection.java:43:27:43:49 | getInputStream(...) | this user input | +| MvelInjection.java:61:7:61:16 | expression | MvelInjection.java:55:27:55:49 | getInputStream(...) : InputStream | MvelInjection.java:61:7:61:16 | expression | MVEL injection from $@. | MvelInjection.java:55:27:55:49 | getInputStream(...) | this user input | +| MvelInjection.java:71:7:71:16 | expression | MvelInjection.java:66:27:66:49 | getInputStream(...) : InputStream | MvelInjection.java:71:7:71:16 | expression | MVEL injection from $@. | MvelInjection.java:66:27:66:49 | getInputStream(...) | this user input | +| MvelInjection.java:84:5:84:18 | compiledScript | MvelInjection.java:76:22:76:44 | getInputStream(...) : InputStream | MvelInjection.java:84:5:84:18 | compiledScript | MVEL injection from $@. | MvelInjection.java:76:22:76:44 | getInputStream(...) | this user input | +| MvelInjection.java:87:21:87:26 | script | MvelInjection.java:76:22:76:44 | getInputStream(...) : InputStream | MvelInjection.java:87:21:87:26 | script | MVEL injection from $@. | MvelInjection.java:76:22:76:44 | getInputStream(...) | this user input | +| MvelInjection.java:101:5:101:10 | script | MvelInjection.java:91:22:91:44 | getInputStream(...) : InputStream | MvelInjection.java:101:5:101:10 | script | MVEL injection from $@. | MvelInjection.java:91:22:91:44 | getInputStream(...) | this user input | +| MvelInjection.java:111:26:111:30 | input | MvelInjection.java:105:22:105:44 | getInputStream(...) : InputStream | MvelInjection.java:111:26:111:30 | input | MVEL injection from $@. | MvelInjection.java:105:22:105:44 | getInputStream(...) | this user input | +| MvelInjection.java:121:29:121:67 | compileTemplate(...) | MvelInjection.java:115:22:115:44 | getInputStream(...) : InputStream | MvelInjection.java:121:29:121:67 | compileTemplate(...) | MVEL injection from $@. | MvelInjection.java:115:22:115:44 | getInputStream(...) | this user input | +| MvelInjection.java:132:54:132:71 | compile(...) | MvelInjection.java:125:22:125:44 | getInputStream(...) : InputStream | MvelInjection.java:132:54:132:71 | compile(...) | MVEL injection from $@. | MvelInjection.java:125:22:125:44 | getInputStream(...) | this user input | diff --git a/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.java b/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.java index aaa264b3c260..b5ef1625502f 100644 --- a/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.java +++ b/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.java @@ -2,6 +2,7 @@ import java.io.InputStream; import java.io.Serializable; import java.net.Socket; +import java.util.HashMap; import javax.script.CompiledScript; import javax.script.SimpleScriptContext; import org.mvel2.MVEL; @@ -13,6 +14,9 @@ import org.mvel2.integration.impl.ImmutableDefaultFactory; import org.mvel2.jsr223.MvelCompiledScript; import org.mvel2.jsr223.MvelScriptEngine; +import org.mvel2.templates.CompiledTemplate; +import org.mvel2.templates.TemplateCompiler; +import org.mvel2.templates.TemplateRuntime; public class MvelInjection { @@ -96,4 +100,35 @@ public static void testMvelCompiledScriptCompileAndEvaluate(Socket socket) throw MvelCompiledScript script = new MvelCompiledScript(engine, statement); script.eval(new SimpleScriptContext()); } + + public static void testTemplateRuntimeEval(Socket socket) throws Exception { + InputStream in = socket.getInputStream(); + + byte[] bytes = new byte[1024]; + int n = in.read(bytes); + String input = new String(bytes, 0, n); + + TemplateRuntime.eval(input, new HashMap()); + } + + public static void testTemplateRuntimeCompileTemplateAndExecute(Socket socket) throws Exception { + InputStream in = socket.getInputStream(); + + byte[] bytes = new byte[1024]; + int n = in.read(bytes); + String input = new String(bytes, 0, n); + + TemplateRuntime.execute(TemplateCompiler.compileTemplate(input), new HashMap()); + } + + public static void testTemplateRuntimeCompileAndExecute(Socket socket) throws Exception { + InputStream in = socket.getInputStream(); + + byte[] bytes = new byte[1024]; + int n = in.read(bytes); + String input = new String(bytes, 0, n); + + TemplateCompiler compiler = new TemplateCompiler(input); + String output = (String) TemplateRuntime.execute(compiler.compile(), new HashMap()); + } } diff --git a/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/templates/CompiledTemplate.java b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/templates/CompiledTemplate.java new file mode 100644 index 000000000000..d0152d28318e --- /dev/null +++ b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/templates/CompiledTemplate.java @@ -0,0 +1,3 @@ +package org.mvel2.templates; + +public class CompiledTemplate {} \ No newline at end of file diff --git a/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/templates/TemplateCompiler.java b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/templates/TemplateCompiler.java new file mode 100644 index 000000000000..333e4164bcd4 --- /dev/null +++ b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/templates/TemplateCompiler.java @@ -0,0 +1,7 @@ +package org.mvel2.templates; + +public class TemplateCompiler { + public TemplateCompiler(String template) {} + public static CompiledTemplate compileTemplate(String template) { return null; } + public CompiledTemplate compile() { return null; } +} \ No newline at end of file diff --git a/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/templates/TemplateRuntime.java b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/templates/TemplateRuntime.java new file mode 100644 index 000000000000..4fec9fa4e30b --- /dev/null +++ b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/templates/TemplateRuntime.java @@ -0,0 +1,8 @@ +package org.mvel2.templates; + +import java.util.Map; + +public class TemplateRuntime { + public static Object eval(String template, Map vars) { return null; } + public static Object execute(CompiledTemplate compiled, Map vars) { return null; } +} \ No newline at end of file From df9d10f2ac2f9d42993d1cc13ed6b3fb5c37180a Mon Sep 17 00:00:00 2001 From: Artem Smotrakov Date: Fri, 1 May 2020 17:02:15 +0200 Subject: [PATCH 07/10] Java: Added MVELRuntime.execute() sink for MVEL injections --- .../Security/CWE/CWE-094/MvelInjectionLib.qll | 19 ++++ .../CWE/CWE-094/MvelInjection.expected | 94 ++++++++++--------- .../Security/CWE/CWE-094/MvelInjection.java | 13 +++ .../mvel2-2.4.7/org/mvel2/MVELRuntime.java | 8 ++ 4 files changed, 89 insertions(+), 45 deletions(-) create mode 100644 java/ql/test/stubs/mvel2-2.4.7/org/mvel2/MVELRuntime.java diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjectionLib.qll b/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjectionLib.qll index 4810aa8e5068..5bd6c122015b 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjectionLib.qll +++ b/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjectionLib.qll @@ -56,6 +56,11 @@ class MvelEvaluationSink extends DataFlow::ExprNode { ) and (ma = asExpr() or ma.getQualifier() = asExpr()) ) + or + exists(StaticMethodAccess ma, Method m | m = ma.getMethod() | + m instanceof MvelRuntimeEvaluationMethod and + ma.getArgument(1) = asExpr() + ) } } @@ -308,6 +313,16 @@ class MvelCompiledScriptEvaluationMethod extends Method { } } +/** + * Methods in `MVELRuntime` that evaluate a MVEL expression. + */ +class MvelRuntimeEvaluationMethod extends Method { + MvelRuntimeEvaluationMethod() { + getDeclaringType() instanceof MVELRuntime and + hasName("execute") + } +} + class MVEL extends RefType { MVEL() { hasQualifiedName("org.mvel2", "MVEL") } } @@ -351,3 +366,7 @@ class TemplateRuntime extends RefType { class TemplateCompiler extends RefType { TemplateCompiler() { hasQualifiedName("org.mvel2.templates", "TemplateCompiler") } } + +class MVELRuntime extends RefType { + MVELRuntime() { hasQualifiedName("org.mvel2", "MVELRuntime") } +} diff --git a/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.expected b/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.expected index c340cd5a19a8..c40da7f5f870 100644 --- a/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.expected +++ b/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.expected @@ -1,49 +1,53 @@ edges -| MvelInjection.java:24:27:24:49 | getInputStream(...) : InputStream | MvelInjection.java:28:17:28:21 | input | -| MvelInjection.java:33:27:33:49 | getInputStream(...) : InputStream | MvelInjection.java:38:30:38:39 | expression | -| MvelInjection.java:43:27:43:49 | getInputStream(...) : InputStream | MvelInjection.java:49:7:49:15 | statement | -| MvelInjection.java:43:27:43:49 | getInputStream(...) : InputStream | MvelInjection.java:50:7:50:15 | statement | -| MvelInjection.java:55:27:55:49 | getInputStream(...) : InputStream | MvelInjection.java:61:7:61:16 | expression | -| MvelInjection.java:66:27:66:49 | getInputStream(...) : InputStream | MvelInjection.java:71:7:71:16 | expression | -| MvelInjection.java:76:22:76:44 | getInputStream(...) : InputStream | MvelInjection.java:84:5:84:18 | compiledScript | -| MvelInjection.java:76:22:76:44 | getInputStream(...) : InputStream | MvelInjection.java:87:21:87:26 | script | -| MvelInjection.java:91:22:91:44 | getInputStream(...) : InputStream | MvelInjection.java:101:5:101:10 | script | -| MvelInjection.java:105:22:105:44 | getInputStream(...) : InputStream | MvelInjection.java:111:26:111:30 | input | -| MvelInjection.java:115:22:115:44 | getInputStream(...) : InputStream | MvelInjection.java:121:29:121:67 | compileTemplate(...) | -| MvelInjection.java:125:22:125:44 | getInputStream(...) : InputStream | MvelInjection.java:132:54:132:71 | compile(...) | +| MvelInjection.java:25:27:25:49 | getInputStream(...) : InputStream | MvelInjection.java:29:17:29:21 | input | +| MvelInjection.java:34:27:34:49 | getInputStream(...) : InputStream | MvelInjection.java:39:30:39:39 | expression | +| MvelInjection.java:44:27:44:49 | getInputStream(...) : InputStream | MvelInjection.java:50:7:50:15 | statement | +| MvelInjection.java:44:27:44:49 | getInputStream(...) : InputStream | MvelInjection.java:51:7:51:15 | statement | +| MvelInjection.java:56:27:56:49 | getInputStream(...) : InputStream | MvelInjection.java:62:7:62:16 | expression | +| MvelInjection.java:67:27:67:49 | getInputStream(...) : InputStream | MvelInjection.java:72:7:72:16 | expression | +| MvelInjection.java:77:22:77:44 | getInputStream(...) : InputStream | MvelInjection.java:85:5:85:18 | compiledScript | +| MvelInjection.java:77:22:77:44 | getInputStream(...) : InputStream | MvelInjection.java:88:21:88:26 | script | +| MvelInjection.java:92:22:92:44 | getInputStream(...) : InputStream | MvelInjection.java:102:5:102:10 | script | +| MvelInjection.java:106:22:106:44 | getInputStream(...) : InputStream | MvelInjection.java:112:26:112:30 | input | +| MvelInjection.java:116:22:116:44 | getInputStream(...) : InputStream | MvelInjection.java:122:29:122:67 | compileTemplate(...) | +| MvelInjection.java:126:22:126:44 | getInputStream(...) : InputStream | MvelInjection.java:133:54:133:71 | compile(...) | +| MvelInjection.java:137:22:137:44 | getInputStream(...) : InputStream | MvelInjection.java:145:32:145:41 | expression | nodes -| MvelInjection.java:24:27:24:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| MvelInjection.java:28:17:28:21 | input | semmle.label | input | -| MvelInjection.java:33:27:33:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| MvelInjection.java:38:30:38:39 | expression | semmle.label | expression | -| MvelInjection.java:43:27:43:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| MvelInjection.java:49:7:49:15 | statement | semmle.label | statement | +| MvelInjection.java:25:27:25:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:29:17:29:21 | input | semmle.label | input | +| MvelInjection.java:34:27:34:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:39:30:39:39 | expression | semmle.label | expression | +| MvelInjection.java:44:27:44:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | | MvelInjection.java:50:7:50:15 | statement | semmle.label | statement | -| MvelInjection.java:55:27:55:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| MvelInjection.java:61:7:61:16 | expression | semmle.label | expression | -| MvelInjection.java:66:27:66:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| MvelInjection.java:71:7:71:16 | expression | semmle.label | expression | -| MvelInjection.java:76:22:76:44 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| MvelInjection.java:84:5:84:18 | compiledScript | semmle.label | compiledScript | -| MvelInjection.java:87:21:87:26 | script | semmle.label | script | -| MvelInjection.java:91:22:91:44 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| MvelInjection.java:101:5:101:10 | script | semmle.label | script | -| MvelInjection.java:105:22:105:44 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| MvelInjection.java:111:26:111:30 | input | semmle.label | input | -| MvelInjection.java:115:22:115:44 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| MvelInjection.java:121:29:121:67 | compileTemplate(...) | semmle.label | compileTemplate(...) | -| MvelInjection.java:125:22:125:44 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| MvelInjection.java:132:54:132:71 | compile(...) | semmle.label | compile(...) | +| MvelInjection.java:51:7:51:15 | statement | semmle.label | statement | +| MvelInjection.java:56:27:56:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:62:7:62:16 | expression | semmle.label | expression | +| MvelInjection.java:67:27:67:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:72:7:72:16 | expression | semmle.label | expression | +| MvelInjection.java:77:22:77:44 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:85:5:85:18 | compiledScript | semmle.label | compiledScript | +| MvelInjection.java:88:21:88:26 | script | semmle.label | script | +| MvelInjection.java:92:22:92:44 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:102:5:102:10 | script | semmle.label | script | +| MvelInjection.java:106:22:106:44 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:112:26:112:30 | input | semmle.label | input | +| MvelInjection.java:116:22:116:44 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:122:29:122:67 | compileTemplate(...) | semmle.label | compileTemplate(...) | +| MvelInjection.java:126:22:126:44 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:133:54:133:71 | compile(...) | semmle.label | compile(...) | +| MvelInjection.java:137:22:137:44 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:145:32:145:41 | expression | semmle.label | expression | #select -| MvelInjection.java:28:17:28:21 | input | MvelInjection.java:24:27:24:49 | getInputStream(...) : InputStream | MvelInjection.java:28:17:28:21 | input | MVEL injection from $@. | MvelInjection.java:24:27:24:49 | getInputStream(...) | this user input | -| MvelInjection.java:38:30:38:39 | expression | MvelInjection.java:33:27:33:49 | getInputStream(...) : InputStream | MvelInjection.java:38:30:38:39 | expression | MVEL injection from $@. | MvelInjection.java:33:27:33:49 | getInputStream(...) | this user input | -| MvelInjection.java:49:7:49:15 | statement | MvelInjection.java:43:27:43:49 | getInputStream(...) : InputStream | MvelInjection.java:49:7:49:15 | statement | MVEL injection from $@. | MvelInjection.java:43:27:43:49 | getInputStream(...) | this user input | -| MvelInjection.java:50:7:50:15 | statement | MvelInjection.java:43:27:43:49 | getInputStream(...) : InputStream | MvelInjection.java:50:7:50:15 | statement | MVEL injection from $@. | MvelInjection.java:43:27:43:49 | getInputStream(...) | this user input | -| MvelInjection.java:61:7:61:16 | expression | MvelInjection.java:55:27:55:49 | getInputStream(...) : InputStream | MvelInjection.java:61:7:61:16 | expression | MVEL injection from $@. | MvelInjection.java:55:27:55:49 | getInputStream(...) | this user input | -| MvelInjection.java:71:7:71:16 | expression | MvelInjection.java:66:27:66:49 | getInputStream(...) : InputStream | MvelInjection.java:71:7:71:16 | expression | MVEL injection from $@. | MvelInjection.java:66:27:66:49 | getInputStream(...) | this user input | -| MvelInjection.java:84:5:84:18 | compiledScript | MvelInjection.java:76:22:76:44 | getInputStream(...) : InputStream | MvelInjection.java:84:5:84:18 | compiledScript | MVEL injection from $@. | MvelInjection.java:76:22:76:44 | getInputStream(...) | this user input | -| MvelInjection.java:87:21:87:26 | script | MvelInjection.java:76:22:76:44 | getInputStream(...) : InputStream | MvelInjection.java:87:21:87:26 | script | MVEL injection from $@. | MvelInjection.java:76:22:76:44 | getInputStream(...) | this user input | -| MvelInjection.java:101:5:101:10 | script | MvelInjection.java:91:22:91:44 | getInputStream(...) : InputStream | MvelInjection.java:101:5:101:10 | script | MVEL injection from $@. | MvelInjection.java:91:22:91:44 | getInputStream(...) | this user input | -| MvelInjection.java:111:26:111:30 | input | MvelInjection.java:105:22:105:44 | getInputStream(...) : InputStream | MvelInjection.java:111:26:111:30 | input | MVEL injection from $@. | MvelInjection.java:105:22:105:44 | getInputStream(...) | this user input | -| MvelInjection.java:121:29:121:67 | compileTemplate(...) | MvelInjection.java:115:22:115:44 | getInputStream(...) : InputStream | MvelInjection.java:121:29:121:67 | compileTemplate(...) | MVEL injection from $@. | MvelInjection.java:115:22:115:44 | getInputStream(...) | this user input | -| MvelInjection.java:132:54:132:71 | compile(...) | MvelInjection.java:125:22:125:44 | getInputStream(...) : InputStream | MvelInjection.java:132:54:132:71 | compile(...) | MVEL injection from $@. | MvelInjection.java:125:22:125:44 | getInputStream(...) | this user input | +| MvelInjection.java:29:17:29:21 | input | MvelInjection.java:25:27:25:49 | getInputStream(...) : InputStream | MvelInjection.java:29:17:29:21 | input | MVEL injection from $@. | MvelInjection.java:25:27:25:49 | getInputStream(...) | this user input | +| MvelInjection.java:39:30:39:39 | expression | MvelInjection.java:34:27:34:49 | getInputStream(...) : InputStream | MvelInjection.java:39:30:39:39 | expression | MVEL injection from $@. | MvelInjection.java:34:27:34:49 | getInputStream(...) | this user input | +| MvelInjection.java:50:7:50:15 | statement | MvelInjection.java:44:27:44:49 | getInputStream(...) : InputStream | MvelInjection.java:50:7:50:15 | statement | MVEL injection from $@. | MvelInjection.java:44:27:44:49 | getInputStream(...) | this user input | +| MvelInjection.java:51:7:51:15 | statement | MvelInjection.java:44:27:44:49 | getInputStream(...) : InputStream | MvelInjection.java:51:7:51:15 | statement | MVEL injection from $@. | MvelInjection.java:44:27:44:49 | getInputStream(...) | this user input | +| MvelInjection.java:62:7:62:16 | expression | MvelInjection.java:56:27:56:49 | getInputStream(...) : InputStream | MvelInjection.java:62:7:62:16 | expression | MVEL injection from $@. | MvelInjection.java:56:27:56:49 | getInputStream(...) | this user input | +| MvelInjection.java:72:7:72:16 | expression | MvelInjection.java:67:27:67:49 | getInputStream(...) : InputStream | MvelInjection.java:72:7:72:16 | expression | MVEL injection from $@. | MvelInjection.java:67:27:67:49 | getInputStream(...) | this user input | +| MvelInjection.java:85:5:85:18 | compiledScript | MvelInjection.java:77:22:77:44 | getInputStream(...) : InputStream | MvelInjection.java:85:5:85:18 | compiledScript | MVEL injection from $@. | MvelInjection.java:77:22:77:44 | getInputStream(...) | this user input | +| MvelInjection.java:88:21:88:26 | script | MvelInjection.java:77:22:77:44 | getInputStream(...) : InputStream | MvelInjection.java:88:21:88:26 | script | MVEL injection from $@. | MvelInjection.java:77:22:77:44 | getInputStream(...) | this user input | +| MvelInjection.java:102:5:102:10 | script | MvelInjection.java:92:22:92:44 | getInputStream(...) : InputStream | MvelInjection.java:102:5:102:10 | script | MVEL injection from $@. | MvelInjection.java:92:22:92:44 | getInputStream(...) | this user input | +| MvelInjection.java:112:26:112:30 | input | MvelInjection.java:106:22:106:44 | getInputStream(...) : InputStream | MvelInjection.java:112:26:112:30 | input | MVEL injection from $@. | MvelInjection.java:106:22:106:44 | getInputStream(...) | this user input | +| MvelInjection.java:122:29:122:67 | compileTemplate(...) | MvelInjection.java:116:22:116:44 | getInputStream(...) : InputStream | MvelInjection.java:122:29:122:67 | compileTemplate(...) | MVEL injection from $@. | MvelInjection.java:116:22:116:44 | getInputStream(...) | this user input | +| MvelInjection.java:133:54:133:71 | compile(...) | MvelInjection.java:126:22:126:44 | getInputStream(...) : InputStream | MvelInjection.java:133:54:133:71 | compile(...) | MVEL injection from $@. | MvelInjection.java:126:22:126:44 | getInputStream(...) | this user input | +| MvelInjection.java:145:32:145:41 | expression | MvelInjection.java:137:22:137:44 | getInputStream(...) : InputStream | MvelInjection.java:145:32:145:41 | expression | MVEL injection from $@. | MvelInjection.java:137:22:137:44 | getInputStream(...) | this user input | diff --git a/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.java b/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.java index b5ef1625502f..4454a782bf89 100644 --- a/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.java +++ b/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.java @@ -6,6 +6,7 @@ import javax.script.CompiledScript; import javax.script.SimpleScriptContext; import org.mvel2.MVEL; +import org.mvel2.MVELRuntime; import org.mvel2.ParserContext; import org.mvel2.compiler.CompiledAccExpression; import org.mvel2.compiler.CompiledExpression; @@ -131,4 +132,16 @@ public static void testTemplateRuntimeCompileAndExecute(Socket socket) throws Ex TemplateCompiler compiler = new TemplateCompiler(input); String output = (String) TemplateRuntime.execute(compiler.compile(), new HashMap()); } + + public static void testMvelRuntimeExecute(Socket socket) throws Exception { + InputStream in = socket.getInputStream(); + + byte[] bytes = new byte[1024]; + int n = in.read(bytes); + String input = new String(bytes, 0, n); + + ExpressionCompiler compiler = new ExpressionCompiler(input); + CompiledExpression expression = compiler.compile(); + MVELRuntime.execute(false, expression, new Object(), new ImmutableDefaultFactory()); + } } diff --git a/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/MVELRuntime.java b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/MVELRuntime.java new file mode 100644 index 000000000000..30fef49f0b88 --- /dev/null +++ b/java/ql/test/stubs/mvel2-2.4.7/org/mvel2/MVELRuntime.java @@ -0,0 +1,8 @@ +package org.mvel2; + +import org.mvel2.compiler.CompiledExpression; +import org.mvel2.integration.VariableResolverFactory; + +public class MVELRuntime { + public static Object execute(boolean debugger, CompiledExpression expression, Object ctx, VariableResolverFactory variableFactory) { return null; } +} \ No newline at end of file From 4a83fb8cc17ee4a5fc476e86ccc247443160ee75 Mon Sep 17 00:00:00 2001 From: Artem Smotrakov Date: Fri, 1 May 2020 17:13:11 +0200 Subject: [PATCH 08/10] Java: Simplified MvelInjection test --- .../CWE/CWE-094/MvelInjection.expected | 110 ++++++++++-------- .../Security/CWE/CWE-094/MvelInjection.java | 107 +++++------------ 2 files changed, 89 insertions(+), 128 deletions(-) diff --git a/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.expected b/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.expected index c40da7f5f870..b2325fa78a42 100644 --- a/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.expected +++ b/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.expected @@ -1,53 +1,63 @@ edges -| MvelInjection.java:25:27:25:49 | getInputStream(...) : InputStream | MvelInjection.java:29:17:29:21 | input | -| MvelInjection.java:34:27:34:49 | getInputStream(...) : InputStream | MvelInjection.java:39:30:39:39 | expression | -| MvelInjection.java:44:27:44:49 | getInputStream(...) : InputStream | MvelInjection.java:50:7:50:15 | statement | -| MvelInjection.java:44:27:44:49 | getInputStream(...) : InputStream | MvelInjection.java:51:7:51:15 | statement | -| MvelInjection.java:56:27:56:49 | getInputStream(...) : InputStream | MvelInjection.java:62:7:62:16 | expression | -| MvelInjection.java:67:27:67:49 | getInputStream(...) : InputStream | MvelInjection.java:72:7:72:16 | expression | -| MvelInjection.java:77:22:77:44 | getInputStream(...) : InputStream | MvelInjection.java:85:5:85:18 | compiledScript | -| MvelInjection.java:77:22:77:44 | getInputStream(...) : InputStream | MvelInjection.java:88:21:88:26 | script | -| MvelInjection.java:92:22:92:44 | getInputStream(...) : InputStream | MvelInjection.java:102:5:102:10 | script | -| MvelInjection.java:106:22:106:44 | getInputStream(...) : InputStream | MvelInjection.java:112:26:112:30 | input | -| MvelInjection.java:116:22:116:44 | getInputStream(...) : InputStream | MvelInjection.java:122:29:122:67 | compileTemplate(...) | -| MvelInjection.java:126:22:126:44 | getInputStream(...) : InputStream | MvelInjection.java:133:54:133:71 | compile(...) | -| MvelInjection.java:137:22:137:44 | getInputStream(...) : InputStream | MvelInjection.java:145:32:145:41 | expression | +| MvelInjection.java:29:54:29:65 | read(...) : String | MvelInjection.java:30:28:30:37 | expression | +| MvelInjection.java:34:58:34:69 | read(...) : String | MvelInjection.java:36:5:36:13 | statement | +| MvelInjection.java:34:58:34:69 | read(...) : String | MvelInjection.java:37:5:37:13 | statement | +| MvelInjection.java:41:58:41:69 | read(...) : String | MvelInjection.java:43:5:43:14 | expression | +| MvelInjection.java:48:7:48:18 | read(...) : String | MvelInjection.java:49:5:49:14 | expression | +| MvelInjection.java:53:20:53:31 | read(...) : String | MvelInjection.java:57:5:57:18 | compiledScript | +| MvelInjection.java:53:20:53:31 | read(...) : String | MvelInjection.java:60:21:60:26 | script | +| MvelInjection.java:65:58:65:69 | read(...) : String | MvelInjection.java:68:5:68:10 | script | +| MvelInjection.java:77:40:77:51 | read(...) : String | MvelInjection.java:77:7:77:52 | compileTemplate(...) | +| MvelInjection.java:81:54:81:65 | read(...) : String | MvelInjection.java:82:29:82:46 | compile(...) | +| MvelInjection.java:86:58:86:69 | read(...) : String | MvelInjection.java:88:32:88:41 | expression | +| MvelInjection.java:92:27:92:49 | getInputStream(...) : InputStream | MvelInjection.java:95:14:95:36 | new String(...) : String | +| MvelInjection.java:95:14:95:36 | new String(...) : String | MvelInjection.java:25:15:25:26 | read(...) | +| MvelInjection.java:95:14:95:36 | new String(...) : String | MvelInjection.java:29:54:29:65 | read(...) : String | +| MvelInjection.java:95:14:95:36 | new String(...) : String | MvelInjection.java:34:58:34:69 | read(...) : String | +| MvelInjection.java:95:14:95:36 | new String(...) : String | MvelInjection.java:41:58:41:69 | read(...) : String | +| MvelInjection.java:95:14:95:36 | new String(...) : String | MvelInjection.java:48:7:48:18 | read(...) : String | +| MvelInjection.java:95:14:95:36 | new String(...) : String | MvelInjection.java:53:20:53:31 | read(...) : String | +| MvelInjection.java:95:14:95:36 | new String(...) : String | MvelInjection.java:65:58:65:69 | read(...) : String | +| MvelInjection.java:95:14:95:36 | new String(...) : String | MvelInjection.java:72:26:72:37 | read(...) | +| MvelInjection.java:95:14:95:36 | new String(...) : String | MvelInjection.java:77:40:77:51 | read(...) : String | +| MvelInjection.java:95:14:95:36 | new String(...) : String | MvelInjection.java:81:54:81:65 | read(...) : String | +| MvelInjection.java:95:14:95:36 | new String(...) : String | MvelInjection.java:86:58:86:69 | read(...) : String | nodes -| MvelInjection.java:25:27:25:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| MvelInjection.java:29:17:29:21 | input | semmle.label | input | -| MvelInjection.java:34:27:34:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| MvelInjection.java:39:30:39:39 | expression | semmle.label | expression | -| MvelInjection.java:44:27:44:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| MvelInjection.java:50:7:50:15 | statement | semmle.label | statement | -| MvelInjection.java:51:7:51:15 | statement | semmle.label | statement | -| MvelInjection.java:56:27:56:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| MvelInjection.java:62:7:62:16 | expression | semmle.label | expression | -| MvelInjection.java:67:27:67:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| MvelInjection.java:72:7:72:16 | expression | semmle.label | expression | -| MvelInjection.java:77:22:77:44 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| MvelInjection.java:85:5:85:18 | compiledScript | semmle.label | compiledScript | -| MvelInjection.java:88:21:88:26 | script | semmle.label | script | -| MvelInjection.java:92:22:92:44 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| MvelInjection.java:102:5:102:10 | script | semmle.label | script | -| MvelInjection.java:106:22:106:44 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| MvelInjection.java:112:26:112:30 | input | semmle.label | input | -| MvelInjection.java:116:22:116:44 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| MvelInjection.java:122:29:122:67 | compileTemplate(...) | semmle.label | compileTemplate(...) | -| MvelInjection.java:126:22:126:44 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| MvelInjection.java:133:54:133:71 | compile(...) | semmle.label | compile(...) | -| MvelInjection.java:137:22:137:44 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | -| MvelInjection.java:145:32:145:41 | expression | semmle.label | expression | +| MvelInjection.java:25:15:25:26 | read(...) | semmle.label | read(...) | +| MvelInjection.java:29:54:29:65 | read(...) : String | semmle.label | read(...) : String | +| MvelInjection.java:30:28:30:37 | expression | semmle.label | expression | +| MvelInjection.java:34:58:34:69 | read(...) : String | semmle.label | read(...) : String | +| MvelInjection.java:36:5:36:13 | statement | semmle.label | statement | +| MvelInjection.java:37:5:37:13 | statement | semmle.label | statement | +| MvelInjection.java:41:58:41:69 | read(...) : String | semmle.label | read(...) : String | +| MvelInjection.java:43:5:43:14 | expression | semmle.label | expression | +| MvelInjection.java:48:7:48:18 | read(...) : String | semmle.label | read(...) : String | +| MvelInjection.java:49:5:49:14 | expression | semmle.label | expression | +| MvelInjection.java:53:20:53:31 | read(...) : String | semmle.label | read(...) : String | +| MvelInjection.java:57:5:57:18 | compiledScript | semmle.label | compiledScript | +| MvelInjection.java:60:21:60:26 | script | semmle.label | script | +| MvelInjection.java:65:58:65:69 | read(...) : String | semmle.label | read(...) : String | +| MvelInjection.java:68:5:68:10 | script | semmle.label | script | +| MvelInjection.java:72:26:72:37 | read(...) | semmle.label | read(...) | +| MvelInjection.java:77:7:77:52 | compileTemplate(...) | semmle.label | compileTemplate(...) | +| MvelInjection.java:77:40:77:51 | read(...) : String | semmle.label | read(...) : String | +| MvelInjection.java:81:54:81:65 | read(...) : String | semmle.label | read(...) : String | +| MvelInjection.java:82:29:82:46 | compile(...) | semmle.label | compile(...) | +| MvelInjection.java:86:58:86:69 | read(...) : String | semmle.label | read(...) : String | +| MvelInjection.java:88:32:88:41 | expression | semmle.label | expression | +| MvelInjection.java:92:27:92:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream | +| MvelInjection.java:95:14:95:36 | new String(...) : String | semmle.label | new String(...) : String | #select -| MvelInjection.java:29:17:29:21 | input | MvelInjection.java:25:27:25:49 | getInputStream(...) : InputStream | MvelInjection.java:29:17:29:21 | input | MVEL injection from $@. | MvelInjection.java:25:27:25:49 | getInputStream(...) | this user input | -| MvelInjection.java:39:30:39:39 | expression | MvelInjection.java:34:27:34:49 | getInputStream(...) : InputStream | MvelInjection.java:39:30:39:39 | expression | MVEL injection from $@. | MvelInjection.java:34:27:34:49 | getInputStream(...) | this user input | -| MvelInjection.java:50:7:50:15 | statement | MvelInjection.java:44:27:44:49 | getInputStream(...) : InputStream | MvelInjection.java:50:7:50:15 | statement | MVEL injection from $@. | MvelInjection.java:44:27:44:49 | getInputStream(...) | this user input | -| MvelInjection.java:51:7:51:15 | statement | MvelInjection.java:44:27:44:49 | getInputStream(...) : InputStream | MvelInjection.java:51:7:51:15 | statement | MVEL injection from $@. | MvelInjection.java:44:27:44:49 | getInputStream(...) | this user input | -| MvelInjection.java:62:7:62:16 | expression | MvelInjection.java:56:27:56:49 | getInputStream(...) : InputStream | MvelInjection.java:62:7:62:16 | expression | MVEL injection from $@. | MvelInjection.java:56:27:56:49 | getInputStream(...) | this user input | -| MvelInjection.java:72:7:72:16 | expression | MvelInjection.java:67:27:67:49 | getInputStream(...) : InputStream | MvelInjection.java:72:7:72:16 | expression | MVEL injection from $@. | MvelInjection.java:67:27:67:49 | getInputStream(...) | this user input | -| MvelInjection.java:85:5:85:18 | compiledScript | MvelInjection.java:77:22:77:44 | getInputStream(...) : InputStream | MvelInjection.java:85:5:85:18 | compiledScript | MVEL injection from $@. | MvelInjection.java:77:22:77:44 | getInputStream(...) | this user input | -| MvelInjection.java:88:21:88:26 | script | MvelInjection.java:77:22:77:44 | getInputStream(...) : InputStream | MvelInjection.java:88:21:88:26 | script | MVEL injection from $@. | MvelInjection.java:77:22:77:44 | getInputStream(...) | this user input | -| MvelInjection.java:102:5:102:10 | script | MvelInjection.java:92:22:92:44 | getInputStream(...) : InputStream | MvelInjection.java:102:5:102:10 | script | MVEL injection from $@. | MvelInjection.java:92:22:92:44 | getInputStream(...) | this user input | -| MvelInjection.java:112:26:112:30 | input | MvelInjection.java:106:22:106:44 | getInputStream(...) : InputStream | MvelInjection.java:112:26:112:30 | input | MVEL injection from $@. | MvelInjection.java:106:22:106:44 | getInputStream(...) | this user input | -| MvelInjection.java:122:29:122:67 | compileTemplate(...) | MvelInjection.java:116:22:116:44 | getInputStream(...) : InputStream | MvelInjection.java:122:29:122:67 | compileTemplate(...) | MVEL injection from $@. | MvelInjection.java:116:22:116:44 | getInputStream(...) | this user input | -| MvelInjection.java:133:54:133:71 | compile(...) | MvelInjection.java:126:22:126:44 | getInputStream(...) : InputStream | MvelInjection.java:133:54:133:71 | compile(...) | MVEL injection from $@. | MvelInjection.java:126:22:126:44 | getInputStream(...) | this user input | -| MvelInjection.java:145:32:145:41 | expression | MvelInjection.java:137:22:137:44 | getInputStream(...) : InputStream | MvelInjection.java:145:32:145:41 | expression | MVEL injection from $@. | MvelInjection.java:137:22:137:44 | getInputStream(...) | this user input | +| MvelInjection.java:25:15:25:26 | read(...) | MvelInjection.java:92:27:92:49 | getInputStream(...) : InputStream | MvelInjection.java:25:15:25:26 | read(...) | MVEL injection from $@. | MvelInjection.java:92:27:92:49 | getInputStream(...) | this user input | +| MvelInjection.java:30:28:30:37 | expression | MvelInjection.java:92:27:92:49 | getInputStream(...) : InputStream | MvelInjection.java:30:28:30:37 | expression | MVEL injection from $@. | MvelInjection.java:92:27:92:49 | getInputStream(...) | this user input | +| MvelInjection.java:36:5:36:13 | statement | MvelInjection.java:92:27:92:49 | getInputStream(...) : InputStream | MvelInjection.java:36:5:36:13 | statement | MVEL injection from $@. | MvelInjection.java:92:27:92:49 | getInputStream(...) | this user input | +| MvelInjection.java:37:5:37:13 | statement | MvelInjection.java:92:27:92:49 | getInputStream(...) : InputStream | MvelInjection.java:37:5:37:13 | statement | MVEL injection from $@. | MvelInjection.java:92:27:92:49 | getInputStream(...) | this user input | +| MvelInjection.java:43:5:43:14 | expression | MvelInjection.java:92:27:92:49 | getInputStream(...) : InputStream | MvelInjection.java:43:5:43:14 | expression | MVEL injection from $@. | MvelInjection.java:92:27:92:49 | getInputStream(...) | this user input | +| MvelInjection.java:49:5:49:14 | expression | MvelInjection.java:92:27:92:49 | getInputStream(...) : InputStream | MvelInjection.java:49:5:49:14 | expression | MVEL injection from $@. | MvelInjection.java:92:27:92:49 | getInputStream(...) | this user input | +| MvelInjection.java:57:5:57:18 | compiledScript | MvelInjection.java:92:27:92:49 | getInputStream(...) : InputStream | MvelInjection.java:57:5:57:18 | compiledScript | MVEL injection from $@. | MvelInjection.java:92:27:92:49 | getInputStream(...) | this user input | +| MvelInjection.java:60:21:60:26 | script | MvelInjection.java:92:27:92:49 | getInputStream(...) : InputStream | MvelInjection.java:60:21:60:26 | script | MVEL injection from $@. | MvelInjection.java:92:27:92:49 | getInputStream(...) | this user input | +| MvelInjection.java:68:5:68:10 | script | MvelInjection.java:92:27:92:49 | getInputStream(...) : InputStream | MvelInjection.java:68:5:68:10 | script | MVEL injection from $@. | MvelInjection.java:92:27:92:49 | getInputStream(...) | this user input | +| MvelInjection.java:72:26:72:37 | read(...) | MvelInjection.java:92:27:92:49 | getInputStream(...) : InputStream | MvelInjection.java:72:26:72:37 | read(...) | MVEL injection from $@. | MvelInjection.java:92:27:92:49 | getInputStream(...) | this user input | +| MvelInjection.java:77:7:77:52 | compileTemplate(...) | MvelInjection.java:92:27:92:49 | getInputStream(...) : InputStream | MvelInjection.java:77:7:77:52 | compileTemplate(...) | MVEL injection from $@. | MvelInjection.java:92:27:92:49 | getInputStream(...) | this user input | +| MvelInjection.java:82:29:82:46 | compile(...) | MvelInjection.java:92:27:92:49 | getInputStream(...) : InputStream | MvelInjection.java:82:29:82:46 | compile(...) | MVEL injection from $@. | MvelInjection.java:92:27:92:49 | getInputStream(...) | this user input | +| MvelInjection.java:88:32:88:41 | expression | MvelInjection.java:92:27:92:49 | getInputStream(...) : InputStream | MvelInjection.java:88:32:88:41 | expression | MVEL injection from $@. | MvelInjection.java:92:27:92:49 | getInputStream(...) | this user input | diff --git a/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.java b/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.java index 4454a782bf89..88f9b861caee 100644 --- a/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.java +++ b/java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.java @@ -22,63 +22,35 @@ public class MvelInjection { public static void testWithMvelEval(Socket socket) throws IOException { - try (InputStream in = socket.getInputStream()) { - byte[] bytes = new byte[1024]; - int n = in.read(bytes); - String input = new String(bytes, 0, n); - MVEL.eval(input); - } + MVEL.eval(read(socket)); } public static void testWithMvelCompileAndExecute(Socket socket) throws IOException { - try (InputStream in = socket.getInputStream()) { - byte[] bytes = new byte[1024]; - int n = in.read(bytes); - String input = new String(bytes, 0, n); - Serializable expression = MVEL.compileExpression(input); - MVEL.executeExpression(expression); - } + Serializable expression = MVEL.compileExpression(read(socket)); + MVEL.executeExpression(expression); } public static void testWithExpressionCompiler(Socket socket) throws IOException { - try (InputStream in = socket.getInputStream()) { - byte[] bytes = new byte[1024]; - int n = in.read(bytes); - String input = new String(bytes, 0, n); - ExpressionCompiler compiler = new ExpressionCompiler(input); - ExecutableStatement statement = compiler.compile(); - statement.getValue(new Object(), new ImmutableDefaultFactory()); - statement.getValue(new Object(), new Object(), new ImmutableDefaultFactory()); - } + ExpressionCompiler compiler = new ExpressionCompiler(read(socket)); + ExecutableStatement statement = compiler.compile(); + statement.getValue(new Object(), new ImmutableDefaultFactory()); + statement.getValue(new Object(), new Object(), new ImmutableDefaultFactory()); } public static void testWithCompiledExpressionGetDirectValue(Socket socket) throws IOException { - try (InputStream in = socket.getInputStream()) { - byte[] bytes = new byte[1024]; - int n = in.read(bytes); - String input = new String(bytes, 0, n); - ExpressionCompiler compiler = new ExpressionCompiler(input); - CompiledExpression expression = compiler.compile(); - expression.getDirectValue(new Object(), new ImmutableDefaultFactory()); - } + ExpressionCompiler compiler = new ExpressionCompiler(read(socket)); + CompiledExpression expression = compiler.compile(); + expression.getDirectValue(new Object(), new ImmutableDefaultFactory()); } public static void testCompiledAccExpressionGetValue(Socket socket) throws IOException { - try (InputStream in = socket.getInputStream()) { - byte[] bytes = new byte[1024]; - int n = in.read(bytes); - String input = new String(bytes, 0, n); - CompiledAccExpression expression = new CompiledAccExpression(input.toCharArray(), Object.class, new ParserContext()); - expression.getValue(new Object(), new ImmutableDefaultFactory()); - } + CompiledAccExpression expression = new CompiledAccExpression( + read(socket).toCharArray(), Object.class, new ParserContext()); + expression.getValue(new Object(), new ImmutableDefaultFactory()); } public static void testMvelScriptEngineCompileAndEvaluate(Socket socket) throws Exception { - InputStream in = socket.getInputStream(); - - byte[] bytes = new byte[1024]; - int n = in.read(bytes); - String input = new String(bytes, 0, n); + String input = read(socket); MvelScriptEngine engine = new MvelScriptEngine(); CompiledScript compiledScript = engine.compile(input); @@ -89,59 +61,38 @@ public static void testMvelScriptEngineCompileAndEvaluate(Socket socket) throws } public static void testMvelCompiledScriptCompileAndEvaluate(Socket socket) throws Exception { - InputStream in = socket.getInputStream(); - - byte[] bytes = new byte[1024]; - int n = in.read(bytes); - String input = new String(bytes, 0, n); - MvelScriptEngine engine = new MvelScriptEngine(); - ExpressionCompiler compiler = new ExpressionCompiler(input); + ExpressionCompiler compiler = new ExpressionCompiler(read(socket)); ExecutableStatement statement = compiler.compile(); MvelCompiledScript script = new MvelCompiledScript(engine, statement); script.eval(new SimpleScriptContext()); } public static void testTemplateRuntimeEval(Socket socket) throws Exception { - InputStream in = socket.getInputStream(); - - byte[] bytes = new byte[1024]; - int n = in.read(bytes); - String input = new String(bytes, 0, n); - - TemplateRuntime.eval(input, new HashMap()); + TemplateRuntime.eval(read(socket), new HashMap()); } public static void testTemplateRuntimeCompileTemplateAndExecute(Socket socket) throws Exception { - InputStream in = socket.getInputStream(); - - byte[] bytes = new byte[1024]; - int n = in.read(bytes); - String input = new String(bytes, 0, n); - - TemplateRuntime.execute(TemplateCompiler.compileTemplate(input), new HashMap()); + TemplateRuntime.execute( + TemplateCompiler.compileTemplate(read(socket)), new HashMap()); } public static void testTemplateRuntimeCompileAndExecute(Socket socket) throws Exception { - InputStream in = socket.getInputStream(); - - byte[] bytes = new byte[1024]; - int n = in.read(bytes); - String input = new String(bytes, 0, n); - - TemplateCompiler compiler = new TemplateCompiler(input); - String output = (String) TemplateRuntime.execute(compiler.compile(), new HashMap()); + TemplateCompiler compiler = new TemplateCompiler(read(socket)); + TemplateRuntime.execute(compiler.compile(), new HashMap()); } public static void testMvelRuntimeExecute(Socket socket) throws Exception { - InputStream in = socket.getInputStream(); - - byte[] bytes = new byte[1024]; - int n = in.read(bytes); - String input = new String(bytes, 0, n); - - ExpressionCompiler compiler = new ExpressionCompiler(input); + ExpressionCompiler compiler = new ExpressionCompiler(read(socket)); CompiledExpression expression = compiler.compile(); MVELRuntime.execute(false, expression, new Object(), new ImmutableDefaultFactory()); } + + public static String read(Socket socket) throws IOException { + try (InputStream is = socket.getInputStream()) { + byte[] bytes = new byte[1024]; + int n = is.read(bytes); + return new String(bytes, 0, n); + } + } } From 2842aeee72cf79d8f7c66d56017155523502b2a1 Mon Sep 17 00:00:00 2001 From: Artem Smotrakov Date: Sun, 31 May 2020 21:08:07 +0300 Subject: [PATCH 09/10] Java: Simplified MvelInjectionLib --- .../Security/CWE/CWE-094/MvelInjectionLib.qll | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjectionLib.qll b/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjectionLib.qll index 5bd6c122015b..791ee0b32eb9 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjectionLib.qll +++ b/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjectionLib.qll @@ -1,7 +1,6 @@ import java import semmle.code.java.dataflow.FlowSources import semmle.code.java.dataflow.TaintTracking -import DataFlow::PathGraph /** * A taint-tracking configuration for unsafe user input @@ -54,7 +53,7 @@ class MvelEvaluationSink extends DataFlow::ExprNode { m instanceof CompiledScriptEvaluationMethod or m instanceof MvelCompiledScriptEvaluationMethod ) and - (ma = asExpr() or ma.getQualifier() = asExpr()) + ma.getQualifier() = asExpr() ) or exists(StaticMethodAccess ma, Method m | m = ma.getMethod() | @@ -73,7 +72,7 @@ predicate expressionCompilationStep(DataFlow::Node node1, DataFlow::Node node2) m.getDeclaringType() instanceof MVEL and m.hasName("compileExpression") and ma.getAnArgument() = node1.asExpr() and - (node2.asExpr() = ma.getQualifier() or node2.asExpr() = ma) + node2.asExpr() = ma ) } @@ -84,7 +83,7 @@ predicate expressionCompilationStep(DataFlow::Node node1, DataFlow::Node node2) predicate createExpressionCompilerStep(DataFlow::Node node1, DataFlow::Node node2) { exists(ConstructorCall cc | cc.getConstructedType() instanceof ExpressionCompiler and - (cc = node2.asExpr() or cc.getQualifier() = node2.asExpr()) and + cc = node2.asExpr() and cc.getArgument(0) = node1.asExpr() ) } @@ -96,7 +95,7 @@ predicate createExpressionCompilerStep(DataFlow::Node node1, DataFlow::Node node predicate createCompiledAccExpressionStep(DataFlow::Node node1, DataFlow::Node node2) { exists(ConstructorCall cc | cc.getConstructedType() instanceof CompiledAccExpression and - (cc = node2.asExpr() or cc.getQualifier() = node2.asExpr()) and + cc = node2.asExpr() and cc.getArgument(0) = node1.asExpr() ) } @@ -125,7 +124,7 @@ predicate expressionCompilerCompileStep(DataFlow::Node node1, DataFlow::Node nod predicate scriptCompileStep(DataFlow::Node node1, DataFlow::Node node2) { exists(MethodAccess ma, Method m | ma.getMethod() = m | m instanceof MvelScriptEngineCompilationMethod and - (ma = node2.asExpr() or ma.getQualifier() = node2.asExpr()) and + ma = node2.asExpr() and ma.getArgument(0) = node1.asExpr() ) } @@ -137,7 +136,7 @@ predicate scriptCompileStep(DataFlow::Node node1, DataFlow::Node node2) { predicate createMvelCompiledScriptStep(DataFlow::Node node1, DataFlow::Node node2) { exists(ConstructorCall cc | cc.getConstructedType() instanceof MvelCompiledScript and - (cc = node2.asExpr() or cc.getQualifier() = node2.asExpr()) and + cc = node2.asExpr() and cc.getArgument(1) = node1.asExpr() ) } @@ -149,7 +148,7 @@ predicate createMvelCompiledScriptStep(DataFlow::Node node1, DataFlow::Node node predicate createTemplateCompilerStep(DataFlow::Node node1, DataFlow::Node node2) { exists(ConstructorCall cc | cc.getConstructedType() instanceof TemplateCompiler and - (cc = node2.asExpr() or cc.getQualifier() = node2.asExpr()) and + cc = node2.asExpr() and cc.getArgument(0) = node1.asExpr() ) } @@ -167,7 +166,7 @@ predicate templateCompileStep(DataFlow::Node node1, DataFlow::Node node2) { or exists(StaticMethodAccess ma, Method m | ma.getMethod() = m | m instanceof TemplateCompilerCompileTemplateMethod and - (ma = node2.asExpr() or ma.getQualifier() = node2.asExpr()) and + ma = node2.asExpr() and ma.getArgument(0) = node1.asExpr() ) } From b7c3dd666cea52c2b32b66fe38165d74ec0a18e9 Mon Sep 17 00:00:00 2001 From: Artem Smotrakov Date: Fri, 5 Jun 2020 17:22:45 +0300 Subject: [PATCH 10/10] Java: Clean up MVEL injection query --- .../src/experimental/Security/CWE/CWE-094/MvelInjection.qhelp | 1 + .../experimental/Security/CWE/CWE-094/MvelInjectionLib.qll | 4 ---- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjection.qhelp b/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjection.qhelp index 1055847020f6..d68d298b5f5a 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjection.qhelp +++ b/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjection.qhelp @@ -23,6 +23,7 @@ The following example uses untrusted data to build a MVEL expression and then runs it in the default powerfull context.

    +
  • diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjectionLib.qll b/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjectionLib.qll index 791ee0b32eb9..a6cf891330f0 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjectionLib.qll +++ b/java/ql/src/experimental/Security/CWE/CWE-094/MvelInjectionLib.qll @@ -100,10 +100,6 @@ predicate createCompiledAccExpressionStep(DataFlow::Node node1, DataFlow::Node n ) } -predicate test() { - exists(ConstructorCall cc | cc.getConstructedType() instanceof CompiledAccExpression) -} - /** * Holds if `node1` to `node2` is a dataflow step that compiles a MVEL expression * by calling `ExpressionCompiler.compile()`.