Skip to content

Commit fa717b2

Browse files
Java: Added template sinks for MVEL injections
1 parent 8fd7265 commit fa717b2

File tree

6 files changed

+177
-39
lines changed

6 files changed

+177
-39
lines changed

java/ql/src/experimental/Security/CWE/CWE-094/MvelInjectionLib.qll

Lines changed: 78 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@ class MvelInjectionConfig extends TaintTracking::Configuration {
2020
expressionCompilerCompileStep(node1, node2) or
2121
createCompiledAccExpressionStep(node1, node2) or
2222
scriptCompileStep(node1, node2) or
23-
createMvelCompiledScriptStep(node1, node2)
23+
createMvelCompiledScriptStep(node1, node2) or
24+
templateCompileStep(node1, node2) or
25+
createTemplateCompilerStep(node1, node2)
2426
}
2527
}
2628

@@ -31,7 +33,10 @@ class MvelInjectionConfig extends TaintTracking::Configuration {
3133
class MvelEvaluationSink extends DataFlow::ExprNode {
3234
MvelEvaluationSink() {
3335
exists(StaticMethodAccess ma, Method m | m = ma.getMethod() |
34-
m instanceof MvelEvalMethod and
36+
(
37+
m instanceof MvelEvalMethod or
38+
m instanceof TemplateRuntimeEvaluationMethod
39+
) and
3540
ma.getArgument(0) = asExpr()
3641
)
3742
or
@@ -114,7 +119,7 @@ predicate expressionCompilerCompileStep(DataFlow::Node node1, DataFlow::Node nod
114119
*/
115120
predicate scriptCompileStep(DataFlow::Node node1, DataFlow::Node node2) {
116121
exists(MethodAccess ma, Method m | ma.getMethod() = m |
117-
m instanceof MvelScriptEngineCompilationnMethod and
122+
m instanceof MvelScriptEngineCompilationMethod and
118123
(ma = node2.asExpr() or ma.getQualifier() = node2.asExpr()) and
119124
ma.getArgument(0) = node1.asExpr()
120125
)
@@ -132,6 +137,36 @@ predicate createMvelCompiledScriptStep(DataFlow::Node node1, DataFlow::Node node
132137
)
133138
}
134139

140+
/**
141+
* Holds if `node1` to `node2` is a dataflow step creates `TemplateCompiler`,
142+
* i.e. `new TemplateCompiler(tainted)`.
143+
*/
144+
predicate createTemplateCompilerStep(DataFlow::Node node1, DataFlow::Node node2) {
145+
exists(ConstructorCall cc |
146+
cc.getConstructedType() instanceof TemplateCompiler and
147+
(cc = node2.asExpr() or cc.getQualifier() = node2.asExpr()) and
148+
cc.getArgument(0) = node1.asExpr()
149+
)
150+
}
151+
152+
/**
153+
* Holds if `node1` to `node2` is a dataflow step that compiles a script via `TemplateCompiler`,
154+
* i.e. `compiler.compile()` or `TemplateCompiler.compileTemplate(tainted)`.
155+
*/
156+
predicate templateCompileStep(DataFlow::Node node1, DataFlow::Node node2) {
157+
exists(MethodAccess ma, Method m | ma.getMethod() = m |
158+
m instanceof TemplateCompilerCompileMethod and
159+
ma.getQualifier() = node1.asExpr() and
160+
ma = node2.asExpr()
161+
)
162+
or
163+
exists(StaticMethodAccess ma, Method m | ma.getMethod() = m |
164+
m instanceof TemplateCompilerCompileTemplateMethod and
165+
(ma = node2.asExpr() or ma.getQualifier() = node2.asExpr()) and
166+
ma.getArgument(0) = node1.asExpr()
167+
)
168+
}
169+
135170
/**
136171
* Methods in the MVEL class that evaluate a MVEL expression.
137172
*/
@@ -216,8 +251,8 @@ class MvelScriptEngineEvaluationMethod extends Method {
216251
/**
217252
* Methods in `MvelScriptEngine` that compile a MVEL expression.
218253
*/
219-
class MvelScriptEngineCompilationnMethod extends Method {
220-
MvelScriptEngineCompilationnMethod() {
254+
class MvelScriptEngineCompilationMethod extends Method {
255+
MvelScriptEngineCompilationMethod() {
221256
getDeclaringType() instanceof MvelScriptEngine and
222257
(hasName("compile") or hasName("compiledScript"))
223258
}
@@ -233,6 +268,36 @@ class CompiledScriptEvaluationMethod extends Method {
233268
}
234269
}
235270

271+
/**
272+
* Methods in `TemplateRuntime` that evaluate a MVEL template.
273+
*/
274+
class TemplateRuntimeEvaluationMethod extends Method {
275+
TemplateRuntimeEvaluationMethod() {
276+
getDeclaringType() instanceof TemplateRuntime and
277+
(hasName("eval") or hasName("execute"))
278+
}
279+
}
280+
281+
/**
282+
* `TemplateCompiler.compile()` method compiles a MVEL template.
283+
*/
284+
class TemplateCompilerCompileMethod extends Method {
285+
TemplateCompilerCompileMethod() {
286+
getDeclaringType() instanceof TemplateCompiler and
287+
hasName("compile")
288+
}
289+
}
290+
291+
/**
292+
* `TemplateCompiler.compileTemplate(tainted)` static method compiles a MVEL template.
293+
*/
294+
class TemplateCompilerCompileTemplateMethod extends Method {
295+
TemplateCompilerCompileTemplateMethod() {
296+
getDeclaringType() instanceof TemplateCompiler and
297+
hasName("compileTemplate")
298+
}
299+
}
300+
236301
/**
237302
* Methods in `MvelCompiledScript` that evaluate a MVEL expression.
238303
*/
@@ -278,3 +343,11 @@ class MvelScriptEngine extends RefType {
278343
class MvelCompiledScript extends RefType {
279344
MvelCompiledScript() { hasQualifiedName("org.mvel2.jsr223", "MvelCompiledScript") }
280345
}
346+
347+
class TemplateRuntime extends RefType {
348+
TemplateRuntime() { hasQualifiedName("org.mvel2.templates", "TemplateRuntime") }
349+
}
350+
351+
class TemplateCompiler extends RefType {
352+
TemplateCompiler() { hasQualifiedName("org.mvel2.templates", "TemplateCompiler") }
353+
}
Lines changed: 46 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,49 @@
11
edges
2-
| MvelInjection.java:20:27:20:49 | getInputStream(...) : InputStream | MvelInjection.java:24:17:24:21 | input |
3-
| MvelInjection.java:29:27:29:49 | getInputStream(...) : InputStream | MvelInjection.java:34:30:34:39 | expression |
4-
| MvelInjection.java:39:27:39:49 | getInputStream(...) : InputStream | MvelInjection.java:45:7:45:15 | statement |
5-
| MvelInjection.java:39:27:39:49 | getInputStream(...) : InputStream | MvelInjection.java:46:7:46:15 | statement |
6-
| MvelInjection.java:51:27:51:49 | getInputStream(...) : InputStream | MvelInjection.java:57:7:57:16 | expression |
7-
| MvelInjection.java:62:27:62:49 | getInputStream(...) : InputStream | MvelInjection.java:67:7:67:16 | expression |
8-
| MvelInjection.java:72:22:72:44 | getInputStream(...) : InputStream | MvelInjection.java:80:5:80:18 | compiledScript |
9-
| MvelInjection.java:72:22:72:44 | getInputStream(...) : InputStream | MvelInjection.java:83:21:83:26 | script |
10-
| MvelInjection.java:87:22:87:44 | getInputStream(...) : InputStream | MvelInjection.java:97:5:97:10 | script |
2+
| MvelInjection.java:24:27:24:49 | getInputStream(...) : InputStream | MvelInjection.java:28:17:28:21 | input |
3+
| MvelInjection.java:33:27:33:49 | getInputStream(...) : InputStream | MvelInjection.java:38:30:38:39 | expression |
4+
| MvelInjection.java:43:27:43:49 | getInputStream(...) : InputStream | MvelInjection.java:49:7:49:15 | statement |
5+
| MvelInjection.java:43:27:43:49 | getInputStream(...) : InputStream | MvelInjection.java:50:7:50:15 | statement |
6+
| MvelInjection.java:55:27:55:49 | getInputStream(...) : InputStream | MvelInjection.java:61:7:61:16 | expression |
7+
| MvelInjection.java:66:27:66:49 | getInputStream(...) : InputStream | MvelInjection.java:71:7:71:16 | expression |
8+
| MvelInjection.java:76:22:76:44 | getInputStream(...) : InputStream | MvelInjection.java:84:5:84:18 | compiledScript |
9+
| MvelInjection.java:76:22:76:44 | getInputStream(...) : InputStream | MvelInjection.java:87:21:87:26 | script |
10+
| MvelInjection.java:91:22:91:44 | getInputStream(...) : InputStream | MvelInjection.java:101:5:101:10 | script |
11+
| MvelInjection.java:105:22:105:44 | getInputStream(...) : InputStream | MvelInjection.java:111:26:111:30 | input |
12+
| MvelInjection.java:115:22:115:44 | getInputStream(...) : InputStream | MvelInjection.java:121:29:121:67 | compileTemplate(...) |
13+
| MvelInjection.java:125:22:125:44 | getInputStream(...) : InputStream | MvelInjection.java:132:54:132:71 | compile(...) |
1114
nodes
12-
| MvelInjection.java:20:27:20:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
13-
| MvelInjection.java:24:17:24:21 | input | semmle.label | input |
14-
| MvelInjection.java:29:27:29:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
15-
| MvelInjection.java:34:30:34:39 | expression | semmle.label | expression |
16-
| MvelInjection.java:39:27:39:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
17-
| MvelInjection.java:45:7:45:15 | statement | semmle.label | statement |
18-
| MvelInjection.java:46:7:46:15 | statement | semmle.label | statement |
19-
| MvelInjection.java:51:27:51:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
20-
| MvelInjection.java:57:7:57:16 | expression | semmle.label | expression |
21-
| MvelInjection.java:62:27:62:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
22-
| MvelInjection.java:67:7:67:16 | expression | semmle.label | expression |
23-
| MvelInjection.java:72:22:72:44 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
24-
| MvelInjection.java:80:5:80:18 | compiledScript | semmle.label | compiledScript |
25-
| MvelInjection.java:83:21:83:26 | script | semmle.label | script |
26-
| MvelInjection.java:87:22:87:44 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
27-
| MvelInjection.java:97:5:97:10 | script | semmle.label | script |
15+
| MvelInjection.java:24:27:24:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
16+
| MvelInjection.java:28:17:28:21 | input | semmle.label | input |
17+
| MvelInjection.java:33:27:33:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
18+
| MvelInjection.java:38:30:38:39 | expression | semmle.label | expression |
19+
| MvelInjection.java:43:27:43:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
20+
| MvelInjection.java:49:7:49:15 | statement | semmle.label | statement |
21+
| MvelInjection.java:50:7:50:15 | statement | semmle.label | statement |
22+
| MvelInjection.java:55:27:55:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
23+
| MvelInjection.java:61:7:61:16 | expression | semmle.label | expression |
24+
| MvelInjection.java:66:27:66:49 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
25+
| MvelInjection.java:71:7:71:16 | expression | semmle.label | expression |
26+
| MvelInjection.java:76:22:76:44 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
27+
| MvelInjection.java:84:5:84:18 | compiledScript | semmle.label | compiledScript |
28+
| MvelInjection.java:87:21:87:26 | script | semmle.label | script |
29+
| MvelInjection.java:91:22:91:44 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
30+
| MvelInjection.java:101:5:101:10 | script | semmle.label | script |
31+
| MvelInjection.java:105:22:105:44 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
32+
| MvelInjection.java:111:26:111:30 | input | semmle.label | input |
33+
| MvelInjection.java:115:22:115:44 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
34+
| MvelInjection.java:121:29:121:67 | compileTemplate(...) | semmle.label | compileTemplate(...) |
35+
| MvelInjection.java:125:22:125:44 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
36+
| MvelInjection.java:132:54:132:71 | compile(...) | semmle.label | compile(...) |
2837
#select
29-
| 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 |
30-
| 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 |
31-
| 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 |
32-
| 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 |
33-
| 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 |
34-
| 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 |
35-
| 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 |
36-
| 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 |
37-
| 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 |
38+
| 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 |
39+
| 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 |
40+
| 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 |
41+
| 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 |
42+
| 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 |
43+
| 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 |
44+
| 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 |
45+
| 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 |
46+
| 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 |
47+
| 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 |
48+
| 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 |
49+
| 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 |

java/ql/test/experimental/Security/CWE/CWE-094/MvelInjection.java

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import java.io.InputStream;
33
import java.io.Serializable;
44
import java.net.Socket;
5+
import java.util.HashMap;
56
import javax.script.CompiledScript;
67
import javax.script.SimpleScriptContext;
78
import org.mvel2.MVEL;
@@ -13,6 +14,9 @@
1314
import org.mvel2.integration.impl.ImmutableDefaultFactory;
1415
import org.mvel2.jsr223.MvelCompiledScript;
1516
import org.mvel2.jsr223.MvelScriptEngine;
17+
import org.mvel2.templates.CompiledTemplate;
18+
import org.mvel2.templates.TemplateCompiler;
19+
import org.mvel2.templates.TemplateRuntime;
1620

1721
public class MvelInjection {
1822

@@ -96,4 +100,35 @@ public static void testMvelCompiledScriptCompileAndEvaluate(Socket socket) throw
96100
MvelCompiledScript script = new MvelCompiledScript(engine, statement);
97101
script.eval(new SimpleScriptContext());
98102
}
103+
104+
public static void testTemplateRuntimeEval(Socket socket) throws Exception {
105+
InputStream in = socket.getInputStream();
106+
107+
byte[] bytes = new byte[1024];
108+
int n = in.read(bytes);
109+
String input = new String(bytes, 0, n);
110+
111+
TemplateRuntime.eval(input, new HashMap());
112+
}
113+
114+
public static void testTemplateRuntimeCompileTemplateAndExecute(Socket socket) throws Exception {
115+
InputStream in = socket.getInputStream();
116+
117+
byte[] bytes = new byte[1024];
118+
int n = in.read(bytes);
119+
String input = new String(bytes, 0, n);
120+
121+
TemplateRuntime.execute(TemplateCompiler.compileTemplate(input), new HashMap());
122+
}
123+
124+
public static void testTemplateRuntimeCompileAndExecute(Socket socket) throws Exception {
125+
InputStream in = socket.getInputStream();
126+
127+
byte[] bytes = new byte[1024];
128+
int n = in.read(bytes);
129+
String input = new String(bytes, 0, n);
130+
131+
TemplateCompiler compiler = new TemplateCompiler(input);
132+
String output = (String) TemplateRuntime.execute(compiler.compile(), new HashMap());
133+
}
99134
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
package org.mvel2.templates;
2+
3+
public class CompiledTemplate {}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package org.mvel2.templates;
2+
3+
public class TemplateCompiler {
4+
public TemplateCompiler(String template) {}
5+
public static CompiledTemplate compileTemplate(String template) { return null; }
6+
public CompiledTemplate compile() { return null; }
7+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package org.mvel2.templates;
2+
3+
import java.util.Map;
4+
5+
public class TemplateRuntime {
6+
public static Object eval(String template, Map vars) { return null; }
7+
public static Object execute(CompiledTemplate compiled, Map vars) { return null; }
8+
}

0 commit comments

Comments
 (0)