Skip to content

Commit 95c9a3f

Browse files
committed
add ssh client libraries, add SecondaryServerCmdInjectionCustomizations
1 parent 385c3ba commit 95c9a3f

File tree

7 files changed

+280
-34
lines changed

7 files changed

+280
-34
lines changed
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/**
2+
* Provides classes modeling security-relevant aspects of the `asyncssh` PyPI package.
3+
* See https://pypi.org/project/asyncssh/.
4+
*/
5+
6+
private import python
7+
private import semmle.python.dataflow.new.DataFlow
8+
private import semmle.python.dataflow.new.RemoteFlowSources
9+
private import semmle.python.Concepts
10+
private import semmle.python.ApiGraphs
11+
import experimental.semmle.python.security.SecondaryServerCmdInjectionCustomizations
12+
13+
/**
14+
* Provides models for the `asyncssh` PyPI package.
15+
* See https://pypi.org/project/asyncssh/.
16+
*/
17+
private module Asyncssh {
18+
/**
19+
* Gets `asyncssh` package.
20+
*/
21+
private API::Node asyncssh() { result = API::moduleImport("asyncssh") }
22+
23+
/**
24+
* A `run` method responsible for executing commands on remote secondary servers.
25+
*/
26+
class AsyncsshRun extends SecondaryCommandInjection::Sink {
27+
AsyncsshRun() {
28+
this =
29+
asyncssh()
30+
.getMember("connect")
31+
.getReturn()
32+
.getMember("run")
33+
.getACall()
34+
.getParameter(0, "command")
35+
.asSink()
36+
}
37+
}
38+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/**
2+
* Provides classes modeling security-relevant aspects of the `netmiko` PyPI package.
3+
* See https://pypi.org/project/netmiko/.
4+
*/
5+
6+
private import python
7+
private import semmle.python.dataflow.new.DataFlow
8+
private import semmle.python.dataflow.new.RemoteFlowSources
9+
private import semmle.python.Concepts
10+
private import semmle.python.ApiGraphs
11+
import experimental.semmle.python.security.SecondaryServerCmdInjectionCustomizations
12+
13+
/**
14+
* Provides models for the `netmiko` PyPI package.
15+
* See https://pypi.org/project/netmiko/.
16+
*/
17+
private module Netmiko {
18+
/**
19+
* Gets `netmiko` package.
20+
*/
21+
private API::Node netmiko() { result = API::moduleImport("netmiko") }
22+
23+
/**
24+
* Gets `netmiko.ConnectHandler` return value.
25+
*/
26+
private API::Node netmikoConnectHandler() {
27+
result = netmiko().getMember("ConnectHandler").getReturn()
28+
}
29+
30+
/**
31+
* The `send_*` methods responsible for executing commands on remote secondary servers.
32+
*/
33+
class NetmikoSendCommand extends SecondaryCommandInjection::Sink {
34+
NetmikoSendCommand() {
35+
this =
36+
netmikoConnectHandler()
37+
.getMember(["send_command", "send_command_expect", "send_command_timing"])
38+
.getACall()
39+
.getParameter(0, "command_string")
40+
.asSink()
41+
or
42+
this =
43+
netmikoConnectHandler()
44+
.getMember(["send_multiline", "send_multiline_timing"])
45+
.getACall()
46+
.getParameter(0, "commands")
47+
.asSink()
48+
}
49+
}
50+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/**
2+
* Provides classes modeling security-relevant aspects of the `paramiko` PyPI package.
3+
* See https://pypi.org/project/paramiko/.
4+
*/
5+
6+
private import python
7+
private import semmle.python.dataflow.new.DataFlow
8+
private import semmle.python.dataflow.new.RemoteFlowSources
9+
private import semmle.python.Concepts
10+
private import semmle.python.ApiGraphs
11+
import experimental.semmle.python.security.SecondaryServerCmdInjectionCustomizations
12+
13+
/**
14+
* Provides models for the `paramiko` PyPI package.
15+
* See https://pypi.org/project/paramiko/.
16+
*/
17+
private module Paramiko {
18+
/**
19+
* Gets `paramiko` package.
20+
*/
21+
private API::Node paramiko() { result = API::moduleImport("paramiko") }
22+
23+
/**
24+
* Gets `paramiko.SSHClient` return value.
25+
*/
26+
private API::Node paramikoClient() { result = paramiko().getMember("SSHClient").getReturn() }
27+
28+
/**
29+
* The `exec_command` of `paramiko.SSHClient` class execute command on ssh target server
30+
*/
31+
class ParamikoExecCommand extends SecondaryCommandInjection::Sink {
32+
ParamikoExecCommand() {
33+
this =
34+
paramikoClient().getMember("exec_command").getACall().getParameter(0, "command").asSink()
35+
}
36+
}
37+
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/**
2+
* Provides classes modeling security-relevant aspects of the `scrapli` PyPI package.
3+
* See https://pypi.org/project/scrapli/.
4+
*/
5+
6+
private import python
7+
private import semmle.python.dataflow.new.DataFlow
8+
private import semmle.python.dataflow.new.RemoteFlowSources
9+
private import semmle.python.Concepts
10+
private import semmle.python.ApiGraphs
11+
import experimental.semmle.python.security.SecondaryServerCmdInjectionCustomizations
12+
13+
/**
14+
* Provides models for the `scrapli` PyPI package.
15+
* See https://pypi.org/project/scrapli/.
16+
*/
17+
private module Scrapli {
18+
/**
19+
* Gets `scrapli` package.
20+
*/
21+
private API::Node scrapli() { result = API::moduleImport("scrapli") }
22+
23+
/**
24+
* Gets `scrapli.driver` package.
25+
*/
26+
private API::Node scrapliDriver() { result = scrapli().getMember("driver") }
27+
28+
/**
29+
* Gets `scrapli.driver.core` package.
30+
*/
31+
private API::Node scrapliCore() { result = scrapliDriver().getMember("core") }
32+
33+
/**
34+
* A `send_command` method responsible for executing commands on remote secondary servers.
35+
*/
36+
class ScrapliSendCommand extends SecondaryCommandInjection::Sink {
37+
ScrapliSendCommand() {
38+
this =
39+
scrapliCore()
40+
.getMember([
41+
"AsyncNXOSDriver", "AsyncJunosDriver", "AsyncEOSDriver", "AsyncIOSXEDriver",
42+
"AsyncIOSXRDriver", "NXOSDriver", "JunosDriver", "EOSDriver", "IOSXEDriver",
43+
"IOSXRDriver"
44+
])
45+
.getReturn()
46+
.getMember("send_command")
47+
.getACall()
48+
.getParameter(0, "command")
49+
.asSink()
50+
or
51+
this =
52+
scrapli()
53+
.getMember("Scrapli")
54+
.getReturn()
55+
.getMember("send_command")
56+
.getACall()
57+
.getParameter(0, "command")
58+
.asSink()
59+
or
60+
this =
61+
scrapliDriver()
62+
.getMember("GenericDriver")
63+
.getReturn()
64+
.getMember("send_command")
65+
.getACall()
66+
.getParameter(0, "command")
67+
.asSink()
68+
}
69+
}
70+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/**
2+
* Provides classes modeling security-relevant aspects of the `ssh2-python` PyPI package.
3+
* See https://pypi.org/project/ssh2-python/.
4+
*/
5+
6+
private import python
7+
private import semmle.python.dataflow.new.DataFlow
8+
private import semmle.python.dataflow.new.RemoteFlowSources
9+
private import semmle.python.Concepts
10+
private import semmle.python.ApiGraphs
11+
import experimental.semmle.python.security.SecondaryServerCmdInjectionCustomizations
12+
13+
/**
14+
* Provides models for the `ssh2-python` PyPI package.
15+
* See https://pypi.org/project/ssh2-python/.
16+
*/
17+
private module Ssh2 {
18+
/**
19+
* Gets `ssh2` package.
20+
*/
21+
private API::Node ssh2() { result = API::moduleImport("ssh2") }
22+
23+
/**
24+
* Gets `ssh2.session` package.
25+
*/
26+
private API::Node ssh2Session() { result = API::moduleImport("ssh2").getMember("session") }
27+
28+
/**
29+
* Gets `ssh2.session.Session` return value.
30+
*/
31+
private API::Node ssh2Session() { result = ssh2Session().getMember("Session").getReturn() }
32+
33+
/**
34+
* A `execute` method responsible for executing commands on remote secondary servers.
35+
*/
36+
class Ssh2Execute extends SecondaryCommandInjection::Sink {
37+
Ssh2Execute() {
38+
this =
39+
ssh2Session()
40+
.getMember("open_session")
41+
.getReturn()
42+
.getMember("execute")
43+
.getACall()
44+
.getParameter(0, "command")
45+
.asSink()
46+
}
47+
}
48+
}

python/ql/src/experimental/semmle/python/security/SecondaryServerCmdInjection.qll

Lines changed: 2 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -4,42 +4,10 @@ import semmle.python.dataflow.new.RemoteFlowSources
44
import semmle.python.ApiGraphs
55
import semmle.python.dataflow.new.internal.DataFlowPublic
66
import codeql.util.Unit
7-
8-
/**
9-
* Provides sinks and additional taint steps for the secondary command injection configuration
10-
*/
11-
module SecondaryCommandInjection {
12-
/**
13-
* The additional taint steps that need for creating taint tracking or dataflow.
14-
*/
15-
class AdditionalTaintStep extends Unit {
16-
/**
17-
* Holds if there is a additional taint step between pred and succ.
18-
*/
19-
abstract predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ);
20-
}
21-
22-
/**
23-
* A abstract class responsible for extending new decompression sinks
24-
*/
25-
abstract class Sink extends DataFlow::Node { }
26-
}
27-
28-
/**
29-
* The exec_command of `paramiko.SSHClient` class execute command on ssh target server
30-
*/
31-
class ParamikoExecCommand extends SecondaryCommandInjection::Sink {
32-
ParamikoExecCommand() {
33-
this = paramikoClient().getMember("exec_command").getACall().getParameter(0, "command").asSink()
34-
}
35-
}
36-
37-
private API::Node paramikoClient() {
38-
result = API::moduleImport("paramiko").getMember("SSHClient").getReturn()
39-
}
7+
import SecondaryServerCmdInjectionCustomizations
408

419
module SecondaryCommandInjectionConfig implements DataFlow::ConfigSig {
42-
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
10+
predicate isSource(DataFlow::Node source) { source instanceof SecondaryCommandInjection::Source }
4311

4412
predicate isSink(DataFlow::Node sink) { sink instanceof SecondaryCommandInjection::Sink }
4513
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import python
2+
import semmle.python.dataflow.new.TaintTracking
3+
import semmle.python.dataflow.new.RemoteFlowSources
4+
import semmle.python.ApiGraphs
5+
import semmle.python.dataflow.new.internal.DataFlowPublic
6+
import codeql.util.Unit
7+
8+
/**
9+
* Provides sinks and additional taint steps for the secondary command injection configuration
10+
*/
11+
module SecondaryCommandInjection {
12+
/**
13+
* The additional taint steps that need for creating taint tracking or dataflow.
14+
*/
15+
class AdditionalTaintStep extends Unit {
16+
/**
17+
* Holds if there is a additional taint step between pred and succ.
18+
*/
19+
abstract predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ);
20+
}
21+
22+
/**
23+
* A abstract class responsible for extending secondary command injection dataflow sinks.
24+
*/
25+
abstract class Sink extends DataFlow::Node { }
26+
27+
/**
28+
* A data flow source for secondary command injection data flow queries.
29+
*/
30+
abstract class Source extends DataFlow::Node { }
31+
32+
class RemoteSources extends Source {
33+
RemoteSources() { this instanceof RemoteFlowSource }
34+
}
35+
}

0 commit comments

Comments
 (0)