Python: Add separate query for SimpleXMLRPCServer

This was a rough quick-n-dirty query, and should get some qhelp as well at some point.
This commit is contained in:
Rasmus Wriedt Larsen
2022-03-03 19:35:33 +01:00
parent 9406a972cd
commit 7cda901da2
5 changed files with 34 additions and 33 deletions

View File

@@ -0,0 +1,27 @@
/**
* @name SimpleXMLRPCServer DoS vulnerability
* @description SimpleXMLRPCServer is vulnerable to DoS attacks from untrusted user input
* @kind path-problem
* @problem.severity warning
* @precision high
* @id py/simple-xml-rpc-server
* @tags security
* external/cwe/cwe-776
*/
private import python
private import semmle.python.dataflow.new.DataFlow
private import semmle.python.Concepts
private import experimental.semmle.python.Concepts
private import semmle.python.ApiGraphs
from DataFlow::CallCfgNode call, string kinds
where
call = API::moduleImport("xmlrpc").getMember("server").getMember("SimpleXMLRPCServer").getACall() and
kinds =
strictconcat(XML::XMLVulnerabilityKind kind |
kind.isBillionLaughs() or kind.isQuadraticBlowup()
|
kind, ", "
)
select call, "SimpleXMLRPCServer is vulnerable to: " + kinds + "."

View File

@@ -329,34 +329,4 @@ private module Xml {
(kind.isBillionLaughs() or kind.isQuadraticBlowup())
}
}
/**
* Gets a call to `xmlrpc.server.SimpleXMLRPCServer`.
*
* Given the following example:
*
* ```py
* server = SimpleXMLRPCServer(("127.0.0.1", 8000))
* server.register_function(foo, "foo")
* server.serve_forever()
* ```
*
* * `this` would be `SimpleXMLRPCServer(("127.0.0.1", 8000))`.
* * `getAnInput()`'s result would be `foo`.
* * `vulnerable(kind)`'s `kind` would be `Billion Laughs` and `Quadratic Blowup`.
*/
private class XMLRPCServer extends DataFlow::CallCfgNode, XML::XMLParser::Range {
XMLRPCServer() {
this =
API::moduleImport("xmlrpc").getMember("server").getMember("SimpleXMLRPCServer").getACall()
}
override DataFlow::Node getAnInput() {
result = this.getAMethodCall("register_function").getArg(0)
}
override predicate vulnerable(XML::XMLVulnerabilityKind kind) {
kind.isBillionLaughs() or kind.isQuadraticBlowup()
}
}
}

View File

@@ -0,0 +1 @@
| xmlrpc_server.py:7:10:7:48 | ControlFlowNode for SimpleXMLRPCServer() | SimpleXMLRPCServer is vulnerable to: Billion Laughs, Quadratic Blowup. |

View File

@@ -0,0 +1 @@
experimental/Security/CWE-611/SimpleXmlRpcServer.ql

View File

@@ -1,10 +1,12 @@
from xmlrpc.server import SimpleXMLRPCServer
def foo(n):
return n
def foo(n: str):
print("foo called with arg:", n, type(n))
return "ok"
server = SimpleXMLRPCServer(("127.0.0.1", 8000))
server.register_function(foo, "foo")
server.serve_forever()
# billion_laughs -> curl 127.0.0.1:8000 --data-raw '<?xml version="1.0"?><!DOCTYPE lolz [<!ENTITY lol "lol"><!ELEMENT lolz (#PCDATA)><!ENTITY lol1 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;"><!ENTITY lol2 "&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;"><!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;"><!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;"><!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;"><!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;"><!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;"><!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;"><!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;">]><methodCall><methodName>foo</methodName><params><param><value>&lol9;</value></param></params></methodCall>'
# normal: curl 127.0.0.1:8000 --data-raw '<?xml version="1.0"?><methodCall><methodName>foo</methodName><params><param><value>42</value></param></params></methodCall>'
# billion_laughs: curl 127.0.0.1:8000 --data-raw '<?xml version="1.0"?><!DOCTYPE lolz [<!ENTITY lol "lol"><!ELEMENT lolz (#PCDATA)><!ENTITY lol1 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;"><!ENTITY lol2 "&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;"><!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;"><!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;"><!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;"><!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;"><!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;"><!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;"><!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;">]><methodCall><methodName>foo</methodName><params><param><value>&lol9;</value></param></params></methodCall>'