add Server-side Request Forgery sinks

This commit is contained in:
haby0
2022-02-28 15:24:02 +08:00
parent 958fd9b3ea
commit b23e28a1e6
8 changed files with 417 additions and 0 deletions

View File

@@ -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

View File

@@ -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()
}
}
}
}

View 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()
}
}
}
}

View 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()
}
}
}

View 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()
}
}
}
}

View 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()
}
}
}
}

View 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()
}
}
}

View 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()
}
}
}
}