add twisted SSH client as secondary server command injection sinks, add proper test cases

This commit is contained in:
amammad
2024-02-25 17:52:24 +04:00
parent ab219902a9
commit 7dd1389b9e
4 changed files with 69 additions and 2 deletions

View File

@@ -12,6 +12,7 @@ private import experimental.semmle.python.frameworks.Netmiko
private import experimental.semmle.python.frameworks.Paramiko
private import experimental.semmle.python.frameworks.Pexpect
private import experimental.semmle.python.frameworks.Scrapli
private import experimental.semmle.python.frameworks.Twisted
private import experimental.semmle.python.frameworks.JWT
private import experimental.semmle.python.frameworks.Csv
private import experimental.semmle.python.libraries.PyJWT

View File

@@ -0,0 +1,36 @@
/**
* Provides classes modeling security-relevant aspects of the `twisted` PyPI package.
* See https://twistedmatrix.com/.
*/
private import python
private import semmle.python.dataflow.new.DataFlow
private import semmle.python.dataflow.new.RemoteFlowSources
private import semmle.python.dataflow.new.TaintTracking
private import semmle.python.Concepts
private import semmle.python.ApiGraphs
private import semmle.python.frameworks.internal.InstanceTaintStepsHelper
import experimental.semmle.python.Concepts
/**
* Provides models for the `twisted` PyPI package.
* See https://twistedmatrix.com/.
*/
private module Twisted {
/**
* The `newConnection` and `existingConnection` functions of `twisted.conch.endpoints.SSHCommandClientEndpoint` class execute command on ssh target server
*/
class ParamikoExecCommand extends SecondaryCommandInjection {
ParamikoExecCommand() {
this =
API::moduleImport("twisted")
.getMember("conch")
.getMember("endpoints")
.getMember("SSHCommandClientEndpoint")
.getMember(["newConnection", "existingConnection"])
.getACall()
.getParameter(1, "command")
.asSink()
}
}
}

View File

@@ -0,0 +1,30 @@
#!/usr/bin/env python
from fastapi import FastAPI
from twisted.conch.endpoints import SSHCommandClientEndpoint
from twisted.internet.protocol import Factory
from twisted.internet import reactor
app = FastAPI()
@app.get("/bad1")
async def bad1(cmd: bytes):
endpoint = SSHCommandClientEndpoint.newConnection(
reactor,
cmd, # $ result=BAD getSecondaryCommand=cmd
b"username",
b"ssh.example.com",
22,
password=b"password")
SSHCommandClientEndpoint.existingConnection(
endpoint,
cmd) # $ result=BAD getSecondaryCommand=cmd
factory = Factory()
d = endpoint.connect(factory)
d.addCallback(lambda protocol: protocol.finished)
return {"success": "Dangerous"}

View File

@@ -14,9 +14,9 @@ app = FastAPI()
@app.get("/bad1")
async def bad1(cmd: str):
stdin, stdout, stderr = paramiko_ssh_client.exec_command(cmd) # $ result=BAD getSecondaryCommand=cmd
return {"success": stdout}
return {"success": "Dangerous"}
@app.get("/bad2")
async def bad2(cmd: str):
stdin, stdout, stderr = paramiko_ssh_client.exec_command(command=cmd) # $ result=BAD getSecondaryCommand=cmd
return {"success": "OK"}
return {"success": "Dangerous"}