Skip to content

Commit b567205

Browse files
committed
Python: Model fabric v1.x command injection sinks
1 parent a57eada commit b567205

File tree

5 files changed

+72
-6
lines changed

5 files changed

+72
-6
lines changed

python/ql/src/semmle/python/security/injection/Command.qll

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,3 +227,31 @@ class FabricGroupRun extends CommandSink {
227227
kind instanceof ExternalStringKind
228228
}
229229
}
230+
231+
232+
// -------------------------------------------------------------------------- //
233+
// Modeling of the 'invoke' package and 'fabric' package (v 1.x)
234+
// -------------------------------------------------------------------------- //
235+
class FabricV1Commands extends CommandSink {
236+
FabricV1Commands() {
237+
// since `run` and `sudo` are decorated, we can't use FunctionValue's :(
238+
exists(CallNode call
239+
|
240+
call = Value::named("fabric.api.local").getACall()
241+
or
242+
call = Value::named("fabric.api.run").getACall()
243+
or
244+
call = Value::named("fabric.api.sudo").getACall()
245+
|
246+
this = call.getArg(0)
247+
or
248+
this = call.getArgByName("command")
249+
)
250+
}
251+
252+
override string toString() { result = "FabricV1Commands" }
253+
254+
override predicate sinks(TaintKind kind) {
255+
kind instanceof ExternalStringKind
256+
}
257+
}

python/ql/test/library-tests/security/command-execution/CommandSinks.expected

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
1-
| fabric_test.py:10:16:10:25 | InvokeContextRun | externally controlled string |
2-
| fabric_test.py:12:15:12:36 | InvokeContextRun | externally controlled string |
3-
| fabric_test.py:16:45:16:54 | FabricGroupRun | externally controlled string |
4-
| fabric_test.py:21:10:21:13 | FabricGroupRun | externally controlled string |
5-
| fabric_test.py:31:14:31:41 | InvokeContextRun | externally controlled string |
6-
| fabric_test.py:33:15:33:64 | InvokeContextRun | externally controlled string |
1+
| fabric_v1_test.py:8:7:8:28 | FabricV1Commands | externally controlled string |
2+
| fabric_v1_test.py:9:5:9:27 | FabricV1Commands | externally controlled string |
3+
| fabric_v1_test.py:10:6:10:38 | FabricV1Commands | externally controlled string |
4+
| fabric_v2_test.py:10:16:10:25 | InvokeContextRun | externally controlled string |
5+
| fabric_v2_test.py:12:15:12:36 | InvokeContextRun | externally controlled string |
6+
| fabric_v2_test.py:16:45:16:54 | FabricGroupRun | externally controlled string |
7+
| fabric_v2_test.py:21:10:21:13 | FabricGroupRun | externally controlled string |
8+
| fabric_v2_test.py:31:14:31:41 | InvokeContextRun | externally controlled string |
9+
| fabric_v2_test.py:33:15:33:64 | InvokeContextRun | externally controlled string |
710
| invoke_test.py:8:12:8:21 | InvokeRun | externally controlled string |
811
| invoke_test.py:9:20:9:40 | InvokeRun | externally controlled string |
912
| invoke_test.py:12:17:12:24 | InvokeRun | externally controlled string |
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
"""tests for the 'fabric' package (v1.x)
2+
3+
See http://docs.fabfile.org/en/1.14/tutorial.html
4+
"""
5+
6+
from fabric.api import run, local, sudo
7+
8+
local('echo local execution')
9+
run('echo remote execution')
10+
sudo('echo remote execution with sudo')
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# For the 1.x version
2+
3+
def needs_host(func):
4+
@wraps(func)
5+
def inner(*args, **kwargs):
6+
return func(*args, **kwargs)
7+
return inner
8+
9+
10+
def local(command, capture=False, shell=None):
11+
pass
12+
13+
14+
@needs_host
15+
def run(command, shell=True, pty=True, combine_stderr=None, quiet=False,
16+
warn_only=False, stdout=None, stderr=None, timeout=None, shell_escape=None,
17+
capture_buffer_size=None):
18+
pass
19+
20+
21+
@needs_host
22+
def sudo(command, shell=True, pty=True, combine_stderr=None, user=None,
23+
quiet=False, warn_only=False, stdout=None, stderr=None, group=None,
24+
timeout=None, shell_escape=None, capture_buffer_size=None):
25+
pass

0 commit comments

Comments
 (0)