mirror of
https://github.com/github/codeql.git
synced 2026-04-23 15:55:18 +02:00
Formatted
This commit is contained in:
@@ -4,124 +4,103 @@ import semmle.code.java.dataflow.DataFlow
|
||||
private import semmle.code.java.dataflow.TaintTracking
|
||||
import semmle.code.java.dataflow.FlowSources
|
||||
|
||||
|
||||
// a static string of an unsafe executable tainting arg 0 of Runtime.exec()
|
||||
class ExecTaintConfiguration extends TaintTracking::Configuration {
|
||||
ExecTaintConfiguration() { this = "ExecTaintConfiguration" }
|
||||
ExecTaintConfiguration() { this = "ExecTaintConfiguration" }
|
||||
|
||||
override
|
||||
predicate
|
||||
isSource(DataFlow::Node source) {
|
||||
source.asExpr() instanceof StringLiteral
|
||||
and source.asExpr().(StringLiteral).getValue() instanceof UnSafeExecutable
|
||||
}
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
source.asExpr() instanceof StringLiteral and
|
||||
source.asExpr().(StringLiteral).getValue() instanceof UnSafeExecutable
|
||||
}
|
||||
|
||||
override
|
||||
predicate
|
||||
isSink(DataFlow::Node sink) {
|
||||
exists(RuntimeExecMethod method, MethodAccess call |
|
||||
call.getMethod() = method
|
||||
and sink.asExpr() = call.getArgument(0)
|
||||
and sink.asExpr().getType() instanceof Array
|
||||
)
|
||||
}
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
exists(RuntimeExecMethod method, MethodAccess call |
|
||||
call.getMethod() = method and
|
||||
sink.asExpr() = call.getArgument(0) and
|
||||
sink.asExpr().getType() instanceof Array
|
||||
)
|
||||
}
|
||||
|
||||
override
|
||||
predicate
|
||||
isSanitizer(DataFlow::Node node) {
|
||||
node.asExpr().getFile().isSourceFile() and
|
||||
(
|
||||
node instanceof AssignToNonZeroIndex
|
||||
or node instanceof ArrayInitAtNonZeroIndex
|
||||
or node instanceof StreamConcatAtNonZeroIndex
|
||||
or node.getType() instanceof PrimitiveType
|
||||
or node.getType() instanceof BoxedType
|
||||
)
|
||||
}
|
||||
override predicate isSanitizer(DataFlow::Node node) {
|
||||
node.asExpr().getFile().isSourceFile() and
|
||||
(
|
||||
node instanceof AssignToNonZeroIndex or
|
||||
node instanceof ArrayInitAtNonZeroIndex or
|
||||
node instanceof StreamConcatAtNonZeroIndex or
|
||||
node.getType() instanceof PrimitiveType or
|
||||
node.getType() instanceof BoxedType
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
abstract class Source extends DataFlow::Node {
|
||||
Source() {
|
||||
this = this
|
||||
}
|
||||
Source() { this = this }
|
||||
}
|
||||
|
||||
|
||||
// taint flow from user data to args of the command
|
||||
class ExecTaintConfiguration2 extends TaintTracking::Configuration {
|
||||
ExecTaintConfiguration2() { this = "ExecTaintConfiguration2" }
|
||||
ExecTaintConfiguration2() { this = "ExecTaintConfiguration2" }
|
||||
|
||||
override
|
||||
predicate
|
||||
isSource(DataFlow::Node source) {
|
||||
source instanceof Source
|
||||
}
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof Source }
|
||||
|
||||
override
|
||||
predicate
|
||||
isSink(DataFlow::Node sink) {
|
||||
exists(RuntimeExecMethod method, MethodAccess call, int index |
|
||||
call.getMethod() = method
|
||||
and sink.asExpr() = call.getArgument(index)
|
||||
and sink.asExpr().getType() instanceof Array
|
||||
)
|
||||
}
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
exists(RuntimeExecMethod method, MethodAccess call, int index |
|
||||
call.getMethod() = method and
|
||||
sink.asExpr() = call.getArgument(index) and
|
||||
sink.asExpr().getType() instanceof Array
|
||||
)
|
||||
}
|
||||
|
||||
override
|
||||
predicate
|
||||
isSanitizer(DataFlow::Node node) {
|
||||
node.asExpr().getFile().isSourceFile() and
|
||||
(
|
||||
node.getType() instanceof PrimitiveType
|
||||
or node.getType() instanceof BoxedType
|
||||
)
|
||||
}
|
||||
override predicate isSanitizer(DataFlow::Node node) {
|
||||
node.asExpr().getFile().isSourceFile() and
|
||||
(
|
||||
node.getType() instanceof PrimitiveType or
|
||||
node.getType() instanceof BoxedType
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// array[3] = node
|
||||
class AssignToNonZeroIndex extends DataFlow::Node {
|
||||
AssignExpr assign;
|
||||
ArrayAccess access;
|
||||
AssignExpr assign;
|
||||
ArrayAccess access;
|
||||
|
||||
AssignToNonZeroIndex() {
|
||||
assign.getDest() = access
|
||||
and access.getIndexExpr().(IntegerLiteral).getValue() != "0"
|
||||
and assign.getSource() = this.asExpr()
|
||||
}
|
||||
AssignToNonZeroIndex() {
|
||||
assign.getDest() = access and
|
||||
access.getIndexExpr().(IntegerLiteral).getValue() != "0" and
|
||||
assign.getSource() = this.asExpr()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// String[] array = {"a", "b, "c"};
|
||||
class ArrayInitAtNonZeroIndex extends DataFlow::Node {
|
||||
ArrayInit init;
|
||||
int index;
|
||||
ArrayInit init;
|
||||
int index;
|
||||
|
||||
ArrayInitAtNonZeroIndex() {
|
||||
init.getInit(index) = this.asExpr()
|
||||
and index != 0
|
||||
}
|
||||
ArrayInitAtNonZeroIndex() {
|
||||
init.getInit(index) = this.asExpr() and
|
||||
index != 0
|
||||
}
|
||||
}
|
||||
|
||||
// Stream.concat(Arrays.stream(array_1), Arrays.stream(array_2))
|
||||
class StreamConcatAtNonZeroIndex extends DataFlow::Node {
|
||||
MethodAccess call;
|
||||
int index;
|
||||
MethodAccess call;
|
||||
int index;
|
||||
|
||||
StreamConcatAtNonZeroIndex() {
|
||||
call.getMethod().getQualifiedName() = "java.util.stream.Stream.concat"
|
||||
and call.getArgument(index) = this.asExpr()
|
||||
and index != 0
|
||||
}
|
||||
StreamConcatAtNonZeroIndex() {
|
||||
call.getMethod().getQualifiedName() = "java.util.stream.Stream.concat" and
|
||||
call.getArgument(index) = this.asExpr() and
|
||||
index != 0
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// allow list of executables that execute their arguments
|
||||
// TODO: extend with data extensions
|
||||
class UnSafeExecutable extends string {
|
||||
bindingset[this]
|
||||
UnSafeExecutable() {
|
||||
this.regexpMatch("^(|.*/)([a-z]*sh|javac?|python.*|perl|[Pp]ower[Ss]hell|php|node|deno|bun|ruby|osascript|cmd|Rscript|groovy)(\\.exe)?$")
|
||||
and not this.matches("netsh.exe")
|
||||
}
|
||||
bindingset[this]
|
||||
UnSafeExecutable() {
|
||||
this.regexpMatch("^(|.*/)([a-z]*sh|javac?|python.*|perl|[Pp]ower[Ss]hell|php|node|deno|bun|ruby|osascript|cmd|Rscript|groovy)(\\.exe)?$") and
|
||||
not this.matches("netsh.exe")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,24 +12,29 @@
|
||||
* external/cwe/cwe-078
|
||||
*/
|
||||
|
||||
|
||||
import DataFlow::PathGraph
|
||||
import CommandInjectionRuntimeExec
|
||||
|
||||
class LocalSource extends Source { LocalSource() { this instanceof LocalUserInput } }
|
||||
class LocalSource extends Source {
|
||||
LocalSource() { this instanceof LocalUserInput }
|
||||
}
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, ExecTaintConfiguration2 conf, MethodAccess call, DataFlow::Node sourceCmd, DataFlow::Node sinkCmd, ExecTaintConfiguration confCmd
|
||||
where call.getMethod() instanceof RuntimeExecMethod
|
||||
// this is a command-accepting call to exec, e.g. rt.exec(new String[]{"/bin/sh", ...})
|
||||
and (
|
||||
confCmd.hasFlow(sourceCmd, sinkCmd)
|
||||
and sinkCmd.asExpr() = call.getArgument(0)
|
||||
)
|
||||
// it is tainted by untrusted user input
|
||||
and (
|
||||
conf.hasFlow(source.getNode(), sink.getNode())
|
||||
and sink.getNode().asExpr() = call.getArgument(0)
|
||||
)
|
||||
select sink, source, sink, "Call to dangerous java.lang.Runtime.exec() with command '$@' with arg from untrusted input '$@'",
|
||||
sourceCmd, sourceCmd.toString(),
|
||||
source.getNode(), source.toString()
|
||||
from
|
||||
DataFlow::PathNode source, DataFlow::PathNode sink, ExecTaintConfiguration2 conf,
|
||||
MethodAccess call, DataFlow::Node sourceCmd, DataFlow::Node sinkCmd,
|
||||
ExecTaintConfiguration confCmd
|
||||
where
|
||||
call.getMethod() instanceof RuntimeExecMethod and
|
||||
// this is a command-accepting call to exec, e.g. rt.exec(new String[]{"/bin/sh", ...})
|
||||
(
|
||||
confCmd.hasFlow(sourceCmd, sinkCmd) and
|
||||
sinkCmd.asExpr() = call.getArgument(0)
|
||||
) and
|
||||
// it is tainted by untrusted user input
|
||||
(
|
||||
conf.hasFlow(source.getNode(), sink.getNode()) and
|
||||
sink.getNode().asExpr() = call.getArgument(0)
|
||||
)
|
||||
select sink, source, sink,
|
||||
"Call to dangerous java.lang.Runtime.exec() with command '$@' with arg from untrusted input '$@'",
|
||||
sourceCmd, sourceCmd.toString(), source.getNode(), source.toString()
|
||||
|
||||
@@ -13,23 +13,27 @@
|
||||
* external/cwe/cwe-078
|
||||
*/
|
||||
|
||||
|
||||
import CommandInjectionRuntimeExec
|
||||
|
||||
class DataSource extends Source { DataSource() { this instanceof RemoteFlowSource or this instanceof LocalUserInput } }
|
||||
class DataSource extends Source {
|
||||
DataSource() { this instanceof RemoteFlowSource or this instanceof LocalUserInput }
|
||||
}
|
||||
|
||||
from DataFlow::Node source, DataFlow::Node sink, ExecTaintConfiguration2 conf, MethodAccess call, int index, DataFlow::Node sourceCmd, DataFlow::Node sinkCmd, ExecTaintConfiguration confCmd
|
||||
where call.getMethod() instanceof RuntimeExecMethod
|
||||
// this is a command-accepting call to exec, e.g. exec("/bin/sh", ...)
|
||||
and (
|
||||
confCmd.hasFlow(sourceCmd, sinkCmd)
|
||||
and sinkCmd.asExpr() = call.getArgument(0)
|
||||
)
|
||||
// it is tainted by untrusted user input
|
||||
and (
|
||||
conf.hasFlow(source, sink)
|
||||
and sink.asExpr() = call.getArgument(index)
|
||||
)
|
||||
select sink, "Call to dangerous java.lang.Runtime.exec() with command '$@' with arg from untrusted input '$@'",
|
||||
sourceCmd, sourceCmd.toString(),
|
||||
source, source.toString()
|
||||
from
|
||||
DataFlow::Node source, DataFlow::Node sink, ExecTaintConfiguration2 conf, MethodAccess call,
|
||||
int index, DataFlow::Node sourceCmd, DataFlow::Node sinkCmd, ExecTaintConfiguration confCmd
|
||||
where
|
||||
call.getMethod() instanceof RuntimeExecMethod and
|
||||
// this is a command-accepting call to exec, e.g. exec("/bin/sh", ...)
|
||||
(
|
||||
confCmd.hasFlow(sourceCmd, sinkCmd) and
|
||||
sinkCmd.asExpr() = call.getArgument(0)
|
||||
) and
|
||||
// it is tainted by untrusted user input
|
||||
(
|
||||
conf.hasFlow(source, sink) and
|
||||
sink.asExpr() = call.getArgument(index)
|
||||
)
|
||||
select sink,
|
||||
"Call to dangerous java.lang.Runtime.exec() with command '$@' with arg from untrusted input '$@'",
|
||||
sourceCmd, sourceCmd.toString(), source, source.toString()
|
||||
|
||||
@@ -16,20 +16,26 @@
|
||||
import DataFlow::PathGraph
|
||||
import CommandInjectionRuntimeExec
|
||||
|
||||
class DataSource extends Source { DataSource() { this instanceof RemoteFlowSource or this instanceof LocalUserInput } }
|
||||
class DataSource extends Source {
|
||||
DataSource() { this instanceof RemoteFlowSource or this instanceof LocalUserInput }
|
||||
}
|
||||
|
||||
from DataFlow::PathNode source, DataFlow::PathNode sink, ExecTaintConfiguration2 conf, MethodAccess call, DataFlow::Node sourceCmd, DataFlow::Node sinkCmd, ExecTaintConfiguration confCmd
|
||||
where call.getMethod() instanceof RuntimeExecMethod
|
||||
// this is a command-accepting call to exec, e.g. rt.exec(new String[]{"/bin/sh", ...})
|
||||
and (
|
||||
confCmd.hasFlow(sourceCmd, sinkCmd)
|
||||
and sinkCmd.asExpr() = call.getArgument(0)
|
||||
)
|
||||
// it is tainted by untrusted user input
|
||||
and (
|
||||
conf.hasFlow(source.getNode(), sink.getNode())
|
||||
and sink.getNode().asExpr() = call.getArgument(0)
|
||||
)
|
||||
select sink, source, sink, "Call to dangerous java.lang.Runtime.exec() with command '$@' with arg from untrusted input '$@'",
|
||||
sourceCmd, sourceCmd.toString(),
|
||||
source.getNode(), source.toString()
|
||||
from
|
||||
DataFlow::PathNode source, DataFlow::PathNode sink, ExecTaintConfiguration2 conf,
|
||||
MethodAccess call, DataFlow::Node sourceCmd, DataFlow::Node sinkCmd,
|
||||
ExecTaintConfiguration confCmd
|
||||
where
|
||||
call.getMethod() instanceof RuntimeExecMethod and
|
||||
// this is a command-accepting call to exec, e.g. rt.exec(new String[]{"/bin/sh", ...})
|
||||
(
|
||||
confCmd.hasFlow(sourceCmd, sinkCmd) and
|
||||
sinkCmd.asExpr() = call.getArgument(0)
|
||||
) and
|
||||
// it is tainted by untrusted user input
|
||||
(
|
||||
conf.hasFlow(source.getNode(), sink.getNode()) and
|
||||
sink.getNode().asExpr() = call.getArgument(0)
|
||||
)
|
||||
select sink, source, sink,
|
||||
"Call to dangerous java.lang.Runtime.exec() with command '$@' with arg from untrusted input '$@'",
|
||||
sourceCmd, sourceCmd.toString(), source.getNode(), source.toString()
|
||||
|
||||
Reference in New Issue
Block a user