From ed553d393b7bbe6c80974a07fb72c84aa9c287ab Mon Sep 17 00:00:00 2001
From: Chanel Young
Date: Wed, 16 Apr 2025 14:32:30 -0700
Subject: [PATCH] merged work into CommandInjection query
---
.../CommandInjectionCustomizations.qll | 168 ++++++++++++-
.../security/cwe-078/CommandInjection.qhelp | 20 +-
.../cwe-078/InjectionHunter/Sanitizers.qll | 26 ---
.../cwe-078/InjectionHunter/Sinks.qll | 152 ------------
.../UserInputToDangerousMethod.qhelp | 48 ----
.../UserInputToDangerousMethod.ql | 36 ---
.../cwe-078/CommandInjection/test.ps1 | 211 ++++++++++++++++-
.../InjectionHunter/InjectionHunter.expected | 146 ------------
.../InjectionHunter/InjectionHunter.qlref | 1 -
.../security/cwe-078/InjectionHunter/test.ps1 | 221 ------------------
10 files changed, 392 insertions(+), 637 deletions(-)
delete mode 100644 powershell/ql/src/queries/security/cwe-078/InjectionHunter/Sanitizers.qll
delete mode 100644 powershell/ql/src/queries/security/cwe-078/InjectionHunter/Sinks.qll
delete mode 100644 powershell/ql/src/queries/security/cwe-078/InjectionHunter/UserInputToDangerousMethod.qhelp
delete mode 100644 powershell/ql/src/queries/security/cwe-078/InjectionHunter/UserInputToDangerousMethod.ql
delete mode 100644 powershell/ql/test/query-tests/security/cwe-078/InjectionHunter/InjectionHunter.expected
delete mode 100644 powershell/ql/test/query-tests/security/cwe-078/InjectionHunter/InjectionHunter.qlref
delete mode 100644 powershell/ql/test/query-tests/security/cwe-078/InjectionHunter/test.ps1
diff --git a/powershell/ql/lib/semmle/code/powershell/security/CommandInjectionCustomizations.qll b/powershell/ql/lib/semmle/code/powershell/security/CommandInjectionCustomizations.qll
index 1623941fb82..a75fd0028ca 100644
--- a/powershell/ql/lib/semmle/code/powershell/security/CommandInjectionCustomizations.qll
+++ b/powershell/ql/lib/semmle/code/powershell/security/CommandInjectionCustomizations.qll
@@ -5,6 +5,7 @@
*/
private import semmle.code.powershell.dataflow.DataFlow
+import semmle.code.powershell.ApiGraphs
private import semmle.code.powershell.dataflow.flowsources.FlowSources
private import semmle.code.powershell.Cfg
@@ -20,7 +21,9 @@ module CommandInjection {
/**
* A data flow sink for command-injection vulnerabilities.
*/
- abstract class Sink extends DataFlow::Node { }
+ abstract class Sink extends DataFlow::Node {
+ abstract string getSinkType();
+ }
/**
* A sanitizer for command-injection vulnerabilities.
@@ -39,13 +42,16 @@ module CommandInjection {
SystemCommandExecutionSink() {
// An argument to a call
exists(DataFlow::CallNode call |
- call.getName() = "Invoke-Expression" and
+ call.getName() = ["Invoke-Expression", "iex"] and
call.getAnArgument() = this
)
or
// Or the call command itself in case it's a use of operator &.
any(DataFlow::CallOperatorNode call).getCommand() = this
}
+ override string getSinkType() {
+ result = "call to Invoke-Expression"
+ }
}
class AddTypeSink extends Sink {
@@ -55,11 +61,169 @@ module CommandInjection {
call.getAnArgument() = this
)
}
+ override string getSinkType() {
+ result = "call to Add-Type"
+ }
}
+ class InvokeScriptSink extends Sink {
+ InvokeScriptSink() {
+ exists(API::Node call |
+ API::getTopLevelMember("executioncontext").getMember("invokecommand").getMethod("invokescript") = call and
+ this = call.getArgument(_).asSink()
+ )
+ }
+ override string getSinkType(){
+ result = "call to InvokeScript"
+ }
+}
+
+class CreateNestedPipelineSink extends Sink {
+ CreateNestedPipelineSink() {
+ exists(API::Node call |
+ API::getTopLevelMember("host").getMember("runspace").getMethod("createnestedpipeline") = call and
+ this = call.getArgument(_).asSink()
+ )
+ }
+ override string getSinkType(){
+ result = "call to CreateNestedPipeline"
+ }
+}
+
+class AddScriptInvokeSink extends Sink {
+ AddScriptInvokeSink() {
+ exists(InvokeMemberExpr ie |
+ this.asExpr().getExpr() = ie.getAnArgument() and
+ ie.getName() = "AddScript" and
+ ie.getQualifier().(InvokeMemberExpr).getName() = "Create" and
+ ie.getQualifier().getAChild().toString() = "PowerShell" and
+ ie.getParent().(InvokeMemberExpr).getName() = "Invoke"
+ )
+ }
+ override string getSinkType(){
+ result = "call to AddScript"
+ }
+}
+
+class PowershellSink extends Sink {
+ PowershellSink() {
+ exists( CmdCall c |
+ c.getName() = "powershell" |
+ (
+ this.asExpr().getExpr() = c.getArgument(1) and
+ c.getArgument(0).getValue().toString() = "-command"
+ ) or
+ (
+ this.asExpr().getExpr() = c.getArgument(0)
+ )
+ )
+ }
+ override string getSinkType(){
+ result = "call to Powershell"
+ }
+}
+
+class CmdSink extends Sink {
+ CmdSink() {
+ exists(CmdCall c |
+ this.asExpr().getExpr() = c.getArgument(1) and
+ c.getName() = "cmd" and
+ c.getArgument(0).getValue().toString() = "/c"
+ )
+ }
+ override string getSinkType(){
+ result = "call to Cmd"
+ }
+}
+
+class ForEachObjectSink extends Sink {
+ ForEachObjectSink() {
+ exists(CmdCall c |
+ this.asExpr().getExpr() = c.getAnArgument() and
+ c.getName() = "Foreach-Object"
+ )
+ }
+ override string getSinkType(){
+ result = "call to ForEach-Object"
+ }
+}
+
+class InvokeSink extends Sink {
+ InvokeSink() {
+ exists(InvokeMemberExpr ie |
+ this.asExpr().getExpr() = ie.getCallee() or
+ this.asExpr().getExpr() = ie.getQualifier().getAChild*()
+ )
+ }
+ override string getSinkType(){
+ result = "call to Invoke"
+ }
+}
+
+class CreateScriptBlockSink extends Sink {
+ CreateScriptBlockSink() {
+ exists(InvokeMemberExpr ie |
+ this.asExpr().getExpr() = ie.getAnArgument() and
+ ie.getName() = "Create" and
+ ie.getQualifier().toString() = "ScriptBlock"
+ )
+ }
+ override string getSinkType(){
+ result = "call to CreateScriptBlock"
+ }
+}
+
+class NewScriptBlockSink extends Sink {
+ NewScriptBlockSink() {
+ exists(API::Node call |
+ API::getTopLevelMember("executioncontext").getMember("invokecommand").getMethod("newscriptblock") = call and
+ this = call.getArgument(_).asSink()
+ )
+ }
+ override string getSinkType(){
+ result = "call to NewScriptBlock"
+ }
+}
+
+class ExpandStringSink extends Sink {
+ ExpandStringSink() {
+ exists(API::Node call | this = call.getArgument(_).asSink() |
+ API::getTopLevelMember("executioncontext").getMember("invokecommand").getMethod("expandstring") = call or
+ API::getTopLevelMember("executioncontext").getMember("sessionstate").getMember("invokecommand").getMethod("expandstring") = call
+
+ )
+ }
+ override string getSinkType(){
+ result = "call to ExpandString"
+ }
+}
+
private class ExternalCommandInjectionSink extends Sink {
ExternalCommandInjectionSink() {
this = ModelOutput::getASinkNode("command-injection").asSink()
}
+ override string getSinkType() {
+ result = "external command injection"
+ }
+ }
+
+ class TypedParameterSanitizer extends Sanitizer {
+ TypedParameterSanitizer() {
+ exists(Function f, Parameter p |
+ p = f.getAParameter() and
+ p.getStaticType() != "Object" and
+ this.asParameter() = p
+ )
+ }
+ }
+
+ class SingleQuoteSanitizer extends Sanitizer {
+ SingleQuoteSanitizer() {
+ exists(Expr e, VarReadAccess v |
+ e = this.asExpr().getExpr().getParent() and
+ e.toString().matches("%'$" + v.getVariable().getName() + "'%")
+ )
+ }
}
}
+
diff --git a/powershell/ql/src/queries/security/cwe-078/CommandInjection.qhelp b/powershell/ql/src/queries/security/cwe-078/CommandInjection.qhelp
index b75401a5d70..e89985142d9 100644
--- a/powershell/ql/src/queries/security/cwe-078/CommandInjection.qhelp
+++ b/powershell/ql/src/queries/security/cwe-078/CommandInjection.qhelp
@@ -8,6 +8,21 @@
routine that executes a command, allows the user to execute malicious
code.
+The following are considered dangerous sinks:
+
+ - Invoke-Expression
+ - InvokeScript
+ - CreateNestedPipeline
+ - AddScript
+ - powershell
+ - cmd
+ - Foreach-Object
+ - Invoke
+ - CreateScriptBlock
+ - NewScriptBlock
+ - ExpandString
+
+
@@ -36,7 +51,10 @@ without examining it first.
OWASP:
Command Injection.
-
+
+Injection Hunter:
+PowerShell Injection Hunter: Security Auditing for PowerShell Scripts.
+
diff --git a/powershell/ql/src/queries/security/cwe-078/InjectionHunter/Sanitizers.qll b/powershell/ql/src/queries/security/cwe-078/InjectionHunter/Sanitizers.qll
deleted file mode 100644
index ac635928e10..00000000000
--- a/powershell/ql/src/queries/security/cwe-078/InjectionHunter/Sanitizers.qll
+++ /dev/null
@@ -1,26 +0,0 @@
-import powershell
-import semmle.code.powershell.dataflow.TaintTracking
-import semmle.code.powershell.dataflow.DataFlow
-import semmle.code.powershell.ApiGraphs
-
-
-abstract class Sanitizer extends DataFlow::Node {}
-
-class TypedParameterSanitizer extends Sanitizer {
- TypedParameterSanitizer() {
- exists(Function f, Parameter p |
- p = f.getAParameter() and
- p.getStaticType() != "Object" and
- this.asParameter() = p
- )
- }
-}
-
-class SingleQuoteSanitizer extends Sanitizer {
- SingleQuoteSanitizer() {
- exists(Expr e, VarReadAccess v |
- e = this.asExpr().getExpr().getParent() and
- e.toString().matches("%'$" + v.getVariable().getName() + "'%")
- )
- }
-}
diff --git a/powershell/ql/src/queries/security/cwe-078/InjectionHunter/Sinks.qll b/powershell/ql/src/queries/security/cwe-078/InjectionHunter/Sinks.qll
deleted file mode 100644
index 4c62966746f..00000000000
--- a/powershell/ql/src/queries/security/cwe-078/InjectionHunter/Sinks.qll
+++ /dev/null
@@ -1,152 +0,0 @@
-import powershell
-import semmle.code.powershell.dataflow.TaintTracking
-import semmle.code.powershell.dataflow.DataFlow
-import semmle.code.powershell.ApiGraphs
-import semmle.code.powershell.dataflow.flowsources.FlowSources
-
-abstract class InjectionSink extends DataFlow::Node {
- abstract string getSinkType();
-}
-
-class InvokeExpressionCall extends InjectionSink {
- InvokeExpressionCall() {
- exists(CmdCall c |
- this.asExpr().getExpr() = c.getAnArgument() and
- c.getName() = ["Invoke-Expression", "iex", "Add-Type" ] )
- }
- override string getSinkType(){
- result = "call to Invoke-Expression"
- }
-}
-
-class InvokeScriptSink extends InjectionSink {
- InvokeScriptSink() {
- exists(API::Node call |
- API::getTopLevelMember("executioncontext").getMember("invokecommand").getMethod("invokescript") = call and
- this = call.getArgument(_).asSink()
- )
- }
- override string getSinkType(){
- result = "call to InvokeScript"
- }
-}
-
-class CreateNestedPipelineSink extends InjectionSink {
- CreateNestedPipelineSink() {
- exists(API::Node call |
- API::getTopLevelMember("host").getMember("runspace").getMethod("createnestedpipeline") = call and
- this = call.getArgument(_).asSink()
- )
- }
- override string getSinkType(){
- result = "call to CreateNestedPipeline"
- }
-}
-
-class AddScriptInvokeSink extends InjectionSink {
- AddScriptInvokeSink() {
- exists(InvokeMemberExpr ie |
- this.asExpr().getExpr() = ie.getAnArgument() and
- ie.getName() = "AddScript" and
- ie.getQualifier().(InvokeMemberExpr).getName() = "Create" and
- ie.getQualifier().getAChild().toString() = "PowerShell" and
- ie.getParent().(InvokeMemberExpr).getName() = "Invoke"
- )
- }
- override string getSinkType(){
- result = "call to AddScript"
- }
-}
-
-class PowershellSink extends InjectionSink {
- PowershellSink() {
- exists( CmdCall c |
- c.getName() = "powershell" |
- (
- this.asExpr().getExpr() = c.getArgument(1) and
- c.getArgument(0).getValue().toString() = "-command"
- ) or
- (
- this.asExpr().getExpr() = c.getArgument(0)
- )
- )
- }
- override string getSinkType(){
- result = "call to Powershell"
- }
-}
-
-class CmdSink extends InjectionSink {
- CmdSink() {
- exists(CmdCall c |
- this.asExpr().getExpr() = c.getArgument(1) and
- c.getName() = "cmd" and
- c.getArgument(0).getValue().toString() = "/c"
- )
- }
- override string getSinkType(){
- result = "call to Cmd"
- }
-}
-
-class ForEachObjectSink extends InjectionSink {
- ForEachObjectSink() {
- exists(CmdCall c |
- this.asExpr().getExpr() = c.getAnArgument() and
- c.getName() = "Foreach-Object"
- )
- }
- override string getSinkType(){
- result = "call to ForEach-Object"
- }
-}
-
-class InvokeSink extends InjectionSink {
- InvokeSink() {
- exists(InvokeMemberExpr ie |
- this.asExpr().getExpr() = ie.getCallee() or
- this.asExpr().getExpr() = ie.getQualifier().getAChild*()
- )
- }
- override string getSinkType(){
- result = "call to Invoke"
- }
-}
-
-class CreateScriptBlockSink extends InjectionSink {
- CreateScriptBlockSink() {
- exists(InvokeMemberExpr ie |
- this.asExpr().getExpr() = ie.getAnArgument() and
- ie.getName() = "Create" and
- ie.getQualifier().toString() = "ScriptBlock"
- )
- }
- override string getSinkType(){
- result = "call to CreateScriptBlock"
- }
-}
-
-class NewScriptBlockSink extends InjectionSink {
- NewScriptBlockSink() {
- exists(API::Node call |
- API::getTopLevelMember("executioncontext").getMember("invokecommand").getMethod("newscriptblock") = call and
- this = call.getArgument(_).asSink()
- )
- }
- override string getSinkType(){
- result = "call to NewScriptBlock"
- }
-}
-
-class ExpandStringSink extends InjectionSink {
- ExpandStringSink() {
- exists(API::Node call | this = call.getArgument(_).asSink() |
- API::getTopLevelMember("executioncontext").getMember("invokecommand").getMethod("expandstring") = call or
- API::getTopLevelMember("executioncontext").getMember("sessionstate").getMember("invokecommand").getMethod("expandstring") = call
-
- )
- }
- override string getSinkType(){
- result = "call to ExpandString"
- }
-}
\ No newline at end of file
diff --git a/powershell/ql/src/queries/security/cwe-078/InjectionHunter/UserInputToDangerousMethod.qhelp b/powershell/ql/src/queries/security/cwe-078/InjectionHunter/UserInputToDangerousMethod.qhelp
deleted file mode 100644
index de459c2e84f..00000000000
--- a/powershell/ql/src/queries/security/cwe-078/InjectionHunter/UserInputToDangerousMethod.qhelp
+++ /dev/null
@@ -1,48 +0,0 @@
-
-
-
-Code that passes user input directly to
-Invoke-Expression, &, or some other library
-routine that executes a command, allows the user to execute malicious
-code.
-
-This is a port of the InjectionHunter tool by Lee Holmes, and checks when user input is passed to any of the following:
-
- - Invoke-Expression
- - InvokeScript
- - CreateNestedPipeline
- - AddScript
- - powershell
- - cmd
- - Foreach-Object
- - Invoke
- - CreateScriptBlock
- - NewScriptBlock
- - ExpandString
-
-
-
-
-
-Possible script injection risk. Untrusted input can cause arbitrary PowerShell expressions to be run.
-Variables may be used directly for dynamic parameter arguments, splatting can be used for dynamic parameter names,
-and the invocation operator can be used for dynamic command names. If content escaping is truly needed, PowerShell has several valid quote characters,
-so [System.Management.Automation.Language.CodeGeneration]::Escape* should be used.
-
-
-
-
-
-
-OWASP:
-Command Injection.
-
-
-Injection Hunter:
-PowerShell Injection Hunter: Security Auditing for PowerShell Scripts.
-
-
-
-
diff --git a/powershell/ql/src/queries/security/cwe-078/InjectionHunter/UserInputToDangerousMethod.ql b/powershell/ql/src/queries/security/cwe-078/InjectionHunter/UserInputToDangerousMethod.ql
deleted file mode 100644
index 11730a65299..00000000000
--- a/powershell/ql/src/queries/security/cwe-078/InjectionHunter/UserInputToDangerousMethod.ql
+++ /dev/null
@@ -1,36 +0,0 @@
-/**
- * @name User Input to injection sink
- * @description Finding cases where the user input is passed an dangerous method that can lead to RCE
- * @kind path-problem
- * @problem.severity error
- * @security-severity 9.8
- * @precision high
- * @id powershell/microsoft/public/user-input-to-injection-sink
- * @tags security
- * external/cwe/cwe-078
- * external/cwe/cwe-088
- */
-
-import powershell
-import semmle.code.powershell.dataflow.TaintTracking
-import semmle.code.powershell.dataflow.DataFlow
-import semmle.code.powershell.ApiGraphs
-import semmle.code.powershell.dataflow.flowsources.FlowSources
-
-import Sanitizers
-import Sinks
-
-private module InjectionConfig implements DataFlow::ConfigSig {
- predicate isSource(DataFlow::Node source) {
- source instanceof SourceNode
- }
- predicate isSink(DataFlow::Node sink) { sink instanceof InjectionSink }
- predicate isBarrier(DataFlow::Node node) {node instanceof Sanitizer}
-}
-
-module InjectionFlow = TaintTracking::Global;
-import InjectionFlow::PathGraph
-
-from InjectionFlow::PathNode source, InjectionFlow::PathNode sink
-where InjectionFlow::flowPath(source, sink)
-select sink.getNode(), source, sink, "Possible injection path from user input to dangerous " + sink.getNode().(InjectionSink).getSinkType()
diff --git a/powershell/ql/test/query-tests/security/cwe-078/CommandInjection/test.ps1 b/powershell/ql/test/query-tests/security/cwe-078/CommandInjection/test.ps1
index 682b1af3752..fd1bc38ce08 100644
--- a/powershell/ql/test/query-tests/security/cwe-078/CommandInjection/test.ps1
+++ b/powershell/ql/test/query-tests/security/cwe-078/CommandInjection/test.ps1
@@ -1,7 +1,210 @@
-param ($x)
+function Invoke-InvokeExpressionInjection1
+{
+ param($UserInput)
+ Invoke-Expression "Get-Process -Name $UserInput"
+}
-Invoke-Expression -Command "Get-Process -Id $x" # BAD
+function Invoke-InvokeExpressionInjection2
+{
+ param($UserInput)
+ iex "Get-Process -Name $UserInput"
+}
-$code = "$Env:MY_VAR"
+function Invoke-InvokeExpressionInjection3
+{
+ param($UserInput)
+ $executionContext.InvokeCommand.InvokeScript("Get-Process -Name $UserInput")
+}
-& "$code --enabled" # BAD
\ No newline at end of file
+function Invoke-InvokeExpressionInjection4
+{
+ param($UserInput)
+ $host.Runspace.CreateNestedPipeline("Get-Process -Name $UserInput", $false).Invoke()
+}
+
+function Invoke-InvokeExpressionInjection5
+{
+ param($UserInput)
+ [PowerShell]::Create().AddScript("Get-Process -Name $UserInput").Invoke()
+}
+
+function Invoke-InvokeExpressionInjection6
+{
+ param($UserInput)
+ Add-Type "public class Foo { $UserInput }"
+}
+
+function Invoke-InvokeExpressionInjection7
+{
+ param($UserInput)
+ Add-Type -TypeDefinition "public class Foo { $UserInput }"
+}
+
+function Invoke-InvokeExpressionInjection8
+{
+ param($UserInput)
+
+ $code = "public class Foo { $UserInput }"
+ Add-Type -TypeDefinition $code
+}
+
+function Invoke-InvokeExpressionInjectionFP
+{
+ param($UserInput)
+
+ $code = @"
+ public class BasicTest
+ {
+ public static int Add(int a, int b)
+ {
+ return (a + b);
+ }
+ public int Multiply(int a, int b)
+ {
+ return (a * b);
+ }
+ }
+"@
+ Add-Type -TypeDefinition $code
+}
+
+function Invoke-ExploitableCommandInjection1
+{
+ param($UserInput)
+
+ powershell -command "Get-Process -Name $UserInput"
+}
+
+function Invoke-ExploitableCommandInjection2
+{
+ param($UserInput)
+
+ powershell "Get-Process -Name $UserInput"
+}
+
+function Invoke-ExploitableCommandInjection3
+{
+ param($UserInput)
+
+ cmd /c "ping $UserInput"
+}
+
+function Invoke-ScriptBlockInjection1
+{
+ param($UserInput)
+
+ ## Often used when making remote connections
+
+ $sb = [ScriptBlock]::Create("Get-Process -Name $UserInput")
+ Invoke-Command RemoteServer $sb
+}
+
+function Invoke-ScriptBlockInjection2
+{
+ param($UserInput)
+
+ ## Often used when making remote connections
+
+ $sb = $executionContext.InvokeCommand.NewScriptBlock("Get-Process -Name $UserInput")
+ Invoke-Command RemoteServer $sb
+}
+
+function Invoke-MethodInjection1
+{
+ param($UserInput)
+
+ Get-Process | Foreach-Object $UserInput
+}
+
+function Invoke-MethodInjection2
+{
+ param($UserInput)
+
+ (Get-Process -Id $pid).$UserInput()
+}
+
+function Invoke-MethodInjection3
+{
+ param($UserInput)
+
+ (Get-Process -Id $pid).$UserInput.Invoke()
+}
+
+#TODO: currently a FN
+function Invoke-ExpandStringInjection1
+{
+ param($UserInput)
+
+ ## Used to attempt a variable resolution
+ $executionContext.InvokeCommand.ExpandString($UserInput)
+}
+
+function Invoke-ExpandStringInjection2
+{
+ param($UserInput)
+
+ ## Used to attempt a variable resolution
+ $executionContext.SessionState.InvokeCommand.ExpandString($UserInput)
+}
+
+
+
+$input = Read-Host "enter input"
+
+Invoke-InvokeExpressionInjection1 -UserInput $input
+Invoke-InvokeExpressionInjection2 -UserInput $input
+Invoke-InvokeExpressionInjection3 -UserInput $input
+Invoke-InvokeExpressionInjection4 -UserInput $input
+Invoke-InvokeExpressionInjection5 -UserInput $input
+Invoke-InvokeExpressionInjection6 -UserInput $input
+Invoke-InvokeExpressionInjection7 -UserInput $input
+Invoke-InvokeExpressionInjection8 -UserInput $input
+Invoke-InvokeExpressionInjectionFP -UserInput $input
+Invoke-ExploitableCommandInjection1 -UserInput $input
+Invoke-ExploitableCommandInjection2 -UserInput $input
+Invoke-ExploitableCommandInjection3 -UserInput $input
+Invoke-ScriptBlockInjection1 -UserInput $input
+Invoke-ScriptBlockInjection2 -UserInput $input
+Invoke-MethodInjection1 -UserInput $input
+Invoke-MethodInjection2 -UserInput $input
+Invoke-MethodInjection3 -UserInput $input
+Invoke-PropertyInjection -UserInput $input
+Invoke-ExpandStringInjection1 -UserInput $input
+Invoke-ExpandStringInjection2 -UserInput $input
+
+#typed input
+function Invoke-InvokeExpressionInjectionSafe1
+{
+ param([int] $UserInput)
+ Invoke-Expression "Get-Process -Name $UserInput"
+}
+
+#single quotes to treat them as string literal
+function Invoke-InvokeExpressionInjectionSafe2
+{
+ param($UserInput)
+ Invoke-Expression "Get-Process -Name '$UserInput'"
+}
+#EscapeSingleQuotedStringContent API
+function Invoke-InvokeExpressionInjectionSafe3
+{
+ param([int] $UserInput)
+
+ $UserInputClean = [System.Management.Automation.Language.CodeGeneration]::
+ EscapeSingleQuotedStringContent("$UserInput")
+ Invoke-Expression "Get-Process -Name $UserInputClean"
+}
+
+#EscapeSingleQuotedStringContent API 2
+function Invoke-InvokeExpressionInjectionSafe4
+{
+ param([int] $UserInput)
+
+ $UserInputClean = [System.Management.Automation.Language.CodeGeneration]::EscapeSingleQuotedStringContent("$UserInput")
+ Invoke-Expression "Get-Process -Name $UserInputClean"
+}
+
+Invoke-InvokeExpressionInjectionSafe1 -UserInput $input
+Invoke-InvokeExpressionInjectionSafe2 -UserInput $input
+Invoke-InvokeExpressionInjectionSafe3 -UserInput $input
+Invoke-InvokeExpressionInjectionSafe4 -UserInput $input
\ No newline at end of file
diff --git a/powershell/ql/test/query-tests/security/cwe-078/InjectionHunter/InjectionHunter.expected b/powershell/ql/test/query-tests/security/cwe-078/InjectionHunter/InjectionHunter.expected
deleted file mode 100644
index 8bfcc1dafec..00000000000
--- a/powershell/ql/test/query-tests/security/cwe-078/InjectionHunter/InjectionHunter.expected
+++ /dev/null
@@ -1,146 +0,0 @@
-edges
-| test.ps1:3:11:3:20 | UserInput | test.ps1:4:23:4:52 | Get-Process -Name $UserInput | provenance | |
-| test.ps1:9:11:9:20 | UserInput | test.ps1:10:9:10:38 | Get-Process -Name $UserInput | provenance | |
-| test.ps1:15:11:15:20 | UserInput | test.ps1:16:50:16:79 | Get-Process -Name $UserInput | provenance | |
-| test.ps1:21:11:21:20 | UserInput | test.ps1:22:41:22:70 | Get-Process -Name $UserInput | provenance | |
-| test.ps1:21:11:21:20 | UserInput | test.ps1:22:60:22:69 | UserInput | provenance | |
-| test.ps1:27:11:27:20 | UserInput | test.ps1:28:38:28:67 | Get-Process -Name $UserInput | provenance | |
-| test.ps1:27:11:27:20 | UserInput | test.ps1:28:57:28:66 | UserInput | provenance | |
-| test.ps1:33:11:33:20 | UserInput | test.ps1:34:14:34:46 | public class Foo { $UserInput } | provenance | |
-| test.ps1:39:11:39:20 | UserInput | test.ps1:40:30:40:62 | public class Foo { $UserInput } | provenance | |
-| test.ps1:45:11:45:20 | UserInput | test.ps1:48:30:48:34 | code | provenance | |
-| test.ps1:73:11:73:20 | UserInput | test.ps1:75:25:75:54 | Get-Process -Name $UserInput | provenance | |
-| test.ps1:80:11:80:20 | UserInput | test.ps1:82:16:82:45 | Get-Process -Name $UserInput | provenance | |
-| test.ps1:87:11:87:20 | UserInput | test.ps1:89:12:89:28 | ping $UserInput | provenance | |
-| test.ps1:102:11:102:20 | UserInput | test.ps1:106:33:106:62 | Get-Process -Name $UserInput | provenance | |
-| test.ps1:112:11:112:20 | UserInput | test.ps1:116:58:116:87 | Get-Process -Name $UserInput | provenance | |
-| test.ps1:122:11:122:20 | UserInput | test.ps1:124:34:124:43 | UserInput | provenance | |
-| test.ps1:129:11:129:20 | UserInput | test.ps1:131:28:131:37 | UserInput | provenance | |
-| test.ps1:136:11:136:20 | UserInput | test.ps1:138:28:138:37 | UserInput | provenance | |
-| test.ps1:165:11:165:20 | UserInput | test.ps1:168:50:168:59 | UserInput | provenance | |
-| test.ps1:173:11:173:20 | UserInput | test.ps1:176:63:176:72 | UserInput | provenance | |
-| test.ps1:189:11:189:20 | UserInput | test.ps1:192:23:192:54 | Get-Process -Name "$escaped" | provenance | |
-| test.ps1:195:10:195:32 | Call to Read-Host | test.ps1:197:46:197:51 | input | provenance | Src:MaD:11464 |
-| test.ps1:195:10:195:32 | Call to Read-Host | test.ps1:198:46:198:51 | input | provenance | Src:MaD:11464 |
-| test.ps1:195:10:195:32 | Call to Read-Host | test.ps1:199:46:199:51 | input | provenance | Src:MaD:11464 |
-| test.ps1:195:10:195:32 | Call to Read-Host | test.ps1:200:46:200:51 | input | provenance | Src:MaD:11464 |
-| test.ps1:195:10:195:32 | Call to Read-Host | test.ps1:201:46:201:51 | input | provenance | Src:MaD:11464 |
-| test.ps1:195:10:195:32 | Call to Read-Host | test.ps1:202:46:202:51 | input | provenance | Src:MaD:11464 |
-| test.ps1:195:10:195:32 | Call to Read-Host | test.ps1:203:46:203:51 | input | provenance | Src:MaD:11464 |
-| test.ps1:195:10:195:32 | Call to Read-Host | test.ps1:204:46:204:51 | input | provenance | Src:MaD:11464 |
-| test.ps1:195:10:195:32 | Call to Read-Host | test.ps1:206:48:206:53 | input | provenance | Src:MaD:11464 |
-| test.ps1:195:10:195:32 | Call to Read-Host | test.ps1:207:48:207:53 | input | provenance | Src:MaD:11464 |
-| test.ps1:195:10:195:32 | Call to Read-Host | test.ps1:208:48:208:53 | input | provenance | Src:MaD:11464 |
-| test.ps1:195:10:195:32 | Call to Read-Host | test.ps1:210:41:210:46 | input | provenance | Src:MaD:11464 |
-| test.ps1:195:10:195:32 | Call to Read-Host | test.ps1:211:41:211:46 | input | provenance | Src:MaD:11464 |
-| test.ps1:195:10:195:32 | Call to Read-Host | test.ps1:212:36:212:41 | input | provenance | Src:MaD:11464 |
-| test.ps1:195:10:195:32 | Call to Read-Host | test.ps1:213:36:213:41 | input | provenance | Src:MaD:11464 |
-| test.ps1:195:10:195:32 | Call to Read-Host | test.ps1:214:36:214:41 | input | provenance | Src:MaD:11464 |
-| test.ps1:195:10:195:32 | Call to Read-Host | test.ps1:218:42:218:47 | input | provenance | Src:MaD:11464 |
-| test.ps1:195:10:195:32 | Call to Read-Host | test.ps1:219:42:219:47 | input | provenance | Src:MaD:11464 |
-| test.ps1:195:10:195:32 | Call to Read-Host | test.ps1:221:33:221:38 | input | provenance | Src:MaD:11464 |
-| test.ps1:197:46:197:51 | input | test.ps1:3:11:3:20 | UserInput | provenance | |
-| test.ps1:198:46:198:51 | input | test.ps1:9:11:9:20 | UserInput | provenance | |
-| test.ps1:199:46:199:51 | input | test.ps1:15:11:15:20 | UserInput | provenance | |
-| test.ps1:200:46:200:51 | input | test.ps1:21:11:21:20 | UserInput | provenance | |
-| test.ps1:201:46:201:51 | input | test.ps1:27:11:27:20 | UserInput | provenance | |
-| test.ps1:202:46:202:51 | input | test.ps1:33:11:33:20 | UserInput | provenance | |
-| test.ps1:203:46:203:51 | input | test.ps1:39:11:39:20 | UserInput | provenance | |
-| test.ps1:204:46:204:51 | input | test.ps1:45:11:45:20 | UserInput | provenance | |
-| test.ps1:206:48:206:53 | input | test.ps1:73:11:73:20 | UserInput | provenance | |
-| test.ps1:207:48:207:53 | input | test.ps1:80:11:80:20 | UserInput | provenance | |
-| test.ps1:208:48:208:53 | input | test.ps1:87:11:87:20 | UserInput | provenance | |
-| test.ps1:210:41:210:46 | input | test.ps1:102:11:102:20 | UserInput | provenance | |
-| test.ps1:211:41:211:46 | input | test.ps1:112:11:112:20 | UserInput | provenance | |
-| test.ps1:212:36:212:41 | input | test.ps1:122:11:122:20 | UserInput | provenance | |
-| test.ps1:213:36:213:41 | input | test.ps1:129:11:129:20 | UserInput | provenance | |
-| test.ps1:214:36:214:41 | input | test.ps1:136:11:136:20 | UserInput | provenance | |
-| test.ps1:218:42:218:47 | input | test.ps1:165:11:165:20 | UserInput | provenance | |
-| test.ps1:219:42:219:47 | input | test.ps1:173:11:173:20 | UserInput | provenance | |
-| test.ps1:221:33:221:38 | input | test.ps1:189:11:189:20 | UserInput | provenance | |
-nodes
-| test.ps1:3:11:3:20 | UserInput | semmle.label | UserInput |
-| test.ps1:4:23:4:52 | Get-Process -Name $UserInput | semmle.label | Get-Process -Name $UserInput |
-| test.ps1:9:11:9:20 | UserInput | semmle.label | UserInput |
-| test.ps1:10:9:10:38 | Get-Process -Name $UserInput | semmle.label | Get-Process -Name $UserInput |
-| test.ps1:15:11:15:20 | UserInput | semmle.label | UserInput |
-| test.ps1:16:50:16:79 | Get-Process -Name $UserInput | semmle.label | Get-Process -Name $UserInput |
-| test.ps1:21:11:21:20 | UserInput | semmle.label | UserInput |
-| test.ps1:22:41:22:70 | Get-Process -Name $UserInput | semmle.label | Get-Process -Name $UserInput |
-| test.ps1:22:60:22:69 | UserInput | semmle.label | UserInput |
-| test.ps1:27:11:27:20 | UserInput | semmle.label | UserInput |
-| test.ps1:28:38:28:67 | Get-Process -Name $UserInput | semmle.label | Get-Process -Name $UserInput |
-| test.ps1:28:57:28:66 | UserInput | semmle.label | UserInput |
-| test.ps1:33:11:33:20 | UserInput | semmle.label | UserInput |
-| test.ps1:34:14:34:46 | public class Foo { $UserInput } | semmle.label | public class Foo { $UserInput } |
-| test.ps1:39:11:39:20 | UserInput | semmle.label | UserInput |
-| test.ps1:40:30:40:62 | public class Foo { $UserInput } | semmle.label | public class Foo { $UserInput } |
-| test.ps1:45:11:45:20 | UserInput | semmle.label | UserInput |
-| test.ps1:48:30:48:34 | code | semmle.label | code |
-| test.ps1:73:11:73:20 | UserInput | semmle.label | UserInput |
-| test.ps1:75:25:75:54 | Get-Process -Name $UserInput | semmle.label | Get-Process -Name $UserInput |
-| test.ps1:80:11:80:20 | UserInput | semmle.label | UserInput |
-| test.ps1:82:16:82:45 | Get-Process -Name $UserInput | semmle.label | Get-Process -Name $UserInput |
-| test.ps1:87:11:87:20 | UserInput | semmle.label | UserInput |
-| test.ps1:89:12:89:28 | ping $UserInput | semmle.label | ping $UserInput |
-| test.ps1:102:11:102:20 | UserInput | semmle.label | UserInput |
-| test.ps1:106:33:106:62 | Get-Process -Name $UserInput | semmle.label | Get-Process -Name $UserInput |
-| test.ps1:112:11:112:20 | UserInput | semmle.label | UserInput |
-| test.ps1:116:58:116:87 | Get-Process -Name $UserInput | semmle.label | Get-Process -Name $UserInput |
-| test.ps1:122:11:122:20 | UserInput | semmle.label | UserInput |
-| test.ps1:124:34:124:43 | UserInput | semmle.label | UserInput |
-| test.ps1:129:11:129:20 | UserInput | semmle.label | UserInput |
-| test.ps1:131:28:131:37 | UserInput | semmle.label | UserInput |
-| test.ps1:136:11:136:20 | UserInput | semmle.label | UserInput |
-| test.ps1:138:28:138:37 | UserInput | semmle.label | UserInput |
-| test.ps1:165:11:165:20 | UserInput | semmle.label | UserInput |
-| test.ps1:168:50:168:59 | UserInput | semmle.label | UserInput |
-| test.ps1:173:11:173:20 | UserInput | semmle.label | UserInput |
-| test.ps1:176:63:176:72 | UserInput | semmle.label | UserInput |
-| test.ps1:189:11:189:20 | UserInput | semmle.label | UserInput |
-| test.ps1:192:23:192:54 | Get-Process -Name "$escaped" | semmle.label | Get-Process -Name "$escaped" |
-| test.ps1:195:10:195:32 | Call to Read-Host | semmle.label | Call to Read-Host |
-| test.ps1:197:46:197:51 | input | semmle.label | input |
-| test.ps1:198:46:198:51 | input | semmle.label | input |
-| test.ps1:199:46:199:51 | input | semmle.label | input |
-| test.ps1:200:46:200:51 | input | semmle.label | input |
-| test.ps1:201:46:201:51 | input | semmle.label | input |
-| test.ps1:202:46:202:51 | input | semmle.label | input |
-| test.ps1:203:46:203:51 | input | semmle.label | input |
-| test.ps1:204:46:204:51 | input | semmle.label | input |
-| test.ps1:206:48:206:53 | input | semmle.label | input |
-| test.ps1:207:48:207:53 | input | semmle.label | input |
-| test.ps1:208:48:208:53 | input | semmle.label | input |
-| test.ps1:210:41:210:46 | input | semmle.label | input |
-| test.ps1:211:41:211:46 | input | semmle.label | input |
-| test.ps1:212:36:212:41 | input | semmle.label | input |
-| test.ps1:213:36:213:41 | input | semmle.label | input |
-| test.ps1:214:36:214:41 | input | semmle.label | input |
-| test.ps1:218:42:218:47 | input | semmle.label | input |
-| test.ps1:219:42:219:47 | input | semmle.label | input |
-| test.ps1:221:33:221:38 | input | semmle.label | input |
-subpaths
-#select
-| test.ps1:4:23:4:52 | Get-Process -Name $UserInput | test.ps1:195:10:195:32 | Call to Read-Host | test.ps1:4:23:4:52 | Get-Process -Name $UserInput | Possible injection path from user input to dangerous call to Invoke-Expression |
-| test.ps1:10:9:10:38 | Get-Process -Name $UserInput | test.ps1:195:10:195:32 | Call to Read-Host | test.ps1:10:9:10:38 | Get-Process -Name $UserInput | Possible injection path from user input to dangerous call to Invoke-Expression |
-| test.ps1:16:50:16:79 | Get-Process -Name $UserInput | test.ps1:195:10:195:32 | Call to Read-Host | test.ps1:16:50:16:79 | Get-Process -Name $UserInput | Possible injection path from user input to dangerous call to InvokeScript |
-| test.ps1:22:41:22:70 | Get-Process -Name $UserInput | test.ps1:195:10:195:32 | Call to Read-Host | test.ps1:22:41:22:70 | Get-Process -Name $UserInput | Possible injection path from user input to dangerous call to CreateNestedPipeline |
-| test.ps1:22:41:22:70 | Get-Process -Name $UserInput | test.ps1:195:10:195:32 | Call to Read-Host | test.ps1:22:41:22:70 | Get-Process -Name $UserInput | Possible injection path from user input to dangerous call to Invoke |
-| test.ps1:22:60:22:69 | UserInput | test.ps1:195:10:195:32 | Call to Read-Host | test.ps1:22:60:22:69 | UserInput | Possible injection path from user input to dangerous call to Invoke |
-| test.ps1:28:38:28:67 | Get-Process -Name $UserInput | test.ps1:195:10:195:32 | Call to Read-Host | test.ps1:28:38:28:67 | Get-Process -Name $UserInput | Possible injection path from user input to dangerous call to AddScript |
-| test.ps1:28:38:28:67 | Get-Process -Name $UserInput | test.ps1:195:10:195:32 | Call to Read-Host | test.ps1:28:38:28:67 | Get-Process -Name $UserInput | Possible injection path from user input to dangerous call to Invoke |
-| test.ps1:28:57:28:66 | UserInput | test.ps1:195:10:195:32 | Call to Read-Host | test.ps1:28:57:28:66 | UserInput | Possible injection path from user input to dangerous call to Invoke |
-| test.ps1:34:14:34:46 | public class Foo { $UserInput } | test.ps1:195:10:195:32 | Call to Read-Host | test.ps1:34:14:34:46 | public class Foo { $UserInput } | Possible injection path from user input to dangerous call to Invoke-Expression |
-| test.ps1:40:30:40:62 | public class Foo { $UserInput } | test.ps1:195:10:195:32 | Call to Read-Host | test.ps1:40:30:40:62 | public class Foo { $UserInput } | Possible injection path from user input to dangerous call to Invoke-Expression |
-| test.ps1:48:30:48:34 | code | test.ps1:195:10:195:32 | Call to Read-Host | test.ps1:48:30:48:34 | code | Possible injection path from user input to dangerous call to Invoke-Expression |
-| test.ps1:75:25:75:54 | Get-Process -Name $UserInput | test.ps1:195:10:195:32 | Call to Read-Host | test.ps1:75:25:75:54 | Get-Process -Name $UserInput | Possible injection path from user input to dangerous call to Powershell |
-| test.ps1:82:16:82:45 | Get-Process -Name $UserInput | test.ps1:195:10:195:32 | Call to Read-Host | test.ps1:82:16:82:45 | Get-Process -Name $UserInput | Possible injection path from user input to dangerous call to Powershell |
-| test.ps1:89:12:89:28 | ping $UserInput | test.ps1:195:10:195:32 | Call to Read-Host | test.ps1:89:12:89:28 | ping $UserInput | Possible injection path from user input to dangerous call to Cmd |
-| test.ps1:106:33:106:62 | Get-Process -Name $UserInput | test.ps1:195:10:195:32 | Call to Read-Host | test.ps1:106:33:106:62 | Get-Process -Name $UserInput | Possible injection path from user input to dangerous call to CreateScriptBlock |
-| test.ps1:116:58:116:87 | Get-Process -Name $UserInput | test.ps1:195:10:195:32 | Call to Read-Host | test.ps1:116:58:116:87 | Get-Process -Name $UserInput | Possible injection path from user input to dangerous call to NewScriptBlock |
-| test.ps1:124:34:124:43 | UserInput | test.ps1:195:10:195:32 | Call to Read-Host | test.ps1:124:34:124:43 | UserInput | Possible injection path from user input to dangerous call to ForEach-Object |
-| test.ps1:131:28:131:37 | UserInput | test.ps1:195:10:195:32 | Call to Read-Host | test.ps1:131:28:131:37 | UserInput | Possible injection path from user input to dangerous call to Invoke |
-| test.ps1:138:28:138:37 | UserInput | test.ps1:195:10:195:32 | Call to Read-Host | test.ps1:138:28:138:37 | UserInput | Possible injection path from user input to dangerous call to Invoke |
-| test.ps1:168:50:168:59 | UserInput | test.ps1:195:10:195:32 | Call to Read-Host | test.ps1:168:50:168:59 | UserInput | Possible injection path from user input to dangerous call to ExpandString |
-| test.ps1:176:63:176:72 | UserInput | test.ps1:195:10:195:32 | Call to Read-Host | test.ps1:176:63:176:72 | UserInput | Possible injection path from user input to dangerous call to ExpandString |
-| test.ps1:192:23:192:54 | Get-Process -Name "$escaped" | test.ps1:195:10:195:32 | Call to Read-Host | test.ps1:192:23:192:54 | Get-Process -Name "$escaped" | Possible injection path from user input to dangerous call to Invoke-Expression |
diff --git a/powershell/ql/test/query-tests/security/cwe-078/InjectionHunter/InjectionHunter.qlref b/powershell/ql/test/query-tests/security/cwe-078/InjectionHunter/InjectionHunter.qlref
deleted file mode 100644
index 61447f65050..00000000000
--- a/powershell/ql/test/query-tests/security/cwe-078/InjectionHunter/InjectionHunter.qlref
+++ /dev/null
@@ -1 +0,0 @@
-queries/security/cwe-078/InjectionHunter/UserInputToDangerousMethod.ql
\ No newline at end of file
diff --git a/powershell/ql/test/query-tests/security/cwe-078/InjectionHunter/test.ps1 b/powershell/ql/test/query-tests/security/cwe-078/InjectionHunter/test.ps1
deleted file mode 100644
index 3757d9d4f2c..00000000000
--- a/powershell/ql/test/query-tests/security/cwe-078/InjectionHunter/test.ps1
+++ /dev/null
@@ -1,221 +0,0 @@
-function Invoke-InvokeExpressionInjection1
-{
- param($UserInput)
- Invoke-Expression "Get-Process -Name $UserInput"
-}
-
-function Invoke-InvokeExpressionInjection2
-{
- param($UserInput)
- iex "Get-Process -Name $UserInput"
-}
-
-function Invoke-InvokeExpressionInjection3
-{
- param($UserInput)
- $executionContext.InvokeCommand.InvokeScript("Get-Process -Name $UserInput")
-}
-
-function Invoke-InvokeExpressionInjection4
-{
- param($UserInput)
- $host.Runspace.CreateNestedPipeline("Get-Process -Name $UserInput", $false).Invoke()
-}
-
-function Invoke-InvokeExpressionInjection5
-{
- param($UserInput)
- [PowerShell]::Create().AddScript("Get-Process -Name $UserInput").Invoke()
-}
-
-function Invoke-InvokeExpressionInjection6
-{
- param($UserInput)
- Add-Type "public class Foo { $UserInput }"
-}
-
-function Invoke-InvokeExpressionInjection7
-{
- param($UserInput)
- Add-Type -TypeDefinition "public class Foo { $UserInput }"
-}
-
-function Invoke-InvokeExpressionInjection8
-{
- param($UserInput)
-
- $code = "public class Foo { $UserInput }"
- Add-Type -TypeDefinition $code
-}
-
-function Invoke-InvokeExpressionInjectionFP
-{
- param($UserInput)
-
- $code = @"
- public class BasicTest
- {
- public static int Add(int a, int b)
- {
- return (a + b);
- }
- public int Multiply(int a, int b)
- {
- return (a * b);
- }
- }
-"@
- Add-Type -TypeDefinition $code
-}
-
-function Invoke-ExploitableCommandInjection1
-{
- param($UserInput)
-
- powershell -command "Get-Process -Name $UserInput"
-}
-
-function Invoke-ExploitableCommandInjection2
-{
- param($UserInput)
-
- powershell "Get-Process -Name $UserInput"
-}
-
-function Invoke-ExploitableCommandInjection3
-{
- param($UserInput)
-
- cmd /c "ping $UserInput"
-}
-
-#Allowed
-function Invoke-ExploitableCommandInjectionFP
-{
- param($UserInput)
-
- cmd /c "ping localhost"
-}
-
-function Invoke-ScriptBlockInjection1
-{
- param($UserInput)
-
- ## Often used when making remote connections
-
- $sb = [ScriptBlock]::Create("Get-Process -Name $UserInput")
- Invoke-Command RemoteServer $sb
-}
-
-function Invoke-ScriptBlockInjection2
-{
- param($UserInput)
-
- ## Often used when making remote connections
-
- $sb = $executionContext.InvokeCommand.NewScriptBlock("Get-Process -Name $UserInput")
- Invoke-Command RemoteServer $sb
-}
-
-function Invoke-MethodInjection1
-{
- param($UserInput)
-
- Get-Process | Foreach-Object $UserInput
-}
-
-function Invoke-MethodInjection2
-{
- param($UserInput)
-
- (Get-Process -Id $pid).$UserInput()
-}
-
-function Invoke-MethodInjection3
-{
- param($UserInput)
-
- (Get-Process -Id $pid).$UserInput.Invoke()
-}
-
-#ALLOWED , uses script block
-function Invoke-MethodInjectionFP1
-{
- param($UserInput)
-
- Get-Process | Foreach-Object { $_.Name }
-}
-#ALLOWED, uses constant member access
-function Invoke-MethodInjectionFP2
-{
- param($UserInput)
-
- Get-Process | Foreach-Object "Name"
-}
-
-function Invoke-PropertyInjection
-{
- param($UserInput)
-
- [DateTime]::$UserInput
-}
-
-function Invoke-ExpandStringInjection1
-{
- param($UserInput)
-
- ## Used to attempt a variable resolution
- $executionContext.InvokeCommand.ExpandString($UserInput)
-}
-
-function Invoke-ExpandStringInjection2
-{
- param($UserInput)
-
- ## Used to attempt a variable resolution
- $executionContext.SessionState.InvokeCommand.ExpandString($UserInput)
-}
-
-function Invoke-UnsafeEscape1
-{
- param($UserInput)
-
- $escaped = $UserInput -replace "'", "''"
- Invoke-Expression "Get-Process -Name '$escaped'"
-}
-
-function Invoke-UnsafeEscape2
-{
- param($UserInput)
-
- $escaped = $UserInput -replace '"', '`"'
- Invoke-Expression "Get-Process -Name `"$escaped`""
-}
-
-$input = Read-Host "enter input"
-
-Invoke-InvokeExpressionInjection1 -UserInput $input
-Invoke-InvokeExpressionInjection2 -UserInput $input
-Invoke-InvokeExpressionInjection3 -UserInput $input
-Invoke-InvokeExpressionInjection4 -UserInput $input
-Invoke-InvokeExpressionInjection5 -UserInput $input
-Invoke-InvokeExpressionInjection6 -UserInput $input
-Invoke-InvokeExpressionInjection7 -UserInput $input
-Invoke-InvokeExpressionInjection8 -UserInput $input
-Invoke-InvokeExpressionInjectionFP -UserInput $input
-Invoke-ExploitableCommandInjection1 -UserInput $input
-Invoke-ExploitableCommandInjection2 -UserInput $input
-Invoke-ExploitableCommandInjection3 -UserInput $input
-Invoke-ExploitableCommandInjectionFP -UserInput $input
-Invoke-ScriptBlockInjection1 -UserInput $input
-Invoke-ScriptBlockInjection2 -UserInput $input
-Invoke-MethodInjection1 -UserInput $input
-Invoke-MethodInjection2 -UserInput $input
-Invoke-MethodInjection3 -UserInput $input
-Invoke-MethodInjectionFP1 -UserInput $input
-Invoke-MethodInjectionFP2 -UserInput $input
-Invoke-PropertyInjection -UserInput $input
-Invoke-ExpandStringInjection1 -UserInput $input
-Invoke-ExpandStringInjection2 -UserInput $input
-Invoke-UnsafeEscape1 -UserInput $input
-Invoke-UnsafeEscape2 -UserInput $input
\ No newline at end of file