mirror of
https://github.com/github/codeql.git
synced 2026-05-25 00:27:09 +02:00
moved folder, added tests/docs
This commit is contained in:
@@ -1,241 +0,0 @@
|
||||
/**
|
||||
* @name User Input to Invoke-Expression
|
||||
* @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-invoke-expression
|
||||
* @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
|
||||
|
||||
private module TestConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
source instanceof SourceNode or
|
||||
source instanceof Source
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
|
||||
predicate isBarrier(DataFlow::Node node) {node instanceof Sanitizer}
|
||||
}
|
||||
|
||||
abstract class Source extends DataFlow::Node {}
|
||||
|
||||
class ReadHostSource extends Source {
|
||||
ReadHostSource() {
|
||||
exists(CmdCall c |
|
||||
this.asExpr().getExpr() = c and
|
||||
c.getName() = "Read-Host" )
|
||||
}
|
||||
}
|
||||
|
||||
class GetContentSource extends Source {
|
||||
GetContentSource() {
|
||||
exists(CmdCall c |
|
||||
this.asExpr().getExpr() = c and
|
||||
c.getName() = "Get-Content" )
|
||||
}
|
||||
}
|
||||
|
||||
class ValueFromPipelineSource extends Source {
|
||||
ValueFromPipelineSource() {
|
||||
exists(Parameter p |
|
||||
p.getAnAttribute().toString() = "ValueFromPipeline" and
|
||||
this.asExpr().getExpr() = p.getAnAccess()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
abstract class Sink extends DataFlow::Node {}
|
||||
|
||||
class InvokeExpressionCall extends Sink {
|
||||
InvokeExpressionCall() {
|
||||
exists(CmdCall c |
|
||||
this.asExpr().getExpr() = c.getAnArgument() and
|
||||
c.getName() = ["Invoke-Expression", "iex", "Add-Type" ] )
|
||||
}
|
||||
}
|
||||
|
||||
class InvokeScriptSink extends Sink {
|
||||
InvokeScriptSink() {
|
||||
exists(API::Node call |
|
||||
API::getTopLevelMember("executioncontext").getMember("invokecommand").getMethod("invokescript") = call and
|
||||
this = call.getArgument(_).asSink()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class CreateNestedPipelineSink extends Sink {
|
||||
CreateNestedPipelineSink() {
|
||||
exists(API::Node call |
|
||||
API::getTopLevelMember("host").getMember("runspace").getMethod("createnestedpipeline") = call and
|
||||
this = call.getArgument(_).asSink()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
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"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
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"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class ForEachObjectSink extends Sink {
|
||||
ForEachObjectSink() {
|
||||
exists(CmdCall c |
|
||||
this.asExpr().getExpr() = c.getAnArgument() and
|
||||
c.getName() = "Foreach-Object"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class InvokeSink extends Sink {
|
||||
InvokeSink() {
|
||||
exists(InvokeMemberExpr ie |
|
||||
this.asExpr().getExpr() = ie.getCallee() or
|
||||
this.asExpr().getExpr() = ie.getQualifier().getAChild*()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class CreateScriptBlockSink extends Sink {
|
||||
CreateScriptBlockSink() {
|
||||
exists(InvokeMemberExpr ie |
|
||||
this.asExpr().getExpr() = ie.getAnArgument() and
|
||||
ie.getName() = "Create" and
|
||||
ie.getQualifier().toString() = "ScriptBlock"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class NewScriptBlockSink extends Sink {
|
||||
NewScriptBlockSink() {
|
||||
exists(API::Node call |
|
||||
API::getTopLevelMember("executioncontext").getMember("invokecommand").getMethod("newscriptblock") = call and
|
||||
this = call.getArgument(_).asSink()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
module TestFlow = TaintTracking::Global<TestConfig>;
|
||||
import TestFlow::PathGraph
|
||||
|
||||
from TestFlow::PathNode source, TestFlow::PathNode sink
|
||||
where
|
||||
TestFlow::flowPath(source, sink)
|
||||
select sink.getNode(), source, sink, "Flow from user input to dangerous method"
|
||||
|
||||
// from CmdCall c
|
||||
// where c.getName() = "cmd"
|
||||
// and c.getArgument(0).getValue().toString() = "/c"
|
||||
// select c.getArgument(1)
|
||||
|
||||
// from InvokeMemberExpr ie
|
||||
// where ie.getName() = "Create" and
|
||||
// ie.getQualifier().toString() = "ScriptBlock"
|
||||
// select ie, ie.getQualifier(), ie.getAnArgument()
|
||||
|
||||
// from API::Node call
|
||||
// where API::getTopLevelMember("executioncontext").getMember("invokecommand").getMethod("newscriptblock") = call
|
||||
// select call, call.getArgument(_).asSink()
|
||||
|
||||
// from Expr e
|
||||
// where e.getLocation().getFile().getBaseName() = "InjectionHunterTests.ps1"
|
||||
// and e.getLocation().getStartLine() = 106
|
||||
// select e, e.getAQlClass()
|
||||
|
||||
|
||||
// from Function f, CmdCall c
|
||||
// where f.getLocation().getFile().getBaseName() = "sanitizers.ps1"
|
||||
// select f, f.getAParameter().getStaticType(), f.getAParameter().getName()
|
||||
|
||||
|
||||
//TBD, waiting on mathias on how to connect f and c
|
||||
// from Function f, CmdCall c, Parameter p, Argument a
|
||||
// where
|
||||
// p = f.getAParameter() and
|
||||
// a = c.getAnArgument() and
|
||||
// p.getName().toLowerCase() = a.getName() and
|
||||
// p.getStaticType() != "Object" and
|
||||
// c.getName() = f.getName()
|
||||
// select a, "argument has a specified static type"
|
||||
|
||||
// from Argument a, VarReadAccess v
|
||||
// where a.getAChild() = v and
|
||||
// v.getVariable().getName() = "UserInput"
|
||||
// select a, v
|
||||
|
||||
// from Argument e
|
||||
// where e.getLocation().getFile().getBaseName() = "sanitizers.ps1"
|
||||
// and e.getLocation().getStartLine() = 14
|
||||
// select e, e.getAChild(), e.getParent(), e.toString()
|
||||
|
||||
// from PipelineParameter p
|
||||
// where p.getLocation().getFile().getBaseName() = "userinput.ps1"
|
||||
// select p, p.getName(), p.getAChild()
|
||||
|
||||
// from Attribute a
|
||||
// select a, a.getParent(), a.getParent().getAQlClass(), a.getANamedArgument()
|
||||
|
||||
|
||||
|
||||
// from Expr e
|
||||
// where e.getLocation().getFile().getBaseName() = "sanitizers.ps1"
|
||||
// and e.getLocation().getStartLine() = 31
|
||||
// select e, e.getAQlClass()
|
||||
|
||||
// from InvokeMemberExpr ie
|
||||
// where
|
||||
// ie.getLocation().getStartLine() = 28 and ie.getName() = "AddScript"
|
||||
// select ie, ie.getName(), ie.getQualifier().toString(), ie.getQualifier().getAChild().toString(), ie.getParent().(InvokeMemberExpr).getName()
|
||||
@@ -0,0 +1,152 @@
|
||||
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"
|
||||
}
|
||||
}
|
||||
@@ -8,33 +8,41 @@
|
||||
routine that executes a command, allows the user to execute malicious
|
||||
code.</p>
|
||||
|
||||
<p>This is a port of the InjectionHunter tool by Lee Holmes, and checks when user input is passed to any of the following:</p>
|
||||
<ul>
|
||||
<li>Invoke-Expression</li>
|
||||
<li>InvokeScript</li>
|
||||
<li>CreateNestedPipeline</li>
|
||||
<li>AddScript</li>
|
||||
<li>powershell</li>
|
||||
<li>cmd</li>
|
||||
<li>Foreach-Object</li>
|
||||
<li>Invoke</li>
|
||||
<li>CreateScriptBlock</li>
|
||||
<li>NewScriptBlock</li>
|
||||
<li>ExpandString</li>
|
||||
</ul>
|
||||
|
||||
</overview>
|
||||
<recommendation>
|
||||
|
||||
<p>Possible script injection risk via the Invoke-Expression cmdlet. Untrusted input can cause arbitrary PowerShell expressions to be run.
|
||||
<p>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.</p>
|
||||
|
||||
</recommendation>
|
||||
<example>
|
||||
|
||||
<p>The following example shows code that takes a shell script that can be changed
|
||||
maliciously by a user, and passes it straight to <code>Invoke-Expression</code>
|
||||
without examining it first.</p>
|
||||
|
||||
<sample src="examples/command_injection.ps1" />
|
||||
|
||||
</example>
|
||||
<references>
|
||||
|
||||
<li>
|
||||
OWASP:
|
||||
<a href="https://www.owasp.org/index.php/Command_Injection">Command Injection</a>.
|
||||
</li>
|
||||
|
||||
<!-- LocalWords: CWE untrusted unsanitized Runtime
|
||||
-->
|
||||
<li>
|
||||
Injection Hunter:
|
||||
<a href="https://devblogs.microsoft.com/powershell/powershell-injection-hunter-security-auditing-for-powershell-scripts/">PowerShell Injection Hunter: Security Auditing for PowerShell Scripts</a>.
|
||||
</li>
|
||||
|
||||
</references>
|
||||
</qhelp>
|
||||
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* @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<InjectionConfig>;
|
||||
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()
|
||||
@@ -0,0 +1,146 @@
|
||||
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 |
|
||||
@@ -0,0 +1 @@
|
||||
queries/security/cwe-078/InjectionHunter/UserInputToDangerousMethod.ql
|
||||
@@ -0,0 +1,221 @@
|
||||
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
|
||||
Reference in New Issue
Block a user