Skip to content

Commit 8c73fbe

Browse files
committed
Formatted
1 parent 55eeb00 commit 8c73fbe

File tree

4 files changed

+137
-143
lines changed

4 files changed

+137
-143
lines changed

java/ql/src/experimental/Security/CWE/CWE-078/CommandInjectionRuntimeExec.qll

Lines changed: 72 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -4,124 +4,103 @@ import semmle.code.java.dataflow.DataFlow
44
private import semmle.code.java.dataflow.TaintTracking
55
import semmle.code.java.dataflow.FlowSources
66

7-
87
// a static string of an unsafe executable tainting arg 0 of Runtime.exec()
98
class ExecTaintConfiguration extends TaintTracking::Configuration {
10-
ExecTaintConfiguration() { this = "ExecTaintConfiguration" }
11-
12-
override
13-
predicate
14-
isSource(DataFlow::Node source) {
15-
source.asExpr() instanceof StringLiteral
16-
and source.asExpr().(StringLiteral).getValue() instanceof UnSafeExecutable
17-
}
18-
19-
override
20-
predicate
21-
isSink(DataFlow::Node sink) {
22-
exists(RuntimeExecMethod method, MethodAccess call |
23-
call.getMethod() = method
24-
and sink.asExpr() = call.getArgument(0)
25-
and sink.asExpr().getType() instanceof Array
26-
)
27-
}
28-
29-
override
30-
predicate
31-
isSanitizer(DataFlow::Node node) {
32-
node.asExpr().getFile().isSourceFile() and
33-
(
34-
node instanceof AssignToNonZeroIndex
35-
or node instanceof ArrayInitAtNonZeroIndex
36-
or node instanceof StreamConcatAtNonZeroIndex
37-
or node.getType() instanceof PrimitiveType
38-
or node.getType() instanceof BoxedType
39-
)
40-
}
9+
ExecTaintConfiguration() { this = "ExecTaintConfiguration" }
10+
11+
override predicate isSource(DataFlow::Node source) {
12+
source.asExpr() instanceof StringLiteral and
13+
source.asExpr().(StringLiteral).getValue() instanceof UnSafeExecutable
14+
}
15+
16+
override predicate isSink(DataFlow::Node sink) {
17+
exists(RuntimeExecMethod method, MethodAccess call |
18+
call.getMethod() = method and
19+
sink.asExpr() = call.getArgument(0) and
20+
sink.asExpr().getType() instanceof Array
21+
)
22+
}
23+
24+
override predicate isSanitizer(DataFlow::Node node) {
25+
node.asExpr().getFile().isSourceFile() and
26+
(
27+
node instanceof AssignToNonZeroIndex or
28+
node instanceof ArrayInitAtNonZeroIndex or
29+
node instanceof StreamConcatAtNonZeroIndex or
30+
node.getType() instanceof PrimitiveType or
31+
node.getType() instanceof BoxedType
32+
)
33+
}
4134
}
4235

4336
abstract class Source extends DataFlow::Node {
44-
Source() {
45-
this = this
46-
}
37+
Source() { this = this }
4738
}
4839

49-
5040
// taint flow from user data to args of the command
5141
class ExecTaintConfiguration2 extends TaintTracking::Configuration {
52-
ExecTaintConfiguration2() { this = "ExecTaintConfiguration2" }
53-
54-
override
55-
predicate
56-
isSource(DataFlow::Node source) {
57-
source instanceof Source
58-
}
59-
60-
override
61-
predicate
62-
isSink(DataFlow::Node sink) {
63-
exists(RuntimeExecMethod method, MethodAccess call, int index |
64-
call.getMethod() = method
65-
and sink.asExpr() = call.getArgument(index)
66-
and sink.asExpr().getType() instanceof Array
67-
)
68-
}
69-
70-
override
71-
predicate
72-
isSanitizer(DataFlow::Node node) {
73-
node.asExpr().getFile().isSourceFile() and
74-
(
75-
node.getType() instanceof PrimitiveType
76-
or node.getType() instanceof BoxedType
77-
)
78-
}
42+
ExecTaintConfiguration2() { this = "ExecTaintConfiguration2" }
43+
44+
override predicate isSource(DataFlow::Node source) { source instanceof Source }
45+
46+
override predicate isSink(DataFlow::Node sink) {
47+
exists(RuntimeExecMethod method, MethodAccess call, int index |
48+
call.getMethod() = method and
49+
sink.asExpr() = call.getArgument(index) and
50+
sink.asExpr().getType() instanceof Array
51+
)
52+
}
53+
54+
override predicate isSanitizer(DataFlow::Node node) {
55+
node.asExpr().getFile().isSourceFile() and
56+
(
57+
node.getType() instanceof PrimitiveType or
58+
node.getType() instanceof BoxedType
59+
)
60+
}
7961
}
8062

81-
8263
// array[3] = node
8364
class AssignToNonZeroIndex extends DataFlow::Node {
84-
AssignExpr assign;
85-
ArrayAccess access;
86-
87-
AssignToNonZeroIndex() {
88-
assign.getDest() = access
89-
and access.getIndexExpr().(IntegerLiteral).getValue() != "0"
90-
and assign.getSource() = this.asExpr()
91-
}
65+
AssignExpr assign;
66+
ArrayAccess access;
67+
68+
AssignToNonZeroIndex() {
69+
assign.getDest() = access and
70+
access.getIndexExpr().(IntegerLiteral).getValue() != "0" and
71+
assign.getSource() = this.asExpr()
72+
}
9273
}
9374

94-
9575
// String[] array = {"a", "b, "c"};
9676
class ArrayInitAtNonZeroIndex extends DataFlow::Node {
97-
ArrayInit init;
98-
int index;
77+
ArrayInit init;
78+
int index;
9979

100-
ArrayInitAtNonZeroIndex() {
101-
init.getInit(index) = this.asExpr()
102-
and index != 0
103-
}
80+
ArrayInitAtNonZeroIndex() {
81+
init.getInit(index) = this.asExpr() and
82+
index != 0
83+
}
10484
}
10585

10686
// Stream.concat(Arrays.stream(array_1), Arrays.stream(array_2))
10787
class StreamConcatAtNonZeroIndex extends DataFlow::Node {
108-
MethodAccess call;
109-
int index;
110-
111-
StreamConcatAtNonZeroIndex() {
112-
call.getMethod().getQualifiedName() = "java.util.stream.Stream.concat"
113-
and call.getArgument(index) = this.asExpr()
114-
and index != 0
115-
}
88+
MethodAccess call;
89+
int index;
90+
91+
StreamConcatAtNonZeroIndex() {
92+
call.getMethod().getQualifiedName() = "java.util.stream.Stream.concat" and
93+
call.getArgument(index) = this.asExpr() and
94+
index != 0
95+
}
11696
}
11797

118-
11998
// allow list of executables that execute their arguments
12099
// TODO: extend with data extensions
121100
class UnSafeExecutable extends string {
122-
bindingset[this]
123-
UnSafeExecutable() {
124-
this.regexpMatch("^(|.*/)([a-z]*sh|javac?|python.*|perl|[Pp]ower[Ss]hell|php|node|deno|bun|ruby|osascript|cmd|Rscript|groovy)(\\.exe)?$")
125-
and not this.matches("netsh.exe")
126-
}
101+
bindingset[this]
102+
UnSafeExecutable() {
103+
this.regexpMatch("^(|.*/)([a-z]*sh|javac?|python.*|perl|[Pp]ower[Ss]hell|php|node|deno|bun|ruby|osascript|cmd|Rscript|groovy)(\\.exe)?$") and
104+
not this.matches("netsh.exe")
105+
}
127106
}

java/ql/src/experimental/Security/CWE/CWE-078/CommandInjectionRuntimeExecLocal.ql

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -12,24 +12,29 @@
1212
* external/cwe/cwe-078
1313
*/
1414

15-
1615
import DataFlow::PathGraph
1716
import CommandInjectionRuntimeExec
1817

19-
class LocalSource extends Source { LocalSource() { this instanceof LocalUserInput } }
18+
class LocalSource extends Source {
19+
LocalSource() { this instanceof LocalUserInput }
20+
}
2021

21-
from DataFlow::PathNode source, DataFlow::PathNode sink, ExecTaintConfiguration2 conf, MethodAccess call, DataFlow::Node sourceCmd, DataFlow::Node sinkCmd, ExecTaintConfiguration confCmd
22-
where call.getMethod() instanceof RuntimeExecMethod
23-
// this is a command-accepting call to exec, e.g. rt.exec(new String[]{"/bin/sh", ...})
24-
and (
25-
confCmd.hasFlow(sourceCmd, sinkCmd)
26-
and sinkCmd.asExpr() = call.getArgument(0)
27-
)
28-
// it is tainted by untrusted user input
29-
and (
30-
conf.hasFlow(source.getNode(), sink.getNode())
31-
and sink.getNode().asExpr() = call.getArgument(0)
32-
)
33-
select sink, source, sink, "Call to dangerous java.lang.Runtime.exec() with command '$@' with arg from untrusted input '$@'",
34-
sourceCmd, sourceCmd.toString(),
35-
source.getNode(), source.toString()
22+
from
23+
DataFlow::PathNode source, DataFlow::PathNode sink, ExecTaintConfiguration2 conf,
24+
MethodAccess call, DataFlow::Node sourceCmd, DataFlow::Node sinkCmd,
25+
ExecTaintConfiguration confCmd
26+
where
27+
call.getMethod() instanceof RuntimeExecMethod and
28+
// this is a command-accepting call to exec, e.g. rt.exec(new String[]{"/bin/sh", ...})
29+
(
30+
confCmd.hasFlow(sourceCmd, sinkCmd) and
31+
sinkCmd.asExpr() = call.getArgument(0)
32+
) and
33+
// it is tainted by untrusted user input
34+
(
35+
conf.hasFlow(source.getNode(), sink.getNode()) and
36+
sink.getNode().asExpr() = call.getArgument(0)
37+
)
38+
select sink, source, sink,
39+
"Call to dangerous java.lang.Runtime.exec() with command '$@' with arg from untrusted input '$@'",
40+
sourceCmd, sourceCmd.toString(), source.getNode(), source.toString()

java/ql/src/experimental/Security/CWE/CWE-078/CommandInjectionRuntimeExecTest.ql

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -13,23 +13,27 @@
1313
* external/cwe/cwe-078
1414
*/
1515

16-
1716
import CommandInjectionRuntimeExec
1817

19-
class DataSource extends Source { DataSource() { this instanceof RemoteFlowSource or this instanceof LocalUserInput } }
18+
class DataSource extends Source {
19+
DataSource() { this instanceof RemoteFlowSource or this instanceof LocalUserInput }
20+
}
2021

21-
from DataFlow::Node source, DataFlow::Node sink, ExecTaintConfiguration2 conf, MethodAccess call, int index, DataFlow::Node sourceCmd, DataFlow::Node sinkCmd, ExecTaintConfiguration confCmd
22-
where call.getMethod() instanceof RuntimeExecMethod
23-
// this is a command-accepting call to exec, e.g. exec("/bin/sh", ...)
24-
and (
25-
confCmd.hasFlow(sourceCmd, sinkCmd)
26-
and sinkCmd.asExpr() = call.getArgument(0)
27-
)
28-
// it is tainted by untrusted user input
29-
and (
30-
conf.hasFlow(source, sink)
31-
and sink.asExpr() = call.getArgument(index)
32-
)
33-
select sink, "Call to dangerous java.lang.Runtime.exec() with command '$@' with arg from untrusted input '$@'",
34-
sourceCmd, sourceCmd.toString(),
35-
source, source.toString()
22+
from
23+
DataFlow::Node source, DataFlow::Node sink, ExecTaintConfiguration2 conf, MethodAccess call,
24+
int index, DataFlow::Node sourceCmd, DataFlow::Node sinkCmd, ExecTaintConfiguration confCmd
25+
where
26+
call.getMethod() instanceof RuntimeExecMethod and
27+
// this is a command-accepting call to exec, e.g. exec("/bin/sh", ...)
28+
(
29+
confCmd.hasFlow(sourceCmd, sinkCmd) and
30+
sinkCmd.asExpr() = call.getArgument(0)
31+
) and
32+
// it is tainted by untrusted user input
33+
(
34+
conf.hasFlow(source, sink) and
35+
sink.asExpr() = call.getArgument(index)
36+
)
37+
select sink,
38+
"Call to dangerous java.lang.Runtime.exec() with command '$@' with arg from untrusted input '$@'",
39+
sourceCmd, sourceCmd.toString(), source, source.toString()

java/ql/src/experimental/Security/CWE/CWE-078/CommandInjectionRuntimeExecTestPath.ql

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -16,20 +16,26 @@
1616
import DataFlow::PathGraph
1717
import CommandInjectionRuntimeExec
1818

19-
class DataSource extends Source { DataSource() { this instanceof RemoteFlowSource or this instanceof LocalUserInput } }
19+
class DataSource extends Source {
20+
DataSource() { this instanceof RemoteFlowSource or this instanceof LocalUserInput }
21+
}
2022

21-
from DataFlow::PathNode source, DataFlow::PathNode sink, ExecTaintConfiguration2 conf, MethodAccess call, DataFlow::Node sourceCmd, DataFlow::Node sinkCmd, ExecTaintConfiguration confCmd
22-
where call.getMethod() instanceof RuntimeExecMethod
23-
// this is a command-accepting call to exec, e.g. rt.exec(new String[]{"/bin/sh", ...})
24-
and (
25-
confCmd.hasFlow(sourceCmd, sinkCmd)
26-
and sinkCmd.asExpr() = call.getArgument(0)
27-
)
28-
// it is tainted by untrusted user input
29-
and (
30-
conf.hasFlow(source.getNode(), sink.getNode())
31-
and sink.getNode().asExpr() = call.getArgument(0)
32-
)
33-
select sink, source, sink, "Call to dangerous java.lang.Runtime.exec() with command '$@' with arg from untrusted input '$@'",
34-
sourceCmd, sourceCmd.toString(),
35-
source.getNode(), source.toString()
23+
from
24+
DataFlow::PathNode source, DataFlow::PathNode sink, ExecTaintConfiguration2 conf,
25+
MethodAccess call, DataFlow::Node sourceCmd, DataFlow::Node sinkCmd,
26+
ExecTaintConfiguration confCmd
27+
where
28+
call.getMethod() instanceof RuntimeExecMethod and
29+
// this is a command-accepting call to exec, e.g. rt.exec(new String[]{"/bin/sh", ...})
30+
(
31+
confCmd.hasFlow(sourceCmd, sinkCmd) and
32+
sinkCmd.asExpr() = call.getArgument(0)
33+
) and
34+
// it is tainted by untrusted user input
35+
(
36+
conf.hasFlow(source.getNode(), sink.getNode()) and
37+
sink.getNode().asExpr() = call.getArgument(0)
38+
)
39+
select sink, source, sink,
40+
"Call to dangerous java.lang.Runtime.exec() with command '$@' with arg from untrusted input '$@'",
41+
sourceCmd, sourceCmd.toString(), source.getNode(), source.toString()

0 commit comments

Comments
 (0)