PS: Add 'powershell/command-injection' query.

This commit is contained in:
Mathias Vorreiter Pedersen
2024-11-08 15:13:16 +00:00
parent 0fb75afd33
commit 299c3e9eed
3 changed files with 110 additions and 0 deletions

View File

@@ -0,0 +1,59 @@
/**
* Provides default sources, sinks and sanitizers for reasoning about
* command-injection vulnerabilities, as well as extension points for
* adding your own.
*/
private import semmle.code.powershell.dataflow.DataFlow
private import semmle.code.powershell.dataflow.flowsources.FlowSources
private import semmle.code.powershell.Cfg
module CommandInjection {
/**
* A data flow source for command-injection vulnerabilities.
*/
abstract class Source extends DataFlow::Node {
/** Gets a string that describes the type of this flow source. */
abstract string getSourceType();
}
/**
* A data flow sink for command-injection vulnerabilities.
*/
abstract class Sink extends DataFlow::Node { }
/**
* A sanitizer for command-injection vulnerabilities.
*/
abstract class Sanitizer extends DataFlow::Node { }
/** A source of user input, considered as a flow source for command injection. */
class FlowSourceAsSource extends Source instanceof SourceNode {
override string getSourceType() { result = "user-provided value" }
}
/**
* A command argument to a function that initiates an operating system command.
*/
class SystemCommandExecutionSink extends Sink {
SystemCommandExecutionSink() {
// An argument to a call
exists(DataFlow::CallNode call |
call.getName() = "Invoke-Expression"
or
call instanceof DataFlow::CallOperatorNode
|
call.getAnArgument() = this
)
or
// Or the call command itself in case it's a use of operator &.
any(DataFlow::CallOperatorNode call).getCommand() = this
}
}
private class ExternalCommandInjectionSink extends Sink {
ExternalCommandInjectionSink() {
this = ModelOutput::getASinkNode("command-injection").asSink()
}
}
}

View File

@@ -0,0 +1,26 @@
/**
* Provides a taint tracking configuration for reasoning about
* command-injection vulnerabilities (CWE-078).
*
* Note, for performance reasons: only import this file if
* `CommandInjectionFlow` is needed, otherwise
* `CommandInjectionCustomizations` should be imported instead.
*/
import powershell
import semmle.code.powershell.dataflow.TaintTracking
import CommandInjectionCustomizations::CommandInjection
import semmle.code.powershell.dataflow.DataFlow
private module Config implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node source) { source instanceof Source }
predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
predicate isBarrier(DataFlow::Node node) { node instanceof Sanitizer }
}
/**
* Taint-tracking for reasoning about command-injection vulnerabilities.
*/
module CommandInjectionFlow = TaintTracking::Global<Config>;

View File

@@ -0,0 +1,25 @@
/**
* @name Uncontrolled command line
* @description Using externally controlled strings in a command line may allow a malicious
* user to change the meaning of the command.
* @kind path-problem
* @problem.severity error
* @security-severity 9.8
* @precision high
* @id powershell/command-injection
* @tags correctness
* security
* external/cwe/cwe-078
* external/cwe/cwe-088
*/
import powershell
import semmle.code.powershell.security.CommandInjectionQuery
import CommandInjectionFlow::PathGraph
from CommandInjectionFlow::PathNode source, CommandInjectionFlow::PathNode sink, Source sourceNode
where
CommandInjectionFlow::flowPath(source, sink) and
sourceNode = source.getNode()
select sink.getNode(), source, sink, "This command depends on a $@.", sourceNode,
sourceNode.getSourceType()