From 299c3e9eed7c3c4be826373203bfbeeeb2d75e7e Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Fri, 8 Nov 2024 15:13:16 +0000 Subject: [PATCH] PS: Add 'powershell/command-injection' query. --- .../CommandInjectionCustomizations.qll | 59 +++++++++++++++++++ .../security/CommandInjectionQuery.qll | 26 ++++++++ .../security/cwe-078/CommandInjection.ql | 25 ++++++++ 3 files changed, 110 insertions(+) create mode 100644 powershell/ql/lib/semmle/code/powershell/security/CommandInjectionCustomizations.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/security/CommandInjectionQuery.qll create mode 100644 powershell/ql/src/queries/security/cwe-078/CommandInjection.ql diff --git a/powershell/ql/lib/semmle/code/powershell/security/CommandInjectionCustomizations.qll b/powershell/ql/lib/semmle/code/powershell/security/CommandInjectionCustomizations.qll new file mode 100644 index 00000000000..5f8ae6701f4 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/security/CommandInjectionCustomizations.qll @@ -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() + } + } +} diff --git a/powershell/ql/lib/semmle/code/powershell/security/CommandInjectionQuery.qll b/powershell/ql/lib/semmle/code/powershell/security/CommandInjectionQuery.qll new file mode 100644 index 00000000000..dd7283d1546 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/security/CommandInjectionQuery.qll @@ -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; diff --git a/powershell/ql/src/queries/security/cwe-078/CommandInjection.ql b/powershell/ql/src/queries/security/cwe-078/CommandInjection.ql new file mode 100644 index 00000000000..ca28bea3aa0 --- /dev/null +++ b/powershell/ql/src/queries/security/cwe-078/CommandInjection.ql @@ -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()