Skip to content

Commit bfcc194

Browse files
committed
Python: Move experimental paramiko to new dataflow API
1 parent acd0f2a commit bfcc194

File tree

2 files changed

+14
-10
lines changed

2 files changed

+14
-10
lines changed

python/ql/src/experimental/Security/CWE-074/paramiko/paramiko.ql

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,24 +16,21 @@ import semmle.python.dataflow.new.DataFlow
1616
import semmle.python.dataflow.new.TaintTracking
1717
import semmle.python.dataflow.new.RemoteFlowSources
1818
import semmle.python.ApiGraphs
19-
import DataFlow::PathGraph
2019

2120
private API::Node paramikoClient() {
2221
result = API::moduleImport("paramiko").getMember("SSHClient").getReturn()
2322
}
2423

25-
class ParamikoCmdInjectionConfiguration extends TaintTracking::Configuration {
26-
ParamikoCmdInjectionConfiguration() { this = "ParamikoCMDInjectionConfiguration" }
27-
28-
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
24+
private module ParamikoConfig implements DataFlow::ConfigSig {
25+
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
2926

3027
/**
3128
* exec_command of `paramiko.SSHClient` class execute command on ssh target server
3229
* the `paramiko.ProxyCommand` is equivalent of `ssh -o ProxyCommand="CMD"`
3330
* and it run CMD on current system that running the ssh command
3431
* the Sink related to proxy command is the `connect` method of `paramiko.SSHClient` class
3532
*/
36-
override predicate isSink(DataFlow::Node sink) {
33+
predicate isSink(DataFlow::Node sink) {
3734
sink = paramikoClient().getMember("exec_command").getACall().getParameter(0, "command").asSink()
3835
or
3936
sink = paramikoClient().getMember("connect").getACall().getParameter(11, "sock").asSink()
@@ -42,7 +39,7 @@ class ParamikoCmdInjectionConfiguration extends TaintTracking::Configuration {
4239
/**
4340
* this additional taint step help taint tracking to find the vulnerable `connect` method of `paramiko.SSHClient` class
4441
*/
45-
override predicate isAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
42+
predicate isAdditionalFlowStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
4643
exists(API::CallNode call |
4744
call = API::moduleImport("paramiko").getMember("ProxyCommand").getACall() and
4845
nodeFrom = call.getParameter(0, "command_line").asSink() and
@@ -51,7 +48,12 @@ class ParamikoCmdInjectionConfiguration extends TaintTracking::Configuration {
5148
}
5249
}
5350

54-
from ParamikoCmdInjectionConfiguration config, DataFlow::PathNode source, DataFlow::PathNode sink
55-
where config.hasFlowPath(source, sink)
51+
/** Global taint-tracking for detecting "paramiko command injection" vulnerabilities. */
52+
module ParamikoFlow = TaintTracking::Global<ParamikoConfig>;
53+
54+
import ParamikoFlow::PathGraph
55+
56+
from ParamikoFlow::PathNode source, ParamikoFlow::PathNode sink
57+
where ParamikoFlow::flowPath(source, sink)
5658
select sink.getNode(), source, sink, "This code execution depends on a $@.", source.getNode(),
5759
"a user-provided value"

python/ql/test/experimental/query-tests/Security/CWE-074-paramiko/paramiko.expected

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
edges
22
| paramiko.py:15:21:15:23 | ControlFlowNode for cmd | paramiko.py:16:62:16:64 | ControlFlowNode for cmd |
33
| paramiko.py:20:21:20:23 | ControlFlowNode for cmd | paramiko.py:21:70:21:72 | ControlFlowNode for cmd |
4-
| paramiko.py:25:21:25:23 | ControlFlowNode for cmd | paramiko.py:26:114:26:139 | ControlFlowNode for Attribute() |
4+
| paramiko.py:25:21:25:23 | ControlFlowNode for cmd | paramiko.py:26:136:26:138 | ControlFlowNode for cmd |
5+
| paramiko.py:26:136:26:138 | ControlFlowNode for cmd | paramiko.py:26:114:26:139 | ControlFlowNode for Attribute() |
56
nodes
67
| paramiko.py:15:21:15:23 | ControlFlowNode for cmd | semmle.label | ControlFlowNode for cmd |
78
| paramiko.py:16:62:16:64 | ControlFlowNode for cmd | semmle.label | ControlFlowNode for cmd |
89
| paramiko.py:20:21:20:23 | ControlFlowNode for cmd | semmle.label | ControlFlowNode for cmd |
910
| paramiko.py:21:70:21:72 | ControlFlowNode for cmd | semmle.label | ControlFlowNode for cmd |
1011
| paramiko.py:25:21:25:23 | ControlFlowNode for cmd | semmle.label | ControlFlowNode for cmd |
1112
| paramiko.py:26:114:26:139 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
13+
| paramiko.py:26:136:26:138 | ControlFlowNode for cmd | semmle.label | ControlFlowNode for cmd |
1214
subpaths
1315
#select
1416
| paramiko.py:16:62:16:64 | ControlFlowNode for cmd | paramiko.py:15:21:15:23 | ControlFlowNode for cmd | paramiko.py:16:62:16:64 | ControlFlowNode for cmd | This code execution depends on a $@. | paramiko.py:15:21:15:23 | ControlFlowNode for cmd | a user-provided value |

0 commit comments

Comments
 (0)