Skip to content

Commit adb1ed3

Browse files
Added tests for Jakarta expression injection
1 parent 73e940d commit adb1ed3

16 files changed

+223
-11
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/**
2-
* @name Java EE Expression Language injection
3-
* @description Evaluation of a user-controlled Jave EE expression
2+
* @name Jakarta Expression Language injection
3+
* @description Evaluation of a user-controlled expression
44
* may lead to arbitrary code execution.
55
* @kind path-problem
66
* @problem.severity error
@@ -11,10 +11,10 @@
1111
*/
1212

1313
import java
14-
import JavaEEExpressionInjectionLib
14+
import JakartaExpressionInjectionLib
1515
import DataFlow::PathGraph
1616

17-
from DataFlow::PathNode source, DataFlow::PathNode sink, JavaEEExpressionInjectionConfig conf
17+
from DataFlow::PathNode source, DataFlow::PathNode sink, JakartaExpressionInjectionConfig conf
1818
where conf.hasFlowPath(source, sink)
19-
select sink.getNode(), source, sink, "Java EE Expression Language injection from $@.",
19+
select sink.getNode(), source, sink, "Jakarta Expression Language injection from $@.",
2020
source.getNode(), "this user input"

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

+4-4
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@ import semmle.code.java.dataflow.TaintTracking
55

66
/**
77
* A taint-tracking configuration for unsafe user input
8-
* that is used to construct and evaluate a Java EE expression.
8+
* that is used to construct and evaluate an expression.
99
*/
10-
class JavaEEExpressionInjectionConfig extends TaintTracking::Configuration {
11-
JavaEEExpressionInjectionConfig() { this = "JavaEEExpressionInjectionConfig" }
10+
class JakartaExpressionInjectionConfig extends TaintTracking::Configuration {
11+
JakartaExpressionInjectionConfig() { this = "JakartaExpressionInjectionConfig" }
1212

1313
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
1414

@@ -22,7 +22,7 @@ class JavaEEExpressionInjectionConfig extends TaintTracking::Configuration {
2222

2323
/**
2424
* A sink for Expresssion Language injection vulnerabilities,
25-
* i.e. method calls that run evaluation of a Java EE expression.
25+
* i.e. method calls that run evaluation of an expression.
2626
*/
2727
private class ExpressionEvaluationSink extends DataFlow::ExprNode {
2828
ExpressionEvaluationSink() {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
edges
2+
| JakartaExpressionInjection.java:22:25:22:47 | getInputStream(...) : InputStream | JakartaExpressionInjection.java:24:31:24:40 | expression : String |
3+
| JakartaExpressionInjection.java:24:31:24:40 | expression : String | JakartaExpressionInjection.java:30:24:30:33 | expression : String |
4+
| JakartaExpressionInjection.java:24:31:24:40 | expression : String | JakartaExpressionInjection.java:37:24:37:33 | expression : String |
5+
| JakartaExpressionInjection.java:24:31:24:40 | expression : String | JakartaExpressionInjection.java:44:24:44:33 | expression : String |
6+
| JakartaExpressionInjection.java:24:31:24:40 | expression : String | JakartaExpressionInjection.java:54:24:54:33 | expression : String |
7+
| JakartaExpressionInjection.java:24:31:24:40 | expression : String | JakartaExpressionInjection.java:61:24:61:33 | expression : String |
8+
| JakartaExpressionInjection.java:24:31:24:40 | expression : String | JakartaExpressionInjection.java:70:24:70:33 | expression : String |
9+
| JakartaExpressionInjection.java:24:31:24:40 | expression : String | JakartaExpressionInjection.java:79:24:79:33 | expression : String |
10+
| JakartaExpressionInjection.java:30:24:30:33 | expression : String | JakartaExpressionInjection.java:32:28:32:37 | expression |
11+
| JakartaExpressionInjection.java:37:24:37:33 | expression : String | JakartaExpressionInjection.java:39:32:39:41 | expression |
12+
| JakartaExpressionInjection.java:44:24:44:33 | expression : String | JakartaExpressionInjection.java:49:13:49:28 | lambdaExpression |
13+
| JakartaExpressionInjection.java:48:49:48:104 | new LambdaExpression(...) : LambdaExpression | JakartaExpressionInjection.java:49:13:49:28 | lambdaExpression |
14+
| JakartaExpressionInjection.java:54:24:54:33 | expression : String | JakartaExpressionInjection.java:56:32:56:41 | expression |
15+
| JakartaExpressionInjection.java:61:24:61:33 | expression : String | JakartaExpressionInjection.java:64:33:64:96 | createValueExpression(...) : ValueExpression |
16+
| JakartaExpressionInjection.java:61:24:61:33 | expression : String | JakartaExpressionInjection.java:65:13:65:13 | e |
17+
| JakartaExpressionInjection.java:61:24:61:33 | expression : String | JakartaExpressionInjection.java:65:13:65:13 | e : ValueExpression |
18+
| JakartaExpressionInjection.java:64:33:64:96 | createValueExpression(...) : ValueExpression | JakartaExpressionInjection.java:48:49:48:104 | new LambdaExpression(...) : LambdaExpression |
19+
| JakartaExpressionInjection.java:64:33:64:96 | createValueExpression(...) : ValueExpression | JakartaExpressionInjection.java:65:13:65:13 | e |
20+
| JakartaExpressionInjection.java:64:33:64:96 | createValueExpression(...) : ValueExpression | JakartaExpressionInjection.java:65:13:65:13 | e : ValueExpression |
21+
| JakartaExpressionInjection.java:65:13:65:13 | e : ValueExpression | JakartaExpressionInjection.java:48:49:48:104 | new LambdaExpression(...) : LambdaExpression |
22+
| JakartaExpressionInjection.java:70:24:70:33 | expression : String | JakartaExpressionInjection.java:73:33:73:96 | createValueExpression(...) : ValueExpression |
23+
| JakartaExpressionInjection.java:70:24:70:33 | expression : String | JakartaExpressionInjection.java:74:13:74:13 | e |
24+
| JakartaExpressionInjection.java:70:24:70:33 | expression : String | JakartaExpressionInjection.java:74:13:74:13 | e : ValueExpression |
25+
| JakartaExpressionInjection.java:73:33:73:96 | createValueExpression(...) : ValueExpression | JakartaExpressionInjection.java:48:49:48:104 | new LambdaExpression(...) : LambdaExpression |
26+
| JakartaExpressionInjection.java:73:33:73:96 | createValueExpression(...) : ValueExpression | JakartaExpressionInjection.java:74:13:74:13 | e |
27+
| JakartaExpressionInjection.java:73:33:73:96 | createValueExpression(...) : ValueExpression | JakartaExpressionInjection.java:74:13:74:13 | e : ValueExpression |
28+
| JakartaExpressionInjection.java:74:13:74:13 | e : ValueExpression | JakartaExpressionInjection.java:48:49:48:104 | new LambdaExpression(...) : LambdaExpression |
29+
| JakartaExpressionInjection.java:79:24:79:33 | expression : String | JakartaExpressionInjection.java:83:13:83:13 | e |
30+
nodes
31+
| JakartaExpressionInjection.java:22:25:22:47 | getInputStream(...) : InputStream | semmle.label | getInputStream(...) : InputStream |
32+
| JakartaExpressionInjection.java:24:31:24:40 | expression : String | semmle.label | expression : String |
33+
| JakartaExpressionInjection.java:30:24:30:33 | expression : String | semmle.label | expression : String |
34+
| JakartaExpressionInjection.java:32:28:32:37 | expression | semmle.label | expression |
35+
| JakartaExpressionInjection.java:37:24:37:33 | expression : String | semmle.label | expression : String |
36+
| JakartaExpressionInjection.java:39:32:39:41 | expression | semmle.label | expression |
37+
| JakartaExpressionInjection.java:44:24:44:33 | expression : String | semmle.label | expression : String |
38+
| JakartaExpressionInjection.java:48:49:48:104 | new LambdaExpression(...) : LambdaExpression | semmle.label | new LambdaExpression(...) : LambdaExpression |
39+
| JakartaExpressionInjection.java:49:13:49:28 | lambdaExpression | semmle.label | lambdaExpression |
40+
| JakartaExpressionInjection.java:54:24:54:33 | expression : String | semmle.label | expression : String |
41+
| JakartaExpressionInjection.java:56:32:56:41 | expression | semmle.label | expression |
42+
| JakartaExpressionInjection.java:61:24:61:33 | expression : String | semmle.label | expression : String |
43+
| JakartaExpressionInjection.java:64:33:64:96 | createValueExpression(...) : ValueExpression | semmle.label | createValueExpression(...) : ValueExpression |
44+
| JakartaExpressionInjection.java:65:13:65:13 | e | semmle.label | e |
45+
| JakartaExpressionInjection.java:65:13:65:13 | e : ValueExpression | semmle.label | e : ValueExpression |
46+
| JakartaExpressionInjection.java:70:24:70:33 | expression : String | semmle.label | expression : String |
47+
| JakartaExpressionInjection.java:73:33:73:96 | createValueExpression(...) : ValueExpression | semmle.label | createValueExpression(...) : ValueExpression |
48+
| JakartaExpressionInjection.java:74:13:74:13 | e | semmle.label | e |
49+
| JakartaExpressionInjection.java:74:13:74:13 | e : ValueExpression | semmle.label | e : ValueExpression |
50+
| JakartaExpressionInjection.java:79:24:79:33 | expression : String | semmle.label | expression : String |
51+
| JakartaExpressionInjection.java:83:13:83:13 | e | semmle.label | e |
52+
#select
53+
| JakartaExpressionInjection.java:32:28:32:37 | expression | JakartaExpressionInjection.java:22:25:22:47 | getInputStream(...) : InputStream | JakartaExpressionInjection.java:32:28:32:37 | expression | Jakarta Expression Language injection from $@. | JakartaExpressionInjection.java:22:25:22:47 | getInputStream(...) | this user input |
54+
| JakartaExpressionInjection.java:39:32:39:41 | expression | JakartaExpressionInjection.java:22:25:22:47 | getInputStream(...) : InputStream | JakartaExpressionInjection.java:39:32:39:41 | expression | Jakarta Expression Language injection from $@. | JakartaExpressionInjection.java:22:25:22:47 | getInputStream(...) | this user input |
55+
| JakartaExpressionInjection.java:49:13:49:28 | lambdaExpression | JakartaExpressionInjection.java:22:25:22:47 | getInputStream(...) : InputStream | JakartaExpressionInjection.java:49:13:49:28 | lambdaExpression | Jakarta Expression Language injection from $@. | JakartaExpressionInjection.java:22:25:22:47 | getInputStream(...) | this user input |
56+
| JakartaExpressionInjection.java:56:32:56:41 | expression | JakartaExpressionInjection.java:22:25:22:47 | getInputStream(...) : InputStream | JakartaExpressionInjection.java:56:32:56:41 | expression | Jakarta Expression Language injection from $@. | JakartaExpressionInjection.java:22:25:22:47 | getInputStream(...) | this user input |
57+
| JakartaExpressionInjection.java:65:13:65:13 | e | JakartaExpressionInjection.java:22:25:22:47 | getInputStream(...) : InputStream | JakartaExpressionInjection.java:65:13:65:13 | e | Jakarta Expression Language injection from $@. | JakartaExpressionInjection.java:22:25:22:47 | getInputStream(...) | this user input |
58+
| JakartaExpressionInjection.java:74:13:74:13 | e | JakartaExpressionInjection.java:22:25:22:47 | getInputStream(...) : InputStream | JakartaExpressionInjection.java:74:13:74:13 | e | Jakarta Expression Language injection from $@. | JakartaExpressionInjection.java:22:25:22:47 | getInputStream(...) | this user input |
59+
| JakartaExpressionInjection.java:83:13:83:13 | e | JakartaExpressionInjection.java:22:25:22:47 | getInputStream(...) : InputStream | JakartaExpressionInjection.java:83:13:83:13 | e | Jakarta Expression Language injection from $@. | JakartaExpressionInjection.java:22:25:22:47 | getInputStream(...) | this user input |
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
import java.io.IOException;
2+
import java.net.ServerSocket;
3+
import java.net.Socket;
4+
import java.util.ArrayList;
5+
import java.util.function.Consumer;
6+
7+
import javax.el.ELContext;
8+
import javax.el.ELManager;
9+
import javax.el.ELProcessor;
10+
import javax.el.ExpressionFactory;
11+
import javax.el.LambdaExpression;
12+
import javax.el.MethodExpression;
13+
import javax.el.StandardELContext;
14+
import javax.el.ValueExpression;
15+
16+
public class JakartaExpressionInjection {
17+
18+
private static void testWithSocket(Consumer<String> action) throws IOException {
19+
try (ServerSocket serverSocket = new ServerSocket(0)) {
20+
try (Socket socket = serverSocket.accept()) {
21+
byte[] bytes = new byte[1024];
22+
int n = socket.getInputStream().read(bytes);
23+
String expression = new String(bytes, 0, n);
24+
action.accept(expression);
25+
}
26+
}
27+
}
28+
29+
private static void testWithELProcessorEval() throws IOException {
30+
testWithSocket(expression -> {
31+
ELProcessor processor = new ELProcessor();
32+
processor.eval(expression);
33+
});
34+
}
35+
36+
private static void testWithELProcessorGetValue() throws IOException {
37+
testWithSocket(expression -> {
38+
ELProcessor processor = new ELProcessor();
39+
processor.getValue(expression, Object.class);
40+
});
41+
}
42+
43+
private static void testWithLambdaExpressionInvoke() throws IOException {
44+
testWithSocket(expression -> {
45+
ExpressionFactory factory = ELManager.getExpressionFactory();
46+
StandardELContext context = new StandardELContext(factory);
47+
ValueExpression valueExpression = factory.createValueExpression(context, expression, Object.class);
48+
LambdaExpression lambdaExpression = new LambdaExpression(new ArrayList<>(), valueExpression);
49+
lambdaExpression.invoke(context, new Object[0]);
50+
});
51+
}
52+
53+
private static void testWithELProcessorSetValue() throws IOException {
54+
testWithSocket(expression -> {
55+
ELProcessor processor = new ELProcessor();
56+
processor.setValue(expression, new Object());
57+
});
58+
}
59+
60+
private static void testWithJuelValueExpressionGetValue() throws IOException {
61+
testWithSocket(expression -> {
62+
ExpressionFactory factory = new de.odysseus.el.ExpressionFactoryImpl();
63+
ELContext context = new de.odysseus.el.util.SimpleContext();
64+
ValueExpression e = factory.createValueExpression(context, expression, Object.class);
65+
e.getValue(context);
66+
});
67+
}
68+
69+
private static void testWithJuelValueExpressionSetValue() throws IOException {
70+
testWithSocket(expression -> {
71+
ExpressionFactory factory = new de.odysseus.el.ExpressionFactoryImpl();
72+
ELContext context = new de.odysseus.el.util.SimpleContext();
73+
ValueExpression e = factory.createValueExpression(context, expression, Object.class);
74+
e.setValue(context, new Object());
75+
});
76+
}
77+
78+
private static void testWithJuelMethodExpressionInvoke() throws IOException {
79+
testWithSocket(expression -> {
80+
ExpressionFactory factory = new de.odysseus.el.ExpressionFactoryImpl();
81+
ELContext context = new de.odysseus.el.util.SimpleContext();
82+
MethodExpression e = factory.createMethodExpression(context, expression, Object.class, new Class[0]);
83+
e.invoke(context, new Object[0]);
84+
});
85+
}
86+
87+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
experimental/Security/CWE/CWE-094/JakartaExpressionInjection.ql
Original file line numberDiff line numberDiff line change
@@ -1,2 +1 @@
1-
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/springframework-5.2.3:${testdir}/../../../../stubs/mvel2-2.4.7:${testdir}/../../../../stubs/jsr223-api:${testdir}/../../../../stubs/apache-commons-jexl-2.1.1:${testdir}/../../../../stubs/apache-commons-jexl-3.1:${testdir}/../../../../stubs/scriptengine
2-
1+
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/springframework-5.2.3:${testdir}/../../../../stubs/mvel2-2.4.7:${testdir}/../../../../stubs/jsr223-api:${testdir}/../../../../stubs/apache-commons-jexl-2.1.1:${testdir}/../../../../stubs/apache-commons-jexl-3.1:${testdir}/../../../../stubs/scriptengine:${testdir}/../../../../stubs/java-ee-el:${testdir}/../../../../stubs/juel-2.2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
package javax.el;
2+
3+
public class ELContext {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package javax.el;
2+
3+
public class ELManager {
4+
public static ExpressionFactory getExpressionFactory() { return null; }
5+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package javax.el;
2+
3+
public class ELProcessor {
4+
public Object eval(String expression) { return null; }
5+
public Object getValue(String expression, Class<?> expectedType) { return null; }
6+
public void setValue(String expression, Object value) {}
7+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package javax.el;
2+
3+
public class ExpressionFactory {
4+
public MethodExpression createMethodExpression(ELContext context, String expression, Class<?> expectedReturnType,
5+
Class<?>[] expectedParamTypes) {
6+
7+
return null;
8+
}
9+
10+
public ValueExpression createValueExpression(ELContext context, String expression, Class<?> expectedType) {
11+
return null;
12+
}
13+
14+
public ValueExpression createValueExpression(Object instance, Class<?> expectedType) {
15+
return null;
16+
}
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package javax.el;
2+
3+
import java.util.List;
4+
5+
public class LambdaExpression {
6+
public LambdaExpression(List<String> formalParameters, ValueExpression expression) {}
7+
public Object invoke(Object... args) { return null; }
8+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package javax.el;
2+
3+
public class MethodExpression {
4+
public Object invoke(ELContext context, Object[] params) { return null; }
5+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package javax.el;
2+
3+
public class StandardELContext extends ELContext {
4+
public StandardELContext(ExpressionFactory factory) {}
5+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package javax.el;
2+
3+
public class ValueExpression {
4+
public Object getValue(ELContext context) { return null; }
5+
public void setValue(ELContext context, Object value) {}
6+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package de.odysseus.el;
2+
3+
import javax.el.ExpressionFactory;
4+
5+
public class ExpressionFactoryImpl extends ExpressionFactory {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package de.odysseus.el.util;
2+
3+
import javax.el.ELContext;
4+
5+
public class SimpleContext extends ELContext {}

0 commit comments

Comments
 (0)