Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions docs/codeql/support/reusables/frameworks.rst
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,12 @@ Python built-in support
starlette, Asynchronous Server Gateway Interface (ASGI)
python-ldap, Lightweight Directory Access Protocol (LDAP)
ldap3, Lightweight Directory Access Protocol (LDAP)
httpx, HTTP client
pycurl, HTTP client
requests, HTTP client
urllib, HTTP client
urllib2, HTTP client
urllib3, HTTP client
dill, Serialization
PyYAML, Serialization
ruamel.yaml, Serialization
Expand Down Expand Up @@ -206,5 +211,6 @@ Python built-in support
pycryptodomex, Cryptography library
rsa, Cryptography library
MarkupSafe, Escaping Library
libtaxii, TAXII utility library
libxml2, XML processing library
lxml, XML processing library
4 changes: 4 additions & 0 deletions python/ql/lib/change-notes/2022-03-04-add-ssrf-sinks.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* Added new SSRF sinks for `httpx`, `pycurl`, `urllib`, `urllib2`, `urllib3`, and `libtaxii`. This improvement was [submitted by @haby0](https://github.com/github/codeql/pull/8275).
4 changes: 4 additions & 0 deletions python/ql/lib/semmle/python/Frameworks.qll
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,13 @@ 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.Libxml2
private import semmle.python.frameworks.Lxml
private import semmle.python.frameworks.MarkupSafe
Expand All @@ -32,6 +34,7 @@ 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
Expand All @@ -46,5 +49,6 @@ 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.Urllib3
private import semmle.python.frameworks.Yaml
private import semmle.python.frameworks.Yarl
50 changes: 50 additions & 0 deletions python/ql/lib/semmle/python/frameworks/Aiohttp.qll
Original file line number Diff line number Diff line change
Expand Up @@ -639,3 +639,53 @@ 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
*/
private 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()
}

override DataFlow::Node getAUrlPart() {
result = this.getArgByName("url")
or
not methodName = "request" and
result = this.getArg(0)
or
methodName = "request" and
result = this.getArg(1)
}

override string getFramework() { result = "aiohttp.ClientSession" }

override predicate disablesCertificateValidation(
DataFlow::Node disablingNode, DataFlow::Node argumentOrigin
) {
// TODO: Look into disabling certificate validation
none()
}
}
}
}
88 changes: 88 additions & 0 deletions python/ql/lib/semmle/python/frameworks/Httpx.qll
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/**
* Provides classes modeling security-relevant aspects of the `httpx` PyPI package.
*
* See
* - https://pypi.org/project/httpx/
* - 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://pypi.org/project/httpx/
* - https://www.python-httpx.org/
*/
private 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()
}

override DataFlow::Node getAUrlPart() {
result = this.getArgByName("url")
or
if methodName in ["request", "stream"]
then result = this.getArg(1)
else result = this.getArg(0)
}

override string getFramework() { result = "httpx" }

override predicate disablesCertificateValidation(
DataFlow::Node disablingNode, DataFlow::Node argumentOrigin
) {
// TODO: Look into disabling certificate validation
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()
}

override DataFlow::Node getAUrlPart() {
result = this.getArgByName("url")
or
if methodName in ["request", "stream"]
then result = this.getArg(1)
else result = this.getArg(0)
}

override string getFramework() { result = "httpx.[Async]Client" }

override predicate disablesCertificateValidation(
DataFlow::Node disablingNode, DataFlow::Node argumentOrigin
) {
// TODO: Look into disabling certificate validation
none()
}
}
}
}
42 changes: 42 additions & 0 deletions python/ql/lib/semmle/python/frameworks/Libtaxii.qll
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/**
* Provides classes modeling security-relevant aspects of the `libtaxii` PyPI package.
*
* See
* - https://pypi.org/project/libtaxii/
* - 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://pypi.org/project/libtaxii/
* - https://github.com/TAXIIProject/libtaxii
*/
private 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").getALocalSource().asExpr() = any(True t)
}

override DataFlow::Node getAUrlPart() { result in [this.getArg(0), this.getArgByName("s")] }

override string getFramework() { result = "libtaxii.common.parse" }

override predicate disablesCertificateValidation(
DataFlow::Node disablingNode, DataFlow::Node argumentOrigin
) {
// TODO: Look into disabling certificate validation
none()
}
}
}
59 changes: 59 additions & 0 deletions python/ql/lib/semmle/python/frameworks/Pycurl.qll
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/**
* Provides classes modeling security-relevant aspects of the `pycurl` PyPI package.
*
* See
* - https://pypi.org/project/pycurl/
* - 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://pypi.org/project/pycurl/
* - https://pycurl.io/docs/latest/
*/
private 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 http://pycurl.io/docs/latest/curlobject.html#pycurl.Curl.setopt.
*/
private class OutgoingRequestCall extends HTTP::Client::Request::Range, DataFlow::CallCfgNode {
OutgoingRequestCall() {
this = instance().getMember("setopt").getACall() and
this.getArg(0).asCfgNode().(AttrNode).getName() = "URL"
}

override DataFlow::Node getAUrlPart() {
result in [this.getArg(1), this.getArgByName("value")]
}

override string getFramework() { result = "pycurl.Curl" }

override predicate disablesCertificateValidation(
DataFlow::Node disablingNode, DataFlow::Node argumentOrigin
) {
// TODO: Look into disabling certificate validation
none()
}
}
}
}
3 changes: 3 additions & 0 deletions python/ql/lib/semmle/python/frameworks/Stdlib.qll
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ private import semmle.python.frameworks.PEP249
private import semmle.python.frameworks.internal.PoorMansFunctionResolution
private import semmle.python.frameworks.internal.SelfRefMixin
private import semmle.python.frameworks.internal.InstanceTaintStepsHelper
// modeling split over multiple files to keep this file from becoming too big
private import semmle.python.frameworks.Stdlib.Urllib
private import semmle.python.frameworks.Stdlib.Urllib2

/** Provides models for the Python standard library. */
module Stdlib {
Expand Down
71 changes: 71 additions & 0 deletions python/ql/lib/semmle/python/frameworks/Stdlib/Urllib.qll
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/**
* Provides classes modeling security-relevant aspects of the `urllib` module, part of
* the Python standard library.
*
* See
* - https://docs.python.org/2/library/urllib.html
* - https://docs.python.org/3/library/urllib.html
*/

private import python
private import semmle.python.Concepts
private import semmle.python.ApiGraphs

/**
* Provides models for the `urllib` module, part of
* the Python standard library.
*
* See
* - https://docs.python.org/2/library/urllib.html
* - https://docs.python.org/3/library/urllib.html
*/
private 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()
}

override DataFlow::Node getAUrlPart() { result in [this.getArg(0), this.getArgByName("url")] }

override string getFramework() { result = "urllib.request.Request" }

override predicate disablesCertificateValidation(
DataFlow::Node disablingNode, DataFlow::Node argumentOrigin
) {
// TODO: Look into disabling certificate validation
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()
}

override DataFlow::Node getAUrlPart() { result in [this.getArg(0), this.getArgByName("url")] }

override string getFramework() { result = "urllib.request.urlopen" }

override predicate disablesCertificateValidation(
DataFlow::Node disablingNode, DataFlow::Node argumentOrigin
) {
// TODO: Look into disabling certificate validation
none()
}
}
}
}
Loading