mirror of
https://github.com/github/codeql.git
synced 2025-12-18 01:33:15 +01:00
add Server-side Request Forgery sinks
This commit is contained in:
@@ -19,17 +19,20 @@ private import semmle.python.frameworks.FastApi
|
|||||||
private import semmle.python.frameworks.Flask
|
private import semmle.python.frameworks.Flask
|
||||||
private import semmle.python.frameworks.FlaskAdmin
|
private import semmle.python.frameworks.FlaskAdmin
|
||||||
private import semmle.python.frameworks.FlaskSqlAlchemy
|
private import semmle.python.frameworks.FlaskSqlAlchemy
|
||||||
|
private import semmle.python.frameworks.Httpx
|
||||||
private import semmle.python.frameworks.Idna
|
private import semmle.python.frameworks.Idna
|
||||||
private import semmle.python.frameworks.Invoke
|
private import semmle.python.frameworks.Invoke
|
||||||
private import semmle.python.frameworks.Jmespath
|
private import semmle.python.frameworks.Jmespath
|
||||||
private import semmle.python.frameworks.Ldap
|
private import semmle.python.frameworks.Ldap
|
||||||
private import semmle.python.frameworks.Ldap3
|
private import semmle.python.frameworks.Ldap3
|
||||||
|
private import semmle.python.frameworks.Libtaxii
|
||||||
private import semmle.python.frameworks.MarkupSafe
|
private import semmle.python.frameworks.MarkupSafe
|
||||||
private import semmle.python.frameworks.Multidict
|
private import semmle.python.frameworks.Multidict
|
||||||
private import semmle.python.frameworks.Mysql
|
private import semmle.python.frameworks.Mysql
|
||||||
private import semmle.python.frameworks.MySQLdb
|
private import semmle.python.frameworks.MySQLdb
|
||||||
private import semmle.python.frameworks.Peewee
|
private import semmle.python.frameworks.Peewee
|
||||||
private import semmle.python.frameworks.Psycopg2
|
private import semmle.python.frameworks.Psycopg2
|
||||||
|
private import semmle.python.frameworks.Pycurl
|
||||||
private import semmle.python.frameworks.Pydantic
|
private import semmle.python.frameworks.Pydantic
|
||||||
private import semmle.python.frameworks.PyMySQL
|
private import semmle.python.frameworks.PyMySQL
|
||||||
private import semmle.python.frameworks.Requests
|
private import semmle.python.frameworks.Requests
|
||||||
@@ -44,5 +47,8 @@ private import semmle.python.frameworks.Toml
|
|||||||
private import semmle.python.frameworks.Tornado
|
private import semmle.python.frameworks.Tornado
|
||||||
private import semmle.python.frameworks.Twisted
|
private import semmle.python.frameworks.Twisted
|
||||||
private import semmle.python.frameworks.Ujson
|
private import semmle.python.frameworks.Ujson
|
||||||
|
private import semmle.python.frameworks.Urllib
|
||||||
|
private import semmle.python.frameworks.Urllib2
|
||||||
|
private import semmle.python.frameworks.Urllib3
|
||||||
private import semmle.python.frameworks.Yaml
|
private import semmle.python.frameworks.Yaml
|
||||||
private import semmle.python.frameworks.Yarl
|
private import semmle.python.frameworks.Yarl
|
||||||
|
|||||||
@@ -639,3 +639,54 @@ module AiohttpWebModel {
|
|||||||
override DataFlow::Node getValueArg() { result = value }
|
override DataFlow::Node getValueArg() { result = value }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides models for the web server part (`aiohttp.client`) of the `aiohttp` PyPI package.
|
||||||
|
* See https://docs.aiohttp.org/en/stable/client.html
|
||||||
|
*/
|
||||||
|
module AiohttpClientModel {
|
||||||
|
/**
|
||||||
|
* Provides models for the `aiohttp.ClientSession` class
|
||||||
|
*
|
||||||
|
* See https://docs.aiohttp.org/en/stable/client_reference.html#aiohttp.ClientSession.
|
||||||
|
*/
|
||||||
|
module ClientSession {
|
||||||
|
/** Gets a reference to the `aiohttp.ClientSession` class. */
|
||||||
|
private API::Node classRef() {
|
||||||
|
result = API::moduleImport("aiohttp").getMember("ClientSession")
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Gets a reference to an instance of `aiohttp.ClientSession`. */
|
||||||
|
private API::Node instance() { result = classRef().getReturn() }
|
||||||
|
|
||||||
|
/** A method call on a ClientSession that sends off a request */
|
||||||
|
private class OutgoingRequestCall extends HTTP::Client::Request::Range, DataFlow::CallCfgNode {
|
||||||
|
string methodName;
|
||||||
|
|
||||||
|
OutgoingRequestCall() {
|
||||||
|
methodName in [HTTP::httpVerbLower(), "request"] and
|
||||||
|
this = instance().getMember(methodName).getACall()
|
||||||
|
}
|
||||||
|
|
||||||
|
DataFlow::Node getUrlArg() {
|
||||||
|
result = this.getArgByName("url")
|
||||||
|
or
|
||||||
|
not methodName = "request" and
|
||||||
|
result = this.getArg(0)
|
||||||
|
or
|
||||||
|
methodName = "request" and
|
||||||
|
result = this.getArg(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
override DataFlow::Node getAUrlPart() { result = this.getUrlArg() }
|
||||||
|
|
||||||
|
override string getFramework() { result = "aiohttp.ClientSession" }
|
||||||
|
|
||||||
|
override predicate disablesCertificateValidation(
|
||||||
|
DataFlow::Node disablingNode, DataFlow::Node argumentOrigin
|
||||||
|
) {
|
||||||
|
none()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
88
python/ql/lib/semmle/python/frameworks/Httpx.qll
Normal file
88
python/ql/lib/semmle/python/frameworks/Httpx.qll
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
/**
|
||||||
|
* Provides classes modeling security-relevant aspects of the `httpx` PyPI package.
|
||||||
|
* See https://www.python-httpx.org/
|
||||||
|
*/
|
||||||
|
|
||||||
|
private import python
|
||||||
|
private import semmle.python.Concepts
|
||||||
|
private import semmle.python.ApiGraphs
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides models for the `httpx` PyPI package.
|
||||||
|
* see https://www.python-httpx.org/
|
||||||
|
*/
|
||||||
|
module HttpxModel {
|
||||||
|
private class RequestCall extends HTTP::Client::Request::Range, DataFlow::CallCfgNode {
|
||||||
|
string methodName;
|
||||||
|
|
||||||
|
RequestCall() {
|
||||||
|
methodName in [HTTP::httpVerbLower(), "request", "stream"] and
|
||||||
|
this = API::moduleImport("httpx").getMember(methodName).getACall()
|
||||||
|
}
|
||||||
|
|
||||||
|
DataFlow::Node getUrlArg() {
|
||||||
|
result = this.getArgByName("url")
|
||||||
|
or
|
||||||
|
not methodName = "request" and
|
||||||
|
result = this.getArg(0)
|
||||||
|
or
|
||||||
|
methodName in ["request", "stream"] and
|
||||||
|
result = this.getArg(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
override DataFlow::Node getAUrlPart() { result = this.getUrlArg() }
|
||||||
|
|
||||||
|
override string getFramework() { result = "httpx" }
|
||||||
|
|
||||||
|
override predicate disablesCertificateValidation(
|
||||||
|
DataFlow::Node disablingNode, DataFlow::Node argumentOrigin
|
||||||
|
) {
|
||||||
|
none()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides models for the `httpx.[Async]Client` class
|
||||||
|
*
|
||||||
|
* See https://www.python-httpx.org/async/
|
||||||
|
*/
|
||||||
|
module Client {
|
||||||
|
/** Get a reference to the `httpx.Client` or `httpx.AsyncClient` class. */
|
||||||
|
private API::Node classRef() {
|
||||||
|
result = API::moduleImport("httpx").getMember(["Client", "AsyncClient"])
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Get a reference to an `httpx.Client` or `httpx.AsyncClient` instance. */
|
||||||
|
private API::Node instance() { result = classRef().getReturn() }
|
||||||
|
|
||||||
|
/** A method call on a Client that sends off a request */
|
||||||
|
private class OutgoingRequestCall extends HTTP::Client::Request::Range, DataFlow::CallCfgNode {
|
||||||
|
string methodName;
|
||||||
|
|
||||||
|
OutgoingRequestCall() {
|
||||||
|
methodName in [HTTP::httpVerbLower(), "request", "stream"] and
|
||||||
|
this = instance().getMember(methodName).getACall()
|
||||||
|
}
|
||||||
|
|
||||||
|
DataFlow::Node getUrlArg() {
|
||||||
|
result = this.getArgByName("url")
|
||||||
|
or
|
||||||
|
not methodName = "request" and
|
||||||
|
result = this.getArg(0)
|
||||||
|
or
|
||||||
|
methodName in ["request", "stream"] and
|
||||||
|
result = this.getArg(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
override DataFlow::Node getAUrlPart() { result = this.getUrlArg() }
|
||||||
|
|
||||||
|
override string getFramework() { result = "httpx.[Async]Client" }
|
||||||
|
|
||||||
|
override predicate disablesCertificateValidation(
|
||||||
|
DataFlow::Node disablingNode, DataFlow::Node argumentOrigin
|
||||||
|
) {
|
||||||
|
none()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
37
python/ql/lib/semmle/python/frameworks/Libtaxii.qll
Normal file
37
python/ql/lib/semmle/python/frameworks/Libtaxii.qll
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
/**
|
||||||
|
* Provides classes modeling security-relevant aspects of the `libtaxii` PyPI package.
|
||||||
|
* See https://github.com/TAXIIProject/libtaxii
|
||||||
|
*/
|
||||||
|
|
||||||
|
private import python
|
||||||
|
private import semmle.python.Concepts
|
||||||
|
private import semmle.python.ApiGraphs
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides models for the `libtaxii` PyPI package.
|
||||||
|
* see https://github.com/TAXIIProject/libtaxii
|
||||||
|
*/
|
||||||
|
module Libtaxii {
|
||||||
|
/**
|
||||||
|
* A call to `libtaxii.common.parse`.
|
||||||
|
* When the `allow_url` parameter value is set to `True`, there is an SSRF vulnerability..
|
||||||
|
*/
|
||||||
|
private class ParseCall extends HTTP::Client::Request::Range, DataFlow::CallCfgNode {
|
||||||
|
ParseCall() {
|
||||||
|
this = API::moduleImport("libtaxii").getMember("common").getMember("parse").getACall() and
|
||||||
|
this.getArgByName("allow_url").asExpr().toString() = "True"
|
||||||
|
}
|
||||||
|
|
||||||
|
DataFlow::Node getUrlArg() { result in [this.getArg(0), this.getArgByName("s")] }
|
||||||
|
|
||||||
|
override DataFlow::Node getAUrlPart() { result = this.getUrlArg() }
|
||||||
|
|
||||||
|
override string getFramework() { result = "libtaxii.common.parse" }
|
||||||
|
|
||||||
|
override predicate disablesCertificateValidation(
|
||||||
|
DataFlow::Node disablingNode, DataFlow::Node argumentOrigin
|
||||||
|
) {
|
||||||
|
none()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
52
python/ql/lib/semmle/python/frameworks/Pycurl.qll
Normal file
52
python/ql/lib/semmle/python/frameworks/Pycurl.qll
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
/**
|
||||||
|
* Provides classes modeling security-relevant aspects of the `pycurl` PyPI package.
|
||||||
|
* See https://pycurl.io/docs/latest/
|
||||||
|
*/
|
||||||
|
|
||||||
|
private import python
|
||||||
|
private import semmle.python.Concepts
|
||||||
|
private import semmle.python.ApiGraphs
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides models for the `pycurl` PyPI package.
|
||||||
|
* see https://pycurl.io/docs/latest/
|
||||||
|
*/
|
||||||
|
module Pycurl {
|
||||||
|
/**
|
||||||
|
* Provides models for the `pycurl.Curl` class
|
||||||
|
*
|
||||||
|
* See https://pycurl.io/docs/latest/curl.html.
|
||||||
|
*/
|
||||||
|
module Curl {
|
||||||
|
/** Gets a reference to the `pycurl.Curl` class. */
|
||||||
|
private API::Node classRef() { result = API::moduleImport("pycurl").getMember("Curl") }
|
||||||
|
|
||||||
|
/** Gets a reference to an instance of `pycurl.Curl`. */
|
||||||
|
private API::Node instance() { result = classRef().getReturn() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When the first parameter value of the `setopt` function is set to `pycurl.URL`,
|
||||||
|
* the second parameter value is the request resource link.
|
||||||
|
*
|
||||||
|
* See https://pycurl.io/docs/latest/curl.html#set_option.
|
||||||
|
*/
|
||||||
|
private class OutgoingRequestCall extends HTTP::Client::Request::Range, DataFlow::CallCfgNode {
|
||||||
|
OutgoingRequestCall() {
|
||||||
|
this = instance().getMember("setopt").getACall() and
|
||||||
|
this.getArg(0).asCfgNode().(AttrNode).getName() = "URL"
|
||||||
|
}
|
||||||
|
|
||||||
|
DataFlow::Node getUrlArg() { result in [this.getArg(1), this.getArgByName("value")] }
|
||||||
|
|
||||||
|
override DataFlow::Node getAUrlPart() { result = this.getUrlArg() }
|
||||||
|
|
||||||
|
override string getFramework() { result = "pycurl.Curl" }
|
||||||
|
|
||||||
|
override predicate disablesCertificateValidation(
|
||||||
|
DataFlow::Node disablingNode, DataFlow::Node argumentOrigin
|
||||||
|
) {
|
||||||
|
none()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
65
python/ql/lib/semmle/python/frameworks/Urllib.qll
Normal file
65
python/ql/lib/semmle/python/frameworks/Urllib.qll
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
/**
|
||||||
|
* Provides classes modeling security-relevant aspects of the `urllib` PyPI package.
|
||||||
|
* See https://docs.python.org/3.9/library/urllib.html
|
||||||
|
*/
|
||||||
|
|
||||||
|
private import python
|
||||||
|
private import semmle.python.Concepts
|
||||||
|
private import semmle.python.ApiGraphs
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides models for the `Urllib` PyPI package.
|
||||||
|
* see https://docs.python.org/3.9/library/urllib.html
|
||||||
|
*/
|
||||||
|
module Urllib {
|
||||||
|
/**
|
||||||
|
* Provides models for the `urllib.request` extension library
|
||||||
|
*
|
||||||
|
* See https://docs.python.org/3.9/library/urllib.request.html
|
||||||
|
*/
|
||||||
|
module Request {
|
||||||
|
/**
|
||||||
|
* See
|
||||||
|
* - https://docs.python.org/3.9/library/urllib.request.html#urllib.request.Request
|
||||||
|
*/
|
||||||
|
private class RequestCall extends HTTP::Client::Request::Range, DataFlow::CallCfgNode {
|
||||||
|
RequestCall() {
|
||||||
|
this = API::moduleImport("urllib").getMember("request").getMember("Request").getACall()
|
||||||
|
}
|
||||||
|
|
||||||
|
DataFlow::Node getUrlArg() { result in [this.getArg(0), this.getArgByName("url")] }
|
||||||
|
|
||||||
|
override DataFlow::Node getAUrlPart() { result = this.getUrlArg() }
|
||||||
|
|
||||||
|
override string getFramework() { result = "urllib.request.Request" }
|
||||||
|
|
||||||
|
override predicate disablesCertificateValidation(
|
||||||
|
DataFlow::Node disablingNode, DataFlow::Node argumentOrigin
|
||||||
|
) {
|
||||||
|
none()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* See
|
||||||
|
* - https://docs.python.org/3.9/library/urllib.request.html#urllib.request.urlopen
|
||||||
|
*/
|
||||||
|
private class UrlOpenCall extends HTTP::Client::Request::Range, DataFlow::CallCfgNode {
|
||||||
|
UrlOpenCall() {
|
||||||
|
this = API::moduleImport("urllib").getMember("request").getMember("urlopen").getACall()
|
||||||
|
}
|
||||||
|
|
||||||
|
DataFlow::Node getUrlArg() { result in [this.getArg(0), this.getArgByName("url")] }
|
||||||
|
|
||||||
|
override DataFlow::Node getAUrlPart() { result = this.getUrlArg() }
|
||||||
|
|
||||||
|
override string getFramework() { result = "urllib.request.urlopen" }
|
||||||
|
|
||||||
|
override predicate disablesCertificateValidation(
|
||||||
|
DataFlow::Node disablingNode, DataFlow::Node argumentOrigin
|
||||||
|
) {
|
||||||
|
none()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
56
python/ql/lib/semmle/python/frameworks/Urllib2.qll
Normal file
56
python/ql/lib/semmle/python/frameworks/Urllib2.qll
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
/**
|
||||||
|
* Provides classes modeling security-relevant aspects of the `urllib2` PyPI package.
|
||||||
|
* See https://docs.python.org/2/library/urllib2.html
|
||||||
|
*/
|
||||||
|
|
||||||
|
private import python
|
||||||
|
private import semmle.python.Concepts
|
||||||
|
private import semmle.python.ApiGraphs
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides models for the `urllib2` PyPI package.
|
||||||
|
* see https://docs.python.org/2/library/urllib2.html
|
||||||
|
*/
|
||||||
|
module Urllib2 {
|
||||||
|
/**
|
||||||
|
* See
|
||||||
|
* - https://docs.python.org/2/library/urllib2.html#urllib2.Request
|
||||||
|
*/
|
||||||
|
private class RequestCall extends HTTP::Client::Request::Range, DataFlow::CallCfgNode {
|
||||||
|
RequestCall() {
|
||||||
|
this = API::moduleImport("urllib2").getMember("Request").getACall()
|
||||||
|
}
|
||||||
|
|
||||||
|
DataFlow::Node getUrlArg() { result in [this.getArg(0), this.getArgByName("url")] }
|
||||||
|
|
||||||
|
override DataFlow::Node getAUrlPart() { result = this.getUrlArg() }
|
||||||
|
|
||||||
|
override string getFramework() { result = "urllib2.Request" }
|
||||||
|
|
||||||
|
override predicate disablesCertificateValidation(
|
||||||
|
DataFlow::Node disablingNode, DataFlow::Node argumentOrigin
|
||||||
|
) {
|
||||||
|
none()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* See
|
||||||
|
* - https://docs.python.org/2/library/urllib2.html#urllib2.urlopen
|
||||||
|
*/
|
||||||
|
private class UrlOpenCall extends HTTP::Client::Request::Range, DataFlow::CallCfgNode {
|
||||||
|
UrlOpenCall() { this = API::moduleImport("urllib2").getMember("urlopen").getACall() }
|
||||||
|
|
||||||
|
DataFlow::Node getUrlArg() { result in [this.getArg(0), this.getArgByName("url")] }
|
||||||
|
|
||||||
|
override DataFlow::Node getAUrlPart() { result = this.getUrlArg() }
|
||||||
|
|
||||||
|
override string getFramework() { result = "urllib2.urlopen" }
|
||||||
|
|
||||||
|
override predicate disablesCertificateValidation(
|
||||||
|
DataFlow::Node disablingNode, DataFlow::Node argumentOrigin
|
||||||
|
) {
|
||||||
|
none()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
62
python/ql/lib/semmle/python/frameworks/Urllib3.qll
Normal file
62
python/ql/lib/semmle/python/frameworks/Urllib3.qll
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
/**
|
||||||
|
* Provides classes modeling security-relevant aspects of the `urllib3` PyPI package.
|
||||||
|
* See https://urllib3.readthedocs.io/en/stable/reference/
|
||||||
|
*/
|
||||||
|
|
||||||
|
private import python
|
||||||
|
private import semmle.python.Concepts
|
||||||
|
private import semmle.python.ApiGraphs
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides models for the `Urllib3` PyPI package.
|
||||||
|
* see https://urllib3.readthedocs.io/en/stable/reference/
|
||||||
|
*/
|
||||||
|
module Urllib3 {
|
||||||
|
/**
|
||||||
|
* Provides models for the `urllib3.PoolManager` class
|
||||||
|
*
|
||||||
|
* See https://urllib3.readthedocs.io/en/stable/reference/urllib3.poolmanager.html.
|
||||||
|
*/
|
||||||
|
module PoolManager {
|
||||||
|
/** Gets a reference to the `urllib3.PoolManager` class. */
|
||||||
|
private API::Node classRef() { result = API::moduleImport("urllib3").getMember("PoolManager") }
|
||||||
|
|
||||||
|
/** Gets a reference to an instance of `urllib3.PoolManager`. */
|
||||||
|
private API::Node instance() { result = classRef().getReturn() }
|
||||||
|
|
||||||
|
private class RequestCall extends HTTP::Client::Request::Range, DataFlow::CallCfgNode {
|
||||||
|
RequestCall() {
|
||||||
|
this =
|
||||||
|
instance().getMember(["request", "request_encode_url", "request_encode_body"]).getACall()
|
||||||
|
}
|
||||||
|
|
||||||
|
DataFlow::Node getUrlArg() { result in [this.getArg(1), this.getArgByName("url")] }
|
||||||
|
|
||||||
|
override DataFlow::Node getAUrlPart() { result = this.getUrlArg() }
|
||||||
|
|
||||||
|
override string getFramework() { result = "urllib3.PoolManager" }
|
||||||
|
|
||||||
|
override predicate disablesCertificateValidation(
|
||||||
|
DataFlow::Node disablingNode, DataFlow::Node argumentOrigin
|
||||||
|
) {
|
||||||
|
none()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class UrlOpenCall extends HTTP::Client::Request::Range, DataFlow::CallCfgNode {
|
||||||
|
UrlOpenCall() { this = instance().getMember("urlopen").getACall() }
|
||||||
|
|
||||||
|
DataFlow::Node getUrlArg() { result in [this.getArg(1), this.getArgByName("url")] }
|
||||||
|
|
||||||
|
override DataFlow::Node getAUrlPart() { result = this.getUrlArg() }
|
||||||
|
|
||||||
|
override string getFramework() { result = "urllib3.PoolManager" }
|
||||||
|
|
||||||
|
override predicate disablesCertificateValidation(
|
||||||
|
DataFlow::Node disablingNode, DataFlow::Node argumentOrigin
|
||||||
|
) {
|
||||||
|
none()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user