1- /** Provides class and predicates to track external data that
1+ /**
2+ * Provides class and predicates to track external data that
23 * may represent malicious OS commands.
34 *
45 * This module is intended to be imported into a taint-tracking query
56 * to extend `TaintKind` and `TaintSink`.
6- *
77 */
8- import python
98
9+ import python
1010import semmle.python.security.TaintTracking
1111import semmle.python.security.strings.Untrusted
1212
@@ -19,8 +19,7 @@ private ModuleObject osOrPopenModule() {
1919}
2020
2121private Object makeOsCall ( ) {
22- exists ( string name |
23- result = ModuleObject:: named ( "subprocess" ) .attr ( name ) |
22+ exists ( string name | result = ModuleObject:: named ( "subprocess" ) .attr ( name ) |
2423 name = "Popen" or
2524 name = "call" or
2625 name = "check_call" or
@@ -31,40 +30,27 @@ private Object makeOsCall() {
3130
3231/**Special case for first element in sequence. */
3332class FirstElementKind extends TaintKind {
33+ FirstElementKind ( ) { this = "sequence[" + any ( ExternalStringKind key ) + "][0]" }
3434
35- FirstElementKind ( ) {
36- this = "sequence[" + any ( ExternalStringKind key ) + "][0]"
37- }
38-
39- override string repr ( ) {
40- result = "first item in sequence of " + this .getItem ( ) .repr ( )
41- }
35+ override string repr ( ) { result = "first item in sequence of " + this .getItem ( ) .repr ( ) }
4236
4337 /** Gets the taint kind for item in this sequence. */
44- ExternalStringKind getItem ( ) {
45- this = "sequence[" + result + "][0]"
46- }
47-
38+ ExternalStringKind getItem ( ) { this = "sequence[" + result + "][0]" }
4839}
4940
5041class FirstElementFlow extends DataFlowExtension:: DataFlowNode {
42+ FirstElementFlow ( ) { this = any ( SequenceNode s ) .getElement ( 0 ) }
5143
52- FirstElementFlow ( ) {
53- this = any ( SequenceNode s ) .getElement ( 0 )
54- }
55-
56- override
57- ControlFlowNode getASuccessorNode ( TaintKind fromkind , TaintKind tokind ) {
44+ override ControlFlowNode getASuccessorNode ( TaintKind fromkind , TaintKind tokind ) {
5845 result .( SequenceNode ) .getElement ( 0 ) = this and tokind .( FirstElementKind ) .getItem ( ) = fromkind
5946 }
60-
6147}
6248
63- /** A taint sink that is potentially vulnerable to malicious shell commands.
49+ /**
50+ * A taint sink that is potentially vulnerable to malicious shell commands.
6451 * The `vuln` in `subprocess.call(shell=vuln)` and similar calls.
6552 */
6653class ShellCommand extends CommandSink {
67-
6854 override string toString ( ) { result = "shell command" }
6955
7056 ShellCommand ( ) {
@@ -77,7 +63,8 @@ class ShellCommand extends CommandSink {
7763 or
7864 exists ( CallNode call , string name |
7965 call .getAnArg ( ) = this and
80- call .getFunction ( ) .refersTo ( osOrPopenModule ( ) .attr ( name ) ) |
66+ call .getFunction ( ) .refersTo ( osOrPopenModule ( ) .attr ( name ) )
67+ |
8168 name = "system" or
8269 name = "popen" or
8370 name .matches ( "popen_" )
@@ -96,19 +83,18 @@ class ShellCommand extends CommandSink {
9683 /* List (or tuple) containing a tainted string command */
9784 kind instanceof ExternalStringSequenceKind
9885 }
99-
10086}
10187
102- /** A taint sink that is potentially vulnerable to malicious shell commands.
88+ /**
89+ * A taint sink that is potentially vulnerable to malicious shell commands.
10390 * The `vuln` in `subprocess.call(vuln, ...)` and similar calls.
10491 */
10592class OsCommandFirstArgument extends CommandSink {
106-
10793 override string toString ( ) { result = "OS command first argument" }
10894
10995 OsCommandFirstArgument ( ) {
11096 not this instanceof ShellCommand and
111- exists ( CallNode call |
97+ exists ( CallNode call |
11298 call .getFunction ( ) .refersTo ( makeOsCall ( ) ) and
11399 call .getArg ( 0 ) = this
114100 )
@@ -121,7 +107,6 @@ class OsCommandFirstArgument extends CommandSink {
121107 /* List (or tuple) whose first element is tainted */
122108 kind instanceof FirstElementKind
123109 }
124-
125110}
126111
127112// -------------------------------------------------------------------------- //
@@ -130,8 +115,8 @@ class OsCommandFirstArgument extends CommandSink {
130115// Since fabric build so closely upon invoke, we model them together to avoid
131116// duplication
132117// -------------------------------------------------------------------------- //
133-
134- /* * A taint sink that is potentially vulnerable to malicious shell commands.
118+ /**
119+ * A taint sink that is potentially vulnerable to malicious shell commands.
135120 * The `vuln` in `invoke.run(vuln, ...)` and similar calls.
136121 */
137122class InvokeRun extends CommandSink {
@@ -143,12 +128,11 @@ class InvokeRun extends CommandSink {
143128
144129 override string toString ( ) { result = "InvokeRun" }
145130
146- override predicate sinks ( TaintKind kind ) {
147- kind instanceof ExternalStringKind
148- }
131+ override predicate sinks ( TaintKind kind ) { kind instanceof ExternalStringKind }
149132}
150133
151- /** Internal TaintKind to track the invoke.Context instance passed to functions
134+ /**
135+ * Internal TaintKind to track the invoke.Context instance passed to functions
152136 * marked with @invoke.task
153137 */
154138private class InvokeContextArg extends TaintKind {
@@ -164,7 +148,6 @@ private class InvokeContextArgSource extends TaintSource {
164148 decorator = f .getADecorator ( ) and not decorator instanceof Call
165149 or
166150 decorator = f .getADecorator ( ) .( Call ) .getFunc ( )
167-
168151 ) and
169152 (
170153 decorator .pointsTo ( Value:: named ( "invoke.task" ) )
@@ -176,12 +159,11 @@ private class InvokeContextArgSource extends TaintSource {
176159 )
177160 }
178161
179- override predicate isSourceOf ( TaintKind kind ) {
180- kind instanceof InvokeContextArg
181- }
162+ override predicate isSourceOf ( TaintKind kind ) { kind instanceof InvokeContextArg }
182163}
183164
184- /** A taint sink that is potentially vulnerable to malicious shell commands.
165+ /**
166+ * A taint sink that is potentially vulnerable to malicious shell commands.
185167 * The `vuln` in `invoke.Context().run(vuln, ...)` and similar calls.
186168 */
187169class InvokeContextRun extends CommandSink {
@@ -195,7 +177,8 @@ class InvokeContextRun extends CommandSink {
195177 // since fabric.Connection.run has a decorator, it doesn't work with FunctionValue :|
196178 // and `Value::named("fabric.Connection").(ClassValue).lookup("run").getACall()` returned no results,
197179 // so here is the hacky solution that works :\
198- call .getFunction ( ) .( AttrNode ) .getObject ( "run" ) .pointsTo ( ) .getClass ( ) = Value:: named ( "fabric.Connection" )
180+ call .getFunction ( ) .( AttrNode ) .getObject ( "run" ) .pointsTo ( ) .getClass ( ) =
181+ Value:: named ( "fabric.Connection" )
199182 |
200183 this = call .getArg ( 0 )
201184 or
@@ -205,38 +188,33 @@ class InvokeContextRun extends CommandSink {
205188
206189 override string toString ( ) { result = "InvokeContextRun" }
207190
208- override predicate sinks ( TaintKind kind ) {
209- kind instanceof ExternalStringKind
210- }
191+ override predicate sinks ( TaintKind kind ) { kind instanceof ExternalStringKind }
211192}
212193
213- /** A taint sink that is potentially vulnerable to malicious shell commands.
194+ /**
195+ * A taint sink that is potentially vulnerable to malicious shell commands.
214196 * The `vuln` in `fabric.Group().run(vuln, ...)` and similar calls.
215197 */
216198class FabricGroupRun extends CommandSink {
217199 FabricGroupRun ( ) {
218200 exists ( ClassValue cls |
219- cls .getASuperType ( ) = Value:: named ( "fabric.Group" ) and
201+ cls .getASuperType ( ) = Value:: named ( "fabric.Group" ) and
220202 this = cls .lookup ( "run" ) .( FunctionValue ) .getArgumentForCall ( _, 1 )
221203 )
222204 }
223205
224206 override string toString ( ) { result = "FabricGroupRun" }
225207
226- override predicate sinks ( TaintKind kind ) {
227- kind instanceof ExternalStringKind
228- }
208+ override predicate sinks ( TaintKind kind ) { kind instanceof ExternalStringKind }
229209}
230210
231-
232211// -------------------------------------------------------------------------- //
233212// Modeling of the 'invoke' package and 'fabric' package (v 1.x)
234213// -------------------------------------------------------------------------- //
235214class FabricV1Commands extends CommandSink {
236215 FabricV1Commands ( ) {
237216 // since `run` and `sudo` are decorated, we can't use FunctionValue's :(
238- exists ( CallNode call
239- |
217+ exists ( CallNode call |
240218 call = Value:: named ( "fabric.api.local" ) .getACall ( )
241219 or
242220 call = Value:: named ( "fabric.api.run" ) .getACall ( )
@@ -251,7 +229,5 @@ class FabricV1Commands extends CommandSink {
251229
252230 override string toString ( ) { result = "FabricV1Commands" }
253231
254- override predicate sinks ( TaintKind kind ) {
255- kind instanceof ExternalStringKind
256- }
232+ override predicate sinks ( TaintKind kind ) { kind instanceof ExternalStringKind }
257233}
0 commit comments