mirror of
https://github.com/github/codeql.git
synced 2026-02-20 17:03:41 +01:00
add twisted SSH client as secondary server command injection sinks, add proper test cases
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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"}
|
||||
@@ -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"}
|
||||
|
||||
Reference in New Issue
Block a user