@@ -18,49 +18,34 @@ import semmle.python.dataflow.new.RemoteFlowSources
1818import semmle.python.ApiGraphs
1919import DataFlow:: PathGraph
2020
21+ private API:: Node paramikoClient ( ) {
22+ result = API:: moduleImport ( "paramiko" ) .getMember ( "SSHClient" ) .getReturn ( )
23+ }
24+
2125class ParamikoCMDInjectionConfiguration extends TaintTracking:: Configuration {
2226 ParamikoCMDInjectionConfiguration ( ) { this = "ParamikoCMDInjectionConfiguration" }
2327
2428 override predicate isSource ( DataFlow:: Node source ) { source instanceof RemoteFlowSource }
2529
30+ /**
31+ * exec_command of `paramiko.SSHClient` class execute command on ssh target server
32+ * the `paramiko.ProxyCommand` is equivalent of `ssh -o ProxyCommand="CMD"`
33+ * and it run CMD on current system that running the ssh command
34+ * the Sink related to proxy command is the `connect` method of `paramiko.SSHClient` class
35+ */
2636 override predicate isSink ( DataFlow:: Node sink ) {
27- sink =
28- [
29- API:: moduleImport ( "paramiko" )
30- .getMember ( "SSHClient" )
31- .getReturn ( )
32- .getMember ( "exec_command" )
33- .getACall ( )
34- .getArgByName ( "command" ) ,
35- API:: moduleImport ( "paramiko" )
36- .getMember ( "SSHClient" )
37- .getReturn ( )
38- .getMember ( "exec_command" )
39- .getACall ( )
40- .getArg ( 0 )
41- ]
37+ sink = paramikoClient ( ) .getMember ( "exec_command" ) .getACall ( ) .getParameter ( 0 , "command" ) .asSink ( )
4238 or
43- sink =
44- [
45- API:: moduleImport ( "paramiko" )
46- .getMember ( "SSHClient" )
47- .getReturn ( )
48- .getMember ( "connect" )
49- .getACall ( )
50- .getArgByName ( "sock" ) ,
51- API:: moduleImport ( "paramiko" )
52- .getMember ( "SSHClient" )
53- .getReturn ( )
54- .getMember ( "connect" )
55- .getACall ( )
56- .getArg ( 11 )
57- ]
39+ sink = paramikoClient ( ) .getMember ( "connect" ) .getACall ( ) .getParameter ( 11 , "sock" ) .asSink ( )
5840 }
5941
42+ /**
43+ * this additional taint step help taint tracking to find the vulnerable `connect` method of `paramiko.SSHClient` class
44+ */
6045 override predicate isAdditionalTaintStep ( DataFlow:: Node nodeFrom , DataFlow:: Node nodeTo ) {
6146 exists ( API:: CallNode call |
6247 call = API:: moduleImport ( "paramiko" ) .getMember ( "ProxyCommand" ) .getACall ( ) and
63- nodeFrom = [ call .getArg ( 0 ) , call . getArgByName ( "command_line" ) ] and
48+ nodeFrom = call .getParameter ( 0 , "command_line" ) . asSink ( ) and
6449 nodeTo = call
6550 )
6651 }
0 commit comments