Skip to content

Commit ed0aabe

Browse files
committed
add isAdditionalTaintStep
1 parent 921b8e8 commit ed0aabe

File tree

5 files changed

+66
-5
lines changed

5 files changed

+66
-5
lines changed

java/ql/src/experimental/Security/CWE/CWE-094/JShellInjection.java

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ public class JShellInjection {
1111
public void bad1(HttpServletRequest request) {
1212
String input = request.getParameter("code");
1313
JShell jShell = JShell.builder().build();
14-
// BAD: allow execution of arbitrary Java code
14+
// BAD: allow execution of arbitrary Java code
1515
jShell.eval(input);
1616
}
1717

@@ -20,7 +20,21 @@ public void bad2(HttpServletRequest request) {
2020
String input = request.getParameter("code");
2121
JShell jShell = JShell.builder().build();
2222
SourceCodeAnalysis sourceCodeAnalysis = jShell.sourceCodeAnalysis();
23-
// BAD: allow execution of arbitrary Java code
23+
// BAD: allow execution of arbitrary Java code
2424
sourceCodeAnalysis.wrappers(input);
2525
}
26+
27+
@GetMapping(value = "bad3")
28+
public void bad3(HttpServletRequest request) {
29+
String input = request.getParameter("code");
30+
JShell jShell = JShell.builder().build();
31+
SourceCodeAnalysis.CompletionInfo info;
32+
SourceCodeAnalysis sca = jShell.sourceCodeAnalysis();
33+
for (info = sca.analyzeCompletion(input);
34+
info.completeness().isComplete();
35+
info = sca.analyzeCompletion(info.remaining())) {
36+
// BAD: allow execution of arbitrary Java code
37+
jShell.eval(info.source());
38+
}
39+
}
2640
}

java/ql/src/experimental/Security/CWE/CWE-094/JShellInjection.ql

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,19 @@ class JShellInjectionConfiguration extends TaintTracking::Configuration {
2121
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
2222

2323
override predicate isSink(DataFlow::Node sink) { sink instanceof JShellInjectionSink }
24+
25+
override predicate isAdditionalTaintStep(DataFlow::Node prod, DataFlow::Node succ) {
26+
exists(MethodAccess ma |
27+
ma.getMethod().hasName("analyzeCompletion") and
28+
ma.getMethod().getNumberOfParameters() = 1 and
29+
ma.getMethod()
30+
.getDeclaringType()
31+
.getASupertype*()
32+
.hasQualifiedName("jdk.jshell", "SourceCodeAnalysis") and
33+
ma.getArgument(0) = prod.asExpr() and
34+
ma = succ.asExpr()
35+
)
36+
}
2437
}
2538

2639
from DataFlow::PathNode source, DataFlow::PathNode sink, JShellInjectionConfiguration conf

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

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,24 @@ import semmle.code.java.dataflow.FlowSources
44
/** A sink for JShell expression injection vulnerabilities. */
55
class JShellInjectionSink extends DataFlow::Node {
66
JShellInjectionSink() {
7-
this.asExpr() = any(JShellEvalCall jsec).getArgument(0) or
7+
this.asExpr() = any(JShellEvalCall jsec).getArgument(0)
8+
or
89
this.asExpr() = any(SourceCodeAnalysisWrappersCall scawc).getArgument(0)
10+
or
11+
exists(MethodAccess ma |
12+
ma.getMethod().hasName("source") and
13+
ma.getMethod().getNumberOfParameters() = 0 and
14+
ma.getMethod()
15+
.getDeclaringType()
16+
.getASupertype*()
17+
.hasQualifiedName("jdk.jshell", "SourceCodeAnalysis$CompletionInfo") and
18+
ma.getQualifier() = this.asExpr() and
19+
(
20+
ma = any(JShellEvalCall jsec).getArgument(0)
21+
or
22+
ma = any(SourceCodeAnalysisWrappersCall scawc).getArgument(0)
23+
)
24+
)
925
}
1026
}
1127

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
edges
22
| JShellInjection.java:12:18:12:45 | getParameter(...) : String | JShellInjection.java:15:15:15:19 | input |
33
| JShellInjection.java:20:18:20:45 | getParameter(...) : String | JShellInjection.java:24:31:24:35 | input |
4+
| JShellInjection.java:29:18:29:45 | getParameter(...) : String | JShellInjection.java:37:16:37:19 | info |
45
nodes
56
| JShellInjection.java:12:18:12:45 | getParameter(...) : String | semmle.label | getParameter(...) : String |
67
| JShellInjection.java:15:15:15:19 | input | semmle.label | input |
78
| JShellInjection.java:20:18:20:45 | getParameter(...) : String | semmle.label | getParameter(...) : String |
89
| JShellInjection.java:24:31:24:35 | input | semmle.label | input |
10+
| JShellInjection.java:29:18:29:45 | getParameter(...) : String | semmle.label | getParameter(...) : String |
11+
| JShellInjection.java:37:16:37:19 | info | semmle.label | info |
912
#select
1013
| JShellInjection.java:15:15:15:19 | input | JShellInjection.java:12:18:12:45 | getParameter(...) : String | JShellInjection.java:15:15:15:19 | input | JShell injection from $@. | JShellInjection.java:12:18:12:45 | getParameter(...) | this user input |
1114
| JShellInjection.java:24:31:24:35 | input | JShellInjection.java:20:18:20:45 | getParameter(...) : String | JShellInjection.java:24:31:24:35 | input | JShell injection from $@. | JShellInjection.java:20:18:20:45 | getParameter(...) | this user input |
15+
| JShellInjection.java:37:16:37:19 | info | JShellInjection.java:29:18:29:45 | getParameter(...) : String | JShellInjection.java:37:16:37:19 | info | JShell injection from $@. | JShellInjection.java:29:18:29:45 | getParameter(...) | this user input |

java/ql/test/experimental/query-tests/security/CWE-094/JShellInjection.java

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ public class JShellInjection {
1111
public void bad1(HttpServletRequest request) {
1212
String input = request.getParameter("code");
1313
JShell jShell = JShell.builder().build();
14-
// BAD: allow execution of arbitrary Java code
14+
// BAD: allow execution of arbitrary Java code
1515
jShell.eval(input);
1616
}
1717

@@ -20,7 +20,21 @@ public void bad2(HttpServletRequest request) {
2020
String input = request.getParameter("code");
2121
JShell jShell = JShell.builder().build();
2222
SourceCodeAnalysis sourceCodeAnalysis = jShell.sourceCodeAnalysis();
23-
// BAD: allow execution of arbitrary Java code
23+
// BAD: allow execution of arbitrary Java code
2424
sourceCodeAnalysis.wrappers(input);
2525
}
26+
27+
@GetMapping(value = "bad3")
28+
public void bad3(HttpServletRequest request) {
29+
String input = request.getParameter("code");
30+
JShell jShell = JShell.builder().build();
31+
SourceCodeAnalysis.CompletionInfo info;
32+
SourceCodeAnalysis sca = jShell.sourceCodeAnalysis();
33+
for (info = sca.analyzeCompletion(input);
34+
info.completeness().isComplete();
35+
info = sca.analyzeCompletion(info.remaining())) {
36+
// BAD: allow execution of arbitrary Java code
37+
jShell.eval(info.source());
38+
}
39+
}
2640
}

0 commit comments

Comments
 (0)