mirror of
https://github.com/github/codeql.git
synced 2025-12-17 17:23:36 +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.FlaskAdmin
|
||||
private import semmle.python.frameworks.FlaskSqlAlchemy
|
||||
private import semmle.python.frameworks.Httpx
|
||||
private import semmle.python.frameworks.Idna
|
||||
private import semmle.python.frameworks.Invoke
|
||||
private import semmle.python.frameworks.Jmespath
|
||||
private import semmle.python.frameworks.Ldap
|
||||
private import semmle.python.frameworks.Ldap3
|
||||
private import semmle.python.frameworks.Libtaxii
|
||||
private import semmle.python.frameworks.MarkupSafe
|
||||
private import semmle.python.frameworks.Multidict
|
||||
private import semmle.python.frameworks.Mysql
|
||||
private import semmle.python.frameworks.MySQLdb
|
||||
private import semmle.python.frameworks.Peewee
|
||||
private import semmle.python.frameworks.Psycopg2
|
||||
private import semmle.python.frameworks.Pycurl
|
||||
private import semmle.python.frameworks.Pydantic
|
||||
private import semmle.python.frameworks.PyMySQL
|
||||
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.Twisted
|
||||
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.Yarl
|
||||
|
||||
@@ -639,3 +639,54 @@ module AiohttpWebModel {
|
||||
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