File tree Expand file tree Collapse file tree 8 files changed +55
-64
lines changed
python/ql/src/experimental/semmle/python Expand file tree Collapse file tree 8 files changed +55
-64
lines changed Original file line number Diff line number Diff line change @@ -15,12 +15,23 @@ private import semmle.python.dataflow.new.TaintTracking
15
15
private import experimental.semmle.python.Frameworks
16
16
private import semmle.python.Concepts
17
17
18
- /**
19
- * A data-flow node that responsible for a command that can be executed on a secondary remote system,
20
- *
21
- * Extend this class to model new APIs.
22
- */
23
- abstract class SecondaryCommandInjection extends DataFlow:: Node { }
18
+ /** Provides classes for modeling remote server command execution related APIs. */
19
+ module RemoteCommandExecution {
20
+ /**
21
+ * A data-flow node that executes an operating system command,
22
+ * on a remote server likely by SSH connections.
23
+ *
24
+ * Extend this class to model new APIs. If you want to refine existing API models,
25
+ * extend `SystemCommandExecution` instead.
26
+ */
27
+ abstract class Range extends DataFlow:: Node {
28
+ /** Gets the argument that specifies the command to be executed. */
29
+ abstract DataFlow:: Node getCommand ( ) ;
30
+
31
+ /** Holds if a shell interprets `arg`. */
32
+ predicate isShellInterpreted ( DataFlow:: Node arg ) { none ( ) }
33
+ }
34
+ }
24
35
25
36
/** Provides classes for modeling copying file related APIs. */
26
37
module CopyFile {
Original file line number Diff line number Diff line change @@ -22,16 +22,9 @@ private module Asyncssh {
22
22
/**
23
23
* A `run` method responsible for executing commands on remote secondary servers.
24
24
*/
25
- class AsyncsshRun extends SecondaryCommandInjection {
26
- AsyncsshRun ( ) {
27
- this =
28
- asyncssh ( )
29
- .getMember ( "connect" )
30
- .getReturn ( )
31
- .getMember ( "run" )
32
- .getACall ( )
33
- .getParameter ( 0 , "command" )
34
- .asSink ( )
35
- }
25
+ class AsyncsshRun extends RemoteCommandExecution:: Range , API:: CallNode {
26
+ AsyncsshRun ( ) { this = asyncssh ( ) .getMember ( "connect" ) .getReturn ( ) .getMember ( "run" ) .getACall ( ) }
27
+
28
+ override DataFlow:: Node getCommand ( ) { result = this .getParameter ( 0 , "command" ) .asSink ( ) }
36
29
}
37
30
}
Original file line number Diff line number Diff line change @@ -29,21 +29,27 @@ private module Netmiko {
29
29
/**
30
30
* The `send_*` methods responsible for executing commands on remote secondary servers.
31
31
*/
32
- class NetmikoSendCommand extends SecondaryCommandInjection {
32
+ class NetmikoSendCommand extends RemoteCommandExecution:: Range , API:: CallNode {
33
+ boolean isMultiline ;
34
+
33
35
NetmikoSendCommand ( ) {
34
36
this =
35
37
netmikoConnectHandler ( )
36
38
.getMember ( [ "send_command" , "send_command_expect" , "send_command_timing" ] )
37
- .getACall ( )
38
- .getParameter ( 0 , "command_string" )
39
- .asSink ( )
39
+ .getACall ( ) and
40
+ isMultiline = false
40
41
or
41
42
this =
42
- netmikoConnectHandler ( )
43
- .getMember ( [ "send_multiline" , "send_multiline_timing" ] )
44
- .getACall ( )
45
- .getParameter ( 0 , "commands" )
46
- .asSink ( )
43
+ netmikoConnectHandler ( ) .getMember ( [ "send_multiline" , "send_multiline_timing" ] ) .getACall ( ) and
44
+ isMultiline = true
45
+ }
46
+
47
+ override DataFlow:: Node getCommand ( ) {
48
+ result = this .getParameter ( 0 , "command_string" ) .asSink ( ) and
49
+ isMultiline = false
50
+ or
51
+ result = this .getParameter ( 0 , "commands" ) .asSink ( ) and
52
+ isMultiline = true
47
53
}
48
54
}
49
55
}
Original file line number Diff line number Diff line change @@ -27,10 +27,9 @@ private module Paramiko {
27
27
/**
28
28
* The `exec_command` of `paramiko.SSHClient` class execute command on ssh target server
29
29
*/
30
- class ParamikoExecCommand extends SecondaryCommandInjection {
31
- ParamikoExecCommand ( ) {
32
- this =
33
- paramikoClient ( ) .getMember ( "exec_command" ) .getACall ( ) .getParameter ( 0 , "command" ) .asSink ( )
34
- }
30
+ class ParamikoExecCommand extends RemoteCommandExecution:: Range , API:: CallNode {
31
+ ParamikoExecCommand ( ) { this = paramikoClient ( ) .getMember ( "exec_command" ) .getACall ( ) }
32
+
33
+ override DataFlow:: Node getCommand ( ) { result = this .getParameter ( 0 , "command" ) .asSink ( ) }
35
34
}
36
35
}
Original file line number Diff line number Diff line change @@ -17,7 +17,7 @@ private module Pexpect {
17
17
* The calls to `pexpect.pxssh.pxssh` functions that execute commands
18
18
* See https://pexpect.readthedocs.io/en/stable/api/pxssh.html
19
19
*/
20
- class PexpectCommandExec extends SecondaryCommandInjection {
20
+ class PexpectCommandExec extends RemoteCommandExecution :: Range , API :: CallNode {
21
21
PexpectCommandExec ( ) {
22
22
this =
23
23
API:: moduleImport ( "pexpect" )
@@ -26,8 +26,8 @@ private module Pexpect {
26
26
.getReturn ( )
27
27
.getMember ( [ "send" , "sendline" ] )
28
28
.getACall ( )
29
- .getParameter ( 0 , "s" )
30
- .asSink ( )
31
29
}
30
+
31
+ override DataFlow:: Node getCommand ( ) { result = this .getParameter ( 0 , "s" ) .asSink ( ) }
32
32
}
33
33
}
Original file line number Diff line number Diff line change @@ -32,7 +32,7 @@ private module Scrapli {
32
32
/**
33
33
* A `send_command` method responsible for executing commands on remote secondary servers.
34
34
*/
35
- class ScrapliSendCommand extends SecondaryCommandInjection {
35
+ class ScrapliSendCommand extends RemoteCommandExecution :: Range , API :: CallNode {
36
36
ScrapliSendCommand ( ) {
37
37
this =
38
38
scrapliCore ( )
@@ -44,26 +44,13 @@ private module Scrapli {
44
44
.getReturn ( )
45
45
.getMember ( "send_command" )
46
46
.getACall ( )
47
- .getParameter ( 0 , "command" )
48
- .asSink ( )
49
47
or
50
- this =
51
- scrapli ( )
52
- .getMember ( "Scrapli" )
53
- .getReturn ( )
54
- .getMember ( "send_command" )
55
- .getACall ( )
56
- .getParameter ( 0 , "command" )
57
- .asSink ( )
48
+ this = scrapli ( ) .getMember ( "Scrapli" ) .getReturn ( ) .getMember ( "send_command" ) .getACall ( )
58
49
or
59
50
this =
60
- scrapliDriver ( )
61
- .getMember ( "GenericDriver" )
62
- .getReturn ( )
63
- .getMember ( "send_command" )
64
- .getACall ( )
65
- .getParameter ( 0 , "command" )
66
- .asSink ( )
51
+ scrapliDriver ( ) .getMember ( "GenericDriver" ) .getReturn ( ) .getMember ( "send_command" ) .getACall ( )
67
52
}
53
+
54
+ override DataFlow:: Node getCommand ( ) { result = this .getParameter ( 0 , "command" ) .asSink ( ) }
68
55
}
69
56
}
Original file line number Diff line number Diff line change @@ -29,16 +29,11 @@ private module Ssh2 {
29
29
/**
30
30
* An `execute` method responsible for executing commands on remote secondary servers.
31
31
*/
32
- class Ssh2Execute extends SecondaryCommandInjection {
32
+ class Ssh2Execute extends RemoteCommandExecution :: Range , API :: CallNode {
33
33
Ssh2Execute ( ) {
34
- this =
35
- ssh2Session ( )
36
- .getMember ( "open_session" )
37
- .getReturn ( )
38
- .getMember ( "execute" )
39
- .getACall ( )
40
- .getParameter ( 0 , "command" )
41
- .asSink ( )
34
+ this = ssh2Session ( ) .getMember ( "open_session" ) .getReturn ( ) .getMember ( "execute" ) .getACall ( )
42
35
}
36
+
37
+ override DataFlow:: Node getCommand ( ) { result = this .getParameter ( 0 , "command" ) .asSink ( ) }
43
38
}
44
39
}
Original file line number Diff line number Diff line change @@ -19,7 +19,7 @@ private module Twisted {
19
19
/**
20
20
* The `newConnection` and `existingConnection` functions of `twisted.conch.endpoints.SSHCommandClientEndpoint` class execute command on ssh target server
21
21
*/
22
- class ParamikoExecCommand extends SecondaryCommandInjection {
22
+ class ParamikoExecCommand extends RemoteCommandExecution :: Range , API :: CallNode {
23
23
ParamikoExecCommand ( ) {
24
24
this =
25
25
API:: moduleImport ( "twisted" )
@@ -28,8 +28,8 @@ private module Twisted {
28
28
.getMember ( "SSHCommandClientEndpoint" )
29
29
.getMember ( [ "newConnection" , "existingConnection" ] )
30
30
.getACall ( )
31
- .getParameter ( 1 , "command" )
32
- .asSink ( )
33
31
}
32
+
33
+ override DataFlow:: Node getCommand ( ) { result = this .getParameter ( 1 , "command" ) .asSink ( ) }
34
34
}
35
35
}
You can’t perform that action at this time.
0 commit comments