From 3c18124faf91a50f91db4e910f37b61bb2a82b82 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Wed, 16 Oct 2024 18:16:50 +0100 Subject: [PATCH 1/5] PS: Add taint-tracking files. --- .../code/powershell/dataflow/TaintTracking.qll | 12 ++++++++++++ .../dataflow/internal/TaintTrackingImpl.qll | 7 +++++++ 2 files changed, 19 insertions(+) create mode 100644 powershell/ql/lib/semmle/code/powershell/dataflow/TaintTracking.qll create mode 100644 powershell/ql/lib/semmle/code/powershell/dataflow/internal/TaintTrackingImpl.qll diff --git a/powershell/ql/lib/semmle/code/powershell/dataflow/TaintTracking.qll b/powershell/ql/lib/semmle/code/powershell/dataflow/TaintTracking.qll new file mode 100644 index 00000000000..af2fc727f74 --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/dataflow/TaintTracking.qll @@ -0,0 +1,12 @@ +/** + * Provides classes for performing local (intra-procedural) and + * global (inter-procedural) taint-tracking analyses. + */ +module TaintTracking { + import semmle.code.powershell.dataflow.internal.TaintTrackingImpl::Public + private import semmle.code.powershell.dataflow.internal.DataFlowImplSpecific + private import semmle.code.powershell.dataflow.internal.TaintTrackingImplSpecific + private import codeql.dataflow.TaintTracking + private import powershell + import TaintFlowMake +} diff --git a/powershell/ql/lib/semmle/code/powershell/dataflow/internal/TaintTrackingImpl.qll b/powershell/ql/lib/semmle/code/powershell/dataflow/internal/TaintTrackingImpl.qll new file mode 100644 index 00000000000..e9b742f420b --- /dev/null +++ b/powershell/ql/lib/semmle/code/powershell/dataflow/internal/TaintTrackingImpl.qll @@ -0,0 +1,7 @@ +import semmle.code.powershell.dataflow.internal.TaintTrackingPublic as Public + +module Private { + import semmle.code.powershell.dataflow.DataFlow::DataFlow as DataFlow + import semmle.code.powershell.dataflow.internal.DataFlowImpl as DataFlowInternal + import semmle.code.powershell.dataflow.internal.TaintTrackingPrivate +} From d3b9e139c4c09310e45f483a356943a477d29718 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Wed, 16 Oct 2024 18:54:24 +0100 Subject: [PATCH 2/5] PS: Extend the set of sources in tests. --- powershell/ql/test/TestUtilities/InlineFlowTestUtil.qll | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/powershell/ql/test/TestUtilities/InlineFlowTestUtil.qll b/powershell/ql/test/TestUtilities/InlineFlowTestUtil.qll index b93d62063da..0712a650034 100644 --- a/powershell/ql/test/TestUtilities/InlineFlowTestUtil.qll +++ b/powershell/ql/test/TestUtilities/InlineFlowTestUtil.qll @@ -7,6 +7,8 @@ import semmle.code.powershell.dataflow.DataFlow predicate defaultSource(DataFlow::Node src) { src.asStmt().getStmt().(Cmd).getCommandName() = ["Source", "Taint"] + or + src.asParameter().getName().matches(["Source%", "Taint%"]) } predicate defaultSink(DataFlow::Node sink) { @@ -15,5 +17,9 @@ predicate defaultSink(DataFlow::Node sink) { string getSourceArgString(DataFlow::Node src) { defaultSource(src) and - src.asStmt().getStmt().(Cmd).getAnArgument().(StringConstExpr).getValue().getValue() = result + ( + src.asStmt().getStmt().(Cmd).getAnArgument().(StringConstExpr).getValue().getValue() = result + or + src.asParameter().getName().regexpCapture(["Source(.+)", "Taint(.+)"], 1) = result + ) } From 56c703ec80bd2d287e89d83e82e7cd4eec6d4f2d Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Wed, 16 Oct 2024 20:11:49 +0100 Subject: [PATCH 3/5] PS: Move a bunch of predicates into ScriptBlock. --- .../semmle/code/powershell/ScriptBlock.qll | 42 ++++++++++++++++++- .../powershell/controlflow/internal/Scope.qll | 28 +------------ 2 files changed, 42 insertions(+), 28 deletions(-) diff --git a/powershell/ql/lib/semmle/code/powershell/ScriptBlock.qll b/powershell/ql/lib/semmle/code/powershell/ScriptBlock.qll index 79691dbb6e5..4e6c7735223 100644 --- a/powershell/ql/lib/semmle/code/powershell/ScriptBlock.qll +++ b/powershell/ql/lib/semmle/code/powershell/ScriptBlock.qll @@ -10,7 +10,7 @@ class ScriptBlock extends @script_block, Ast { else result = "{...}" } - override SourceLocation getLocation() { script_block_location(this, result) } + override Location getLocation() { script_block_location(this, result) } int getNumUsings() { script_block(this, result, _, _, _, _) } @@ -51,6 +51,42 @@ class ScriptBlock extends @script_block, Ast { ModuleSpecification getAModuleSpecification() { result = this.getModuleSpecification(_) } final override Scope getEnclosingScope() { result = this } + + /** + * Gets the `i`'th paramter in this scope. + * + * This may be both function paramters and parameter block parameters. + */ + Parameter getParameter(int i) { + exists(Function func | + func.getBody() = this and + result = func.getParameter(i) + ) + or + this.isTopLevel() and + result = this.getParamBlock().getParameter(i) + } + + /** + * Gets a paramter in this scope. + * + * This may be both function parameters and parameter block parameters. + */ + Parameter getAParameter() { result = this.getParameter(_) } + + Parameter getThisParameter() { + exists(Function func | + func.getBody() = this and + result = func.getThisParameter() + ) + } + + /** Gets the number of function parameters. */ + final int getNumberOfParameters() { result = count(this.getAParameter()) } + + final Parameter getParameterExcludingPiplines(int i) { + result = this.getParamBlock().getParameterExcludingPiplines(i) + } } /** A `process` block. */ @@ -69,3 +105,7 @@ class ProcessBlock extends NamedBlock { result = scriptBlock.getEnclosingFunction().getAParameter() } } + +class TopLevelScriptBlock extends ScriptBlock { + TopLevelScriptBlock() { this.isTopLevel() } +} diff --git a/powershell/ql/lib/semmle/code/powershell/controlflow/internal/Scope.qll b/powershell/ql/lib/semmle/code/powershell/controlflow/internal/Scope.qll index c1c1fab1c97..49d182548fd 100644 --- a/powershell/ql/lib/semmle/code/powershell/controlflow/internal/Scope.qll +++ b/powershell/ql/lib/semmle/code/powershell/controlflow/internal/Scope.qll @@ -14,33 +14,7 @@ Scope scopeOf(Ast n) { * A variable scope. This is either a top-level (file), a module, a class, * or a callable. */ -class Scope extends Ast, @script_block { +class Scope extends Ast, ScriptBlock { /** Gets the outer scope, if any. */ Scope getOuterScope() { result = scopeOf(this) } - - /** - * Gets the `i`'th paramter in this scope. - * - * This may be both function paramters and parameter block parameters. - */ - Parameter getParameter(int i) { - exists(Function func | - func.getBody() = this and - result = func.getParameter(i) - ) - } - - /** - * Gets a paramter in this scope. - * - * This may be both function paramters and parameter block parameters. - */ - Parameter getAParameter() { result = this.getParameter(_) } - - Parameter getThisParameter() { - exists(Function func | - func.getBody() = this and - result = func.getThisParameter() - ) - } } From b426c1fc62a42bee83923e491605a7ba35ab34a9 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Wed, 16 Oct 2024 20:12:10 +0100 Subject: [PATCH 4/5] PS: Make top level a function as well. --- .../ql/lib/semmle/code/powershell/Function.qll | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/powershell/ql/lib/semmle/code/powershell/Function.qll b/powershell/ql/lib/semmle/code/powershell/Function.qll index c803a95b601..f3b1cea97bd 100644 --- a/powershell/ql/lib/semmle/code/powershell/Function.qll +++ b/powershell/ql/lib/semmle/code/powershell/Function.qll @@ -69,6 +69,8 @@ abstract private class AbstractFunction extends Ast { EntryBasicBlock getEntryBasicBlock() { result.getScope() = this.getBody() } } +final class Function = AbstractFunction; + /** * A function definition. */ @@ -114,4 +116,12 @@ class Constructor extends Method { Constructor() { this.isConstructor() } } -final class Function = FunctionBase; +class TopLevel extends AbstractFunction instanceof TopLevelScriptBlock { + final override string getName() { result = "toplevel" } + + final override ScriptBlock getBody() { result = this } + + final override Parameter getFunctionParameter(int i) { none() } + + final override Type getDeclaringType() { none() } +} From dec3e7191c7cc376f8bb5849826b8cb130d499fe Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Wed, 16 Oct 2024 20:15:01 +0100 Subject: [PATCH 5/5] PS: Add test and accept test changes. --- powershell/ql/test/library-tests/dataflow/params/global.ps1 | 3 +++ .../ql/test/library-tests/dataflow/params/test.expected | 4 ++++ 2 files changed, 7 insertions(+) create mode 100644 powershell/ql/test/library-tests/dataflow/params/global.ps1 diff --git a/powershell/ql/test/library-tests/dataflow/params/global.ps1 b/powershell/ql/test/library-tests/dataflow/params/global.ps1 new file mode 100644 index 00000000000..e3850e7715d --- /dev/null +++ b/powershell/ql/test/library-tests/dataflow/params/global.ps1 @@ -0,0 +1,3 @@ +param([string]$Source) + +Sink $Source # $ hasValueFlow \ No newline at end of file diff --git a/powershell/ql/test/library-tests/dataflow/params/test.expected b/powershell/ql/test/library-tests/dataflow/params/test.expected index aa6496a147f..5a477560675 100644 --- a/powershell/ql/test/library-tests/dataflow/params/test.expected +++ b/powershell/ql/test/library-tests/dataflow/params/test.expected @@ -1,5 +1,6 @@ models edges +| global.ps1:1:7:1:22 | Source | global.ps1:3:6:3:13 | Source | provenance | | | test.ps1:1:14:1:16 | a | test.ps1:2:10:2:12 | a | provenance | | | test.ps1:5:6:5:16 | Source | test.ps1:6:5:6:7 | x | provenance | | | test.ps1:6:5:6:7 | x | test.ps1:1:14:1:16 | a | provenance | | @@ -139,6 +140,8 @@ edges | test.ps1:39:24:39:31 | second | test.ps1:8:24:8:26 | y | provenance | | | test.ps1:39:32:39:38 | first | test.ps1:8:20:8:22 | x | provenance | | nodes +| global.ps1:1:7:1:22 | Source | semmle.label | Source | +| global.ps1:3:6:3:13 | Source | semmle.label | Source | | test.ps1:1:14:1:16 | a | semmle.label | a | | test.ps1:2:10:2:12 | a | semmle.label | a | | test.ps1:5:6:5:16 | Source | semmle.label | Source | @@ -221,6 +224,7 @@ nodes subpaths testFailures #select +| global.ps1:3:6:3:13 | Source | global.ps1:1:7:1:22 | Source | global.ps1:3:6:3:13 | Source | $@ | global.ps1:1:7:1:22 | Source | Source | | test.ps1:2:10:2:12 | a | test.ps1:5:6:5:16 | Source | test.ps1:2:10:2:12 | a | $@ | test.ps1:5:6:5:16 | Source | Source | | test.ps1:9:10:9:12 | x | test.ps1:14:10:14:20 | Source | test.ps1:9:10:9:12 | x | $@ | test.ps1:14:10:14:20 | Source | Source | | test.ps1:10:10:10:12 | y | test.ps1:15:11:15:21 | Source | test.ps1:10:10:10:12 | y | $@ | test.ps1:15:11:15:21 | Source | Source |