feat: add codeql exec wrapper sinks (#3037)

* add codeql exec wrapper sinks

* test codeql detection

* Revert "test codeql detection"

This reverts commit 539c9051f2.
This commit is contained in:
Alexander 2024-10-07 17:07:03 -07:00 коммит произвёл GitHub
Родитель f7f98d4fcb
Коммит 055577d858
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
5 изменённых файлов: 43 добавлений и 52 удалений

Просмотреть файл

@ -11,18 +11,7 @@
// Detect inputs from CNS add ipam result / CNS multitenancy ipam add result to command injection
import go
private class Sink extends DataFlow2::Node {
Sink() {
exists(DataFlow::CallNode c |
c.getTarget().hasQualifiedName("os/exec", "CommandContext") and
(c.getArgument(2) = this or c.getArgument(1) = this)
or
c.getTarget().hasQualifiedName("os/exec", "Command") and
(c.getArgument(0) = this or c.getArgument(1) = this)
)
}
}
import lib.ACN
private class Source extends DataFlow2::Node {
Source() {
@ -38,7 +27,7 @@ private class Source extends DataFlow2::Node {
}
module MyConfiguration implements DataFlow::ConfigSig {
predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
predicate isSink(DataFlow::Node sink) { sink instanceof ACN::CommandSink }
predicate isSource(DataFlow::Node source) { source instanceof Source }
}

Просмотреть файл

@ -11,18 +11,7 @@
// Detect inputs from CNI ARGS to command injection
import go
private class Sink extends DataFlow2::Node {
Sink() {
exists(DataFlow::CallNode c |
c.getTarget().hasQualifiedName("os/exec", "CommandContext") and
(c.getArgument(2) = this or c.getArgument(1) = this)
or
c.getTarget().hasQualifiedName("os/exec", "Command") and
(c.getArgument(0) = this or c.getArgument(1) = this)
)
}
}
import lib.ACN
private class Source extends DataFlow2::Node {
Source() {
@ -44,7 +33,7 @@ private class Source extends DataFlow2::Node {
}
module MyConfiguration implements DataFlow::ConfigSig {
predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
predicate isSink(DataFlow::Node sink) { sink instanceof ACN::CommandSink }
predicate isSource(DataFlow::Node source) { source instanceof Source }
}

Просмотреть файл

@ -12,18 +12,7 @@
// Detect inputs from CNS Invoker to command injection
// Does not detect flow to outside the enclosed method (which is why we analyze addIpamInvoker's results too)
import go
private class Sink extends DataFlow2::Node {
Sink() {
exists(DataFlow::CallNode c |
c.getTarget().hasQualifiedName("os/exec", "CommandContext") and
(c.getArgument(2) = this or c.getArgument(1) = this)
or
c.getTarget().hasQualifiedName("os/exec", "Command") and
(c.getArgument(0) = this or c.getArgument(1) = this)
)
}
}
import lib.ACN
private class Source extends DataFlow2::Node {
Source() {
@ -45,7 +34,7 @@ private class Source extends DataFlow2::Node {
}
module MyConfiguration implements DataFlow::ConfigSig {
predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
predicate isSink(DataFlow::Node sink) { sink instanceof ACN::CommandSink }
predicate isSource(DataFlow::Node source) { source instanceof Source }
}

Просмотреть файл

@ -11,18 +11,7 @@
// Detect flow from the DECODE method (which decodes http requests) to a command execution
import go
private class Sink extends DataFlow2::Node {
Sink() {
exists(DataFlow::CallNode c |
c.getTarget().hasQualifiedName("os/exec", "CommandContext") and
(c.getArgument(2) = this or c.getArgument(1) = this)
or
c.getTarget().hasQualifiedName("os/exec", "Command") and
(c.getArgument(0) = this or c.getArgument(1) = this)
)
}
}
import lib.ACN
private class Source extends DataFlow2::Node {
Source() {
@ -34,7 +23,7 @@ private class Source extends DataFlow2::Node {
}
module MyConfiguration implements DataFlow::ConfigSig {
predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
predicate isSink(DataFlow::Node sink) { sink instanceof ACN::CommandSink }
predicate isSource(DataFlow::Node source) { source instanceof Source }
}

35
codeql/lib/ACN.qll Normal file
Просмотреть файл

@ -0,0 +1,35 @@
import go
module ACN {
class CommandSink extends DataFlow2::Node {
CommandSink() {
exists(DataFlow::CallNode c, Method m |
(
// Detect dangerous usage of command wrappers with the command in the 0th arg position
(
m.hasQualifiedName("github.com/Azure/azure-container-networking/platform", "execClient",
"ExecuteRawCommand") or
m.hasQualifiedName("github.com/Azure/azure-container-networking/platform", "execClient",
"ExecutePowershellCommand")
) and
c.getArgument(0) = this
or
// Detect dangerous usage of command wrappers with the command in the 1st arg position
m.hasQualifiedName("github.com/Azure/azure-container-networking/platform", "execClient",
"ExecutePowershellCommandWithContext") and
c.getArgument(1) = this
) and
c = m.getACall()
or
// Detect dangerous calls directly to os exec
(
c.getTarget().hasQualifiedName("os/exec", "CommandContext") and
(c.getArgument(2) = this or c.getArgument(1) = this)
or
c.getTarget().hasQualifiedName("os/exec", "Command") and
(c.getArgument(0) = this or c.getArgument(1) = this)
)
)
}
}
}