JS: add SystemCommandExecution::isShellInterpreted

This commit is contained in:
Esben Sparre Andreasen
2019-10-04 11:20:22 +02:00
parent 9995c12132
commit 80a32aebc1
4 changed files with 59 additions and 24 deletions

View File

@@ -14,6 +14,9 @@ abstract class SystemCommandExecution extends DataFlow::Node {
/** Gets an argument to this execution that specifies the command. */
abstract DataFlow::Node getACommandArgument();
/** Holds if a shell interprets `arg`. */
predicate isShellInterpreted(DataFlow::Node arg) { none() }
/**
* Gets an argument to this command execution that specifies the argument list
* to the command.

View File

@@ -573,21 +573,32 @@ module NodeJSLib {
this = DataFlow::moduleMember("child_process", methodName).getACall()
}
override DataFlow::Node getACommandArgument() {
private DataFlow::Node getACommandArgument(boolean shell) {
// check whether this is an invocation of an exec/spawn/fork method
(
methodName = "exec" or
methodName = "execSync" or
methodName = "execFile" or
methodName = "execFileSync" or
methodName = "spawn" or
methodName = "spawnSync" or
methodName = "fork"
shell = true and
(
methodName = "exec" or
methodName = "execSync"
)
or
shell = false and
(
methodName = "execFile" or
methodName = "execFileSync" or
methodName = "spawn" or
methodName = "spawnSync" or
methodName = "fork"
)
) and
// all of the above methods take the command as their first argument
result = getArgument(0)
}
override DataFlow::Node getACommandArgument() { result = getACommandArgument(_) }
override predicate isShellInterpreted(DataFlow::Node arg) { arg = getACommandArgument(true) }
override DataFlow::Node getArgumentList() {
(
methodName = "execFile" or

View File

@@ -158,6 +158,8 @@ module ShellJS {
ShellJSExec() { name = "exec" }
override DataFlow::Node getACommandArgument() { result = getArgument(0) }
override predicate isShellInterpreted(DataFlow::Node arg) { arg = getACommandArgument() }
}
/**

View File

@@ -8,18 +8,26 @@ import javascript
private class SystemCommandExecutors extends SystemCommandExecution, DataFlow::InvokeNode {
int cmdArg;
boolean shell;
SystemCommandExecutors() {
exists(string mod, DataFlow::SourceNode callee |
exists(string method |
mod = "cross-spawn" and method = "sync" and cmdArg = 0
mod = "cross-spawn" and method = "sync" and cmdArg = 0 and shell = false
or
mod = "execa" and
(
method = "shell" or
method = "shellSync" or
method = "stdout" or
method = "stderr" or
method = "sync"
shell = false and
(
method = "shell" or
method = "shellSync" or
method = "stdout" or
method = "stderr" or
method = "sync"
)
or
shell = true and
(method = "command" or method = "commandSync")
) and
cmdArg = 0
|
@@ -27,17 +35,24 @@ private class SystemCommandExecutors extends SystemCommandExecution, DataFlow::I
)
or
(
mod = "cross-spawn" and cmdArg = 0
shell = false and
(
mod = "cross-spawn" and cmdArg = 0
or
mod = "cross-spawn-async" and cmdArg = 0
or
mod = "exec-async" and cmdArg = 0
or
mod = "execa" and cmdArg = 0
)
or
mod = "cross-spawn-async" and cmdArg = 0
or
mod = "exec" and cmdArg = 0
or
mod = "exec-async" and cmdArg = 0
or
mod = "execa" and cmdArg = 0
or
mod = "remote-exec" and cmdArg = 1
shell = true and
(
mod = "exec" and
cmdArg = 0
or
mod = "remote-exec" and cmdArg = 1
)
) and
callee = DataFlow::moduleImport(mod)
|
@@ -46,4 +61,8 @@ private class SystemCommandExecutors extends SystemCommandExecution, DataFlow::I
}
override DataFlow::Node getACommandArgument() { result = getArgument(cmdArg) }
override predicate isShellInterpreted(DataFlow::Node arg) {
arg = getACommandArgument() and shell = true
}
}