mirror of
https://github.com/github/codeql.git
synced 2025-12-17 01:03:14 +01:00
Properly share ConceptsShared.qll
This commit is contained in:
@@ -6,11 +6,16 @@
|
||||
|
||||
private import python
|
||||
private import semmle.python.dataflow.new.DataFlow
|
||||
private import semmle.python.dataflow.new.internal.DataFlowImplSpecific
|
||||
private import semmle.python.dataflow.new.RemoteFlowSources
|
||||
private import semmle.python.dataflow.new.TaintTracking
|
||||
private import semmle.python.Files
|
||||
private import semmle.python.Frameworks
|
||||
private import semmle.python.security.internal.EncryptionKeySizes
|
||||
private import codeql.threatmodels.ThreatModels
|
||||
private import codeql.concepts.ConceptsShared
|
||||
|
||||
private module ConceptsShared = ConceptsMake<Location, PythonDataFlow>;
|
||||
|
||||
/**
|
||||
* A data flow source, for a specific threat-model.
|
||||
@@ -1617,7 +1622,7 @@ module Http {
|
||||
}
|
||||
}
|
||||
|
||||
import semmle.python.internal.ConceptsShared::Http::Client as Client
|
||||
import ConceptsShared::Http::Client as Client
|
||||
// TODO: investigate whether we should treat responses to client requests as
|
||||
// remote-flow-sources in general.
|
||||
}
|
||||
@@ -1725,5 +1730,5 @@ module Cryptography {
|
||||
}
|
||||
}
|
||||
|
||||
import semmle.python.internal.ConceptsShared::Cryptography
|
||||
import ConceptsShared::Cryptography
|
||||
}
|
||||
|
||||
@@ -758,7 +758,7 @@ module AiohttpClientModel {
|
||||
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, API::CallNode {
|
||||
private class OutgoingRequestCall extends Http::Client::Request::Range instanceof API::CallNode {
|
||||
string methodName;
|
||||
|
||||
OutgoingRequestCall() {
|
||||
@@ -767,13 +767,13 @@ module AiohttpClientModel {
|
||||
}
|
||||
|
||||
override DataFlow::Node getAUrlPart() {
|
||||
result = this.getArgByName("url")
|
||||
result = super.getArgByName("url")
|
||||
or
|
||||
methodName in [Http::httpVerbLower(), "ws_connect"] and
|
||||
result = this.getArg(0)
|
||||
result = super.getArg(0)
|
||||
or
|
||||
methodName = "request" and
|
||||
result = this.getArg(1)
|
||||
result = super.getArg(1)
|
||||
}
|
||||
|
||||
override string getFramework() { result = "aiohttp.ClientSession" }
|
||||
@@ -781,7 +781,7 @@ module AiohttpClientModel {
|
||||
override predicate disablesCertificateValidation(
|
||||
DataFlow::Node disablingNode, DataFlow::Node argumentOrigin
|
||||
) {
|
||||
exists(API::Node param | param = this.getKeywordParameter(["ssl", "verify_ssl"]) |
|
||||
exists(API::Node param | param = super.getKeywordParameter(["ssl", "verify_ssl"]) |
|
||||
disablingNode = param.asSink() and
|
||||
argumentOrigin = param.getAValueReachingSink() and
|
||||
// aiohttp.client treats `None` as the default and all other "falsey" values as `False`.
|
||||
|
||||
@@ -107,8 +107,7 @@ private module CryptodomeModel {
|
||||
/**
|
||||
* A cryptographic operation on an instance from the `Cipher` subpackage of `Cryptodome`/`Crypto`.
|
||||
*/
|
||||
class CryptodomeGenericCipherOperation extends Cryptography::CryptographicOperation::Range,
|
||||
DataFlow::CallCfgNode
|
||||
class CryptodomeGenericCipherOperation extends Cryptography::CryptographicOperation::Range instanceof DataFlow::CallCfgNode
|
||||
{
|
||||
string methodName;
|
||||
string cipherName;
|
||||
@@ -134,31 +133,31 @@ private module CryptodomeModel {
|
||||
|
||||
override DataFlow::Node getAnInput() {
|
||||
methodName = "encrypt" and
|
||||
result in [this.getArg(0), this.getArgByName(["message", "plaintext"])]
|
||||
result in [super.getArg(0), super.getArgByName(["message", "plaintext"])]
|
||||
or
|
||||
methodName = "decrypt" and
|
||||
result in [this.getArg(0), this.getArgByName("ciphertext")]
|
||||
result in [super.getArg(0), super.getArgByName("ciphertext")]
|
||||
or
|
||||
// for the following methods, method signatures can be found in
|
||||
// https://pycryptodome.readthedocs.io/en/latest/src/cipher/modern.html
|
||||
methodName = "update" and
|
||||
result in [this.getArg(0), this.getArgByName("data")]
|
||||
result in [super.getArg(0), super.getArgByName("data")]
|
||||
or
|
||||
// although `mac_tag` is used as the parameter name in the spec above, some implementations use `received_mac_tag`, for an example, see
|
||||
// https://github.com/Legrandin/pycryptodome/blob/5dace638b70ac35bb5d9b565f3e75f7869c9d851/lib/Crypto/Cipher/ChaCha20_Poly1305.py#L207
|
||||
methodName = "verify" and
|
||||
result in [this.getArg(0), this.getArgByName(["mac_tag", "received_mac_tag"])]
|
||||
result in [super.getArg(0), super.getArgByName(["mac_tag", "received_mac_tag"])]
|
||||
or
|
||||
methodName = "hexverify" and
|
||||
result in [this.getArg(0), this.getArgByName("mac_tag_hex")]
|
||||
result in [super.getArg(0), super.getArgByName("mac_tag_hex")]
|
||||
or
|
||||
methodName = "encrypt_and_digest" and
|
||||
result in [this.getArg(0), this.getArgByName("plaintext")]
|
||||
result in [super.getArg(0), super.getArgByName("plaintext")]
|
||||
or
|
||||
methodName = "decrypt_and_verify" and
|
||||
result in [
|
||||
this.getArg(0), this.getArgByName("ciphertext"), this.getArg(1),
|
||||
this.getArgByName("mac_tag")
|
||||
super.getArg(0), super.getArgByName("ciphertext"), super.getArg(1),
|
||||
super.getArgByName("mac_tag")
|
||||
]
|
||||
}
|
||||
|
||||
@@ -180,8 +179,7 @@ private module CryptodomeModel {
|
||||
/**
|
||||
* A cryptographic operation on an instance from the `Signature` subpackage of `Cryptodome`/`Crypto`.
|
||||
*/
|
||||
class CryptodomeGenericSignatureOperation extends Cryptography::CryptographicOperation::Range,
|
||||
DataFlow::CallCfgNode
|
||||
class CryptodomeGenericSignatureOperation extends Cryptography::CryptographicOperation::Range instanceof DataFlow::CallCfgNode
|
||||
{
|
||||
API::CallNode newCall;
|
||||
string methodName;
|
||||
@@ -206,13 +204,13 @@ private module CryptodomeModel {
|
||||
|
||||
override DataFlow::Node getAnInput() {
|
||||
methodName = "sign" and
|
||||
result in [this.getArg(0), this.getArgByName("msg_hash")] // Cryptodome.Hash instance
|
||||
result in [super.getArg(0), super.getArgByName("msg_hash")] // Cryptodome.Hash instance
|
||||
or
|
||||
methodName = "verify" and
|
||||
(
|
||||
result in [this.getArg(0), this.getArgByName("msg_hash")] // Cryptodome.Hash instance
|
||||
result in [super.getArg(0), super.getArgByName("msg_hash")] // Cryptodome.Hash instance
|
||||
or
|
||||
result in [this.getArg(1), this.getArgByName("signature")]
|
||||
result in [super.getArg(1), super.getArgByName("signature")]
|
||||
)
|
||||
}
|
||||
|
||||
@@ -222,8 +220,7 @@ private module CryptodomeModel {
|
||||
/**
|
||||
* A cryptographic operation on an instance from the `Hash` subpackage of `Cryptodome`/`Crypto`.
|
||||
*/
|
||||
class CryptodomeGenericHashOperation extends Cryptography::CryptographicOperation::Range,
|
||||
DataFlow::CallCfgNode
|
||||
class CryptodomeGenericHashOperation extends Cryptography::CryptographicOperation::Range instanceof DataFlow::CallCfgNode
|
||||
{
|
||||
API::CallNode newCall;
|
||||
string hashName;
|
||||
@@ -244,7 +241,7 @@ private module CryptodomeModel {
|
||||
|
||||
override Cryptography::CryptographicAlgorithm getAlgorithm() { result.matchesName(hashName) }
|
||||
|
||||
override DataFlow::Node getAnInput() { result in [this.getArg(0), this.getArgByName("data")] }
|
||||
override DataFlow::Node getAnInput() { result in [super.getArg(0), super.getArgByName("data")] }
|
||||
|
||||
override Cryptography::BlockMode getBlockMode() { none() }
|
||||
}
|
||||
|
||||
@@ -206,8 +206,7 @@ private module CryptographyModel {
|
||||
/**
|
||||
* An encrypt or decrypt operation from `cryptography.hazmat.primitives.ciphers`.
|
||||
*/
|
||||
class CryptographyGenericCipherOperation extends Cryptography::CryptographicOperation::Range,
|
||||
DataFlow::MethodCallNode
|
||||
class CryptographyGenericCipherOperation extends Cryptography::CryptographicOperation::Range instanceof DataFlow::MethodCallNode
|
||||
{
|
||||
API::CallNode init;
|
||||
string algorithmName;
|
||||
@@ -225,7 +224,9 @@ private module CryptographyModel {
|
||||
result.matchesName(algorithmName)
|
||||
}
|
||||
|
||||
override DataFlow::Node getAnInput() { result in [this.getArg(0), this.getArgByName("data")] }
|
||||
override DataFlow::Node getAnInput() {
|
||||
result in [super.getArg(0), super.getArgByName("data")]
|
||||
}
|
||||
|
||||
override Cryptography::BlockMode getBlockMode() { result = modeName }
|
||||
}
|
||||
@@ -263,8 +264,7 @@ private module CryptographyModel {
|
||||
/**
|
||||
* An hashing operation from `cryptography.hazmat.primitives.hashes`.
|
||||
*/
|
||||
class CryptographyGenericHashOperation extends Cryptography::CryptographicOperation::Range,
|
||||
DataFlow::MethodCallNode
|
||||
class CryptographyGenericHashOperation extends Cryptography::CryptographicOperation::Range instanceof DataFlow::MethodCallNode
|
||||
{
|
||||
API::CallNode init;
|
||||
string algorithmName;
|
||||
@@ -280,7 +280,9 @@ private module CryptographyModel {
|
||||
result.matchesName(algorithmName)
|
||||
}
|
||||
|
||||
override DataFlow::Node getAnInput() { result in [this.getArg(0), this.getArgByName("data")] }
|
||||
override DataFlow::Node getAnInput() {
|
||||
result in [super.getArg(0), super.getArgByName("data")]
|
||||
}
|
||||
|
||||
override Cryptography::BlockMode getBlockMode() { none() }
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ module HttpxModel {
|
||||
*
|
||||
* See https://www.python-httpx.org/api/
|
||||
*/
|
||||
private class RequestCall extends Http::Client::Request::Range, API::CallNode {
|
||||
private class RequestCall extends Http::Client::Request::Range instanceof API::CallNode {
|
||||
string methodName;
|
||||
|
||||
RequestCall() {
|
||||
@@ -35,11 +35,11 @@ module HttpxModel {
|
||||
}
|
||||
|
||||
override DataFlow::Node getAUrlPart() {
|
||||
result = this.getArgByName("url")
|
||||
result = super.getArgByName("url")
|
||||
or
|
||||
if methodName in ["request", "stream"]
|
||||
then result = this.getArg(1)
|
||||
else result = this.getArg(0)
|
||||
then result = super.getArg(1)
|
||||
else result = super.getArg(0)
|
||||
}
|
||||
|
||||
override string getFramework() { result = "httpx" }
|
||||
@@ -47,8 +47,8 @@ module HttpxModel {
|
||||
override predicate disablesCertificateValidation(
|
||||
DataFlow::Node disablingNode, DataFlow::Node argumentOrigin
|
||||
) {
|
||||
disablingNode = this.getKeywordParameter("verify").asSink() and
|
||||
argumentOrigin = this.getKeywordParameter("verify").getAValueReachingSink() and
|
||||
disablingNode = super.getKeywordParameter("verify").asSink() and
|
||||
argumentOrigin = super.getKeywordParameter("verify").getAValueReachingSink() and
|
||||
// unlike `requests`, httpx treats `None` as turning off verify (and not as the default)
|
||||
argumentOrigin.asExpr().(ImmutableLiteral).booleanValue() = false
|
||||
// TODO: Handling of insecure SSLContext passed to verify argument
|
||||
@@ -69,7 +69,8 @@ module HttpxModel {
|
||||
}
|
||||
|
||||
/** A method call on a Client that sends off a request */
|
||||
private class OutgoingRequestCall extends Http::Client::Request::Range, DataFlow::CallCfgNode {
|
||||
private class OutgoingRequestCall extends Http::Client::Request::Range instanceof DataFlow::CallCfgNode
|
||||
{
|
||||
string methodName;
|
||||
|
||||
OutgoingRequestCall() {
|
||||
@@ -78,11 +79,11 @@ module HttpxModel {
|
||||
}
|
||||
|
||||
override DataFlow::Node getAUrlPart() {
|
||||
result = this.getArgByName("url")
|
||||
result = super.getArgByName("url")
|
||||
or
|
||||
if methodName in ["request", "stream"]
|
||||
then result = this.getArg(1)
|
||||
else result = this.getArg(0)
|
||||
then result = super.getArg(1)
|
||||
else result = super.getArg(0)
|
||||
}
|
||||
|
||||
override string getFramework() { result = "httpx.[Async]Client" }
|
||||
|
||||
@@ -22,13 +22,13 @@ 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 {
|
||||
private class ParseCall extends Http::Client::Request::Range instanceof 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 DataFlow::Node getAUrlPart() { result in [super.getArg(0), super.getArgByName("s")] }
|
||||
|
||||
override string getFramework() { result = "libtaxii.common.parse" }
|
||||
|
||||
|
||||
@@ -52,14 +52,15 @@ module Pycurl {
|
||||
*
|
||||
* See http://pycurl.io/docs/latest/curlobject.html#pycurl.Curl.setopt.
|
||||
*/
|
||||
private class OutgoingRequestCall extends Http::Client::Request::Range, DataFlow::CallCfgNode {
|
||||
private class OutgoingRequestCall extends Http::Client::Request::Range instanceof DataFlow::CallCfgNode
|
||||
{
|
||||
OutgoingRequestCall() {
|
||||
this = setopt().getACall() and
|
||||
this.getArg(0).asCfgNode().(AttrNode).getName() = "URL"
|
||||
}
|
||||
|
||||
override DataFlow::Node getAUrlPart() {
|
||||
result in [this.getArg(1), this.getArgByName("value")]
|
||||
result in [super.getArg(1), super.getArgByName("value")]
|
||||
}
|
||||
|
||||
override string getFramework() { result = "pycurl.Curl" }
|
||||
@@ -77,7 +78,7 @@ module Pycurl {
|
||||
*
|
||||
* See http://pycurl.io/docs/latest/curlobject.html#pycurl.Curl.setopt.
|
||||
*/
|
||||
private class CurlSslCall extends Http::Client::Request::Range, DataFlow::CallCfgNode {
|
||||
private class CurlSslCall extends Http::Client::Request::Range instanceof DataFlow::CallCfgNode {
|
||||
CurlSslCall() {
|
||||
this = setopt().getACall() and
|
||||
this.getArg(0).asCfgNode().(AttrNode).getName() = ["SSL_VERIFYPEER", "SSL_VERIFYHOST"]
|
||||
@@ -90,13 +91,13 @@ module Pycurl {
|
||||
override predicate disablesCertificateValidation(
|
||||
DataFlow::Node disablingNode, DataFlow::Node argumentOrigin
|
||||
) {
|
||||
sslverifypeer().getAValueReachableFromSource() = this.getArg(0) and
|
||||
sslverifypeer().getAValueReachableFromSource() = super.getArg(0) and
|
||||
(
|
||||
this.getArg(1).asExpr().(IntegerLiteral).getValue() = 0
|
||||
super.getArg(1).asExpr().(IntegerLiteral).getValue() = 0
|
||||
or
|
||||
this.getArg(1).asExpr().(BooleanLiteral).booleanValue() = false
|
||||
super.getArg(1).asExpr().(BooleanLiteral).booleanValue() = false
|
||||
) and
|
||||
(disablingNode = this and argumentOrigin = this.getArg(1))
|
||||
(disablingNode = this and argumentOrigin = super.getArg(1))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ module Requests {
|
||||
*
|
||||
* See https://requests.readthedocs.io/en/latest/api/#requests.request
|
||||
*/
|
||||
private class OutgoingRequestCall extends Http::Client::Request::Range, API::CallNode {
|
||||
private class OutgoingRequestCall extends Http::Client::Request::Range instanceof API::CallNode {
|
||||
string methodName;
|
||||
|
||||
OutgoingRequestCall() {
|
||||
@@ -50,20 +50,20 @@ module Requests {
|
||||
}
|
||||
|
||||
override DataFlow::Node getAUrlPart() {
|
||||
result = this.getArgByName("url")
|
||||
result = super.getArgByName("url")
|
||||
or
|
||||
not methodName = "request" and
|
||||
result = this.getArg(0)
|
||||
result = super.getArg(0)
|
||||
or
|
||||
methodName = "request" and
|
||||
result = this.getArg(1)
|
||||
result = super.getArg(1)
|
||||
}
|
||||
|
||||
override predicate disablesCertificateValidation(
|
||||
DataFlow::Node disablingNode, DataFlow::Node argumentOrigin
|
||||
) {
|
||||
disablingNode = this.getKeywordParameter("verify").asSink() and
|
||||
argumentOrigin = this.getKeywordParameter("verify").getAValueReachingSink() and
|
||||
disablingNode = super.getKeywordParameter("verify").asSink() and
|
||||
argumentOrigin = super.getKeywordParameter("verify").getAValueReachingSink() and
|
||||
// requests treats `None` as the default and all other "falsey" values as `False`.
|
||||
argumentOrigin.asExpr().(ImmutableLiteral).booleanValue() = false and
|
||||
not argumentOrigin.asExpr() instanceof None
|
||||
|
||||
@@ -34,7 +34,8 @@ private module Rsa {
|
||||
*
|
||||
* See https://stuvel.eu/python-rsa-doc/reference.html#rsa.encrypt
|
||||
*/
|
||||
class RsaEncryptCall extends Cryptography::CryptographicOperation::Range, DataFlow::CallCfgNode {
|
||||
class RsaEncryptCall extends Cryptography::CryptographicOperation::Range instanceof DataFlow::CallCfgNode
|
||||
{
|
||||
RsaEncryptCall() { this = API::moduleImport("rsa").getMember("encrypt").getACall() }
|
||||
|
||||
override DataFlow::Node getInitialization() { result = this }
|
||||
@@ -42,7 +43,7 @@ private module Rsa {
|
||||
override Cryptography::CryptographicAlgorithm getAlgorithm() { result.getName() = "RSA" }
|
||||
|
||||
override DataFlow::Node getAnInput() {
|
||||
result in [this.getArg(0), this.getArgByName("message")]
|
||||
result in [super.getArg(0), super.getArgByName("message")]
|
||||
}
|
||||
|
||||
override Cryptography::BlockMode getBlockMode() { none() }
|
||||
@@ -53,14 +54,17 @@ private module Rsa {
|
||||
*
|
||||
* See https://stuvel.eu/python-rsa-doc/reference.html#rsa.decrypt
|
||||
*/
|
||||
class RsaDecryptCall extends Cryptography::CryptographicOperation::Range, DataFlow::CallCfgNode {
|
||||
class RsaDecryptCall extends Cryptography::CryptographicOperation::Range instanceof DataFlow::CallCfgNode
|
||||
{
|
||||
RsaDecryptCall() { this = API::moduleImport("rsa").getMember("decrypt").getACall() }
|
||||
|
||||
override DataFlow::Node getInitialization() { result = this }
|
||||
|
||||
override Cryptography::CryptographicAlgorithm getAlgorithm() { result.getName() = "RSA" }
|
||||
|
||||
override DataFlow::Node getAnInput() { result in [this.getArg(0), this.getArgByName("crypto")] }
|
||||
override DataFlow::Node getAnInput() {
|
||||
result in [super.getArg(0), super.getArgByName("crypto")]
|
||||
}
|
||||
|
||||
override Cryptography::BlockMode getBlockMode() { none() }
|
||||
}
|
||||
@@ -70,7 +74,8 @@ private module Rsa {
|
||||
*
|
||||
* See https://stuvel.eu/python-rsa-doc/reference.html#rsa.sign
|
||||
*/
|
||||
class RsaSignCall extends Cryptography::CryptographicOperation::Range, DataFlow::CallCfgNode {
|
||||
class RsaSignCall extends Cryptography::CryptographicOperation::Range instanceof DataFlow::CallCfgNode
|
||||
{
|
||||
RsaSignCall() { this = API::moduleImport("rsa").getMember("sign").getACall() }
|
||||
|
||||
override DataFlow::Node getInitialization() { result = this }
|
||||
@@ -81,14 +86,14 @@ private module Rsa {
|
||||
or
|
||||
// hashing part
|
||||
exists(StringLiteral str, DataFlow::Node hashNameArg |
|
||||
hashNameArg in [this.getArg(2), this.getArgByName("hash_method")] and
|
||||
hashNameArg in [super.getArg(2), super.getArgByName("hash_method")] and
|
||||
DataFlow::exprNode(str) = hashNameArg.getALocalSource() and
|
||||
result.matchesName(str.getText())
|
||||
)
|
||||
}
|
||||
|
||||
override DataFlow::Node getAnInput() {
|
||||
result in [this.getArg(0), this.getArgByName("message")]
|
||||
result in [super.getArg(0), super.getArgByName("message")]
|
||||
}
|
||||
|
||||
override Cryptography::BlockMode getBlockMode() { none() }
|
||||
@@ -99,7 +104,8 @@ private module Rsa {
|
||||
*
|
||||
* See https://stuvel.eu/python-rsa-doc/reference.html#rsa.verify
|
||||
*/
|
||||
class RsaVerifyCall extends Cryptography::CryptographicOperation::Range, DataFlow::CallCfgNode {
|
||||
class RsaVerifyCall extends Cryptography::CryptographicOperation::Range instanceof DataFlow::CallCfgNode
|
||||
{
|
||||
RsaVerifyCall() { this = API::moduleImport("rsa").getMember("verify").getACall() }
|
||||
|
||||
override DataFlow::Node getInitialization() { result = this }
|
||||
@@ -111,9 +117,9 @@ private module Rsa {
|
||||
}
|
||||
|
||||
override DataFlow::Node getAnInput() {
|
||||
result in [this.getArg(0), this.getArgByName("message")]
|
||||
result in [super.getArg(0), super.getArgByName("message")]
|
||||
or
|
||||
result in [this.getArg(1), this.getArgByName("signature")]
|
||||
result in [super.getArg(1), super.getArgByName("signature")]
|
||||
}
|
||||
|
||||
override Cryptography::BlockMode getBlockMode() { none() }
|
||||
@@ -124,8 +130,7 @@ private module Rsa {
|
||||
*
|
||||
* See https://stuvel.eu/python-rsa-doc/reference.html#rsa.compute_hash
|
||||
*/
|
||||
class RsaComputeHashCall extends Cryptography::CryptographicOperation::Range,
|
||||
DataFlow::CallCfgNode
|
||||
class RsaComputeHashCall extends Cryptography::CryptographicOperation::Range instanceof DataFlow::CallCfgNode
|
||||
{
|
||||
RsaComputeHashCall() { this = API::moduleImport("rsa").getMember("compute_hash").getACall() }
|
||||
|
||||
@@ -133,14 +138,14 @@ private module Rsa {
|
||||
|
||||
override Cryptography::CryptographicAlgorithm getAlgorithm() {
|
||||
exists(StringLiteral str, DataFlow::Node hashNameArg |
|
||||
hashNameArg in [this.getArg(1), this.getArgByName("method_name")] and
|
||||
hashNameArg in [super.getArg(1), super.getArgByName("method_name")] and
|
||||
DataFlow::exprNode(str) = hashNameArg.getALocalSource() and
|
||||
result.matchesName(str.getText())
|
||||
)
|
||||
}
|
||||
|
||||
override DataFlow::Node getAnInput() {
|
||||
result in [this.getArg(0), this.getArgByName("message")]
|
||||
result in [super.getArg(0), super.getArgByName("message")]
|
||||
}
|
||||
|
||||
override Cryptography::BlockMode getBlockMode() { none() }
|
||||
@@ -151,7 +156,8 @@ private module Rsa {
|
||||
*
|
||||
* See https://stuvel.eu/python-rsa-doc/reference.html#rsa.sign_hash
|
||||
*/
|
||||
class RsaSignHashCall extends Cryptography::CryptographicOperation::Range, DataFlow::CallCfgNode {
|
||||
class RsaSignHashCall extends Cryptography::CryptographicOperation::Range instanceof DataFlow::CallCfgNode
|
||||
{
|
||||
RsaSignHashCall() { this = API::moduleImport("rsa").getMember("sign_hash").getACall() }
|
||||
|
||||
override DataFlow::Node getInitialization() { result = this }
|
||||
@@ -159,7 +165,7 @@ private module Rsa {
|
||||
override Cryptography::CryptographicAlgorithm getAlgorithm() { result.getName() = "RSA" }
|
||||
|
||||
override DataFlow::Node getAnInput() {
|
||||
result in [this.getArg(0), this.getArgByName("hash_value")]
|
||||
result in [super.getArg(0), super.getArgByName("hash_value")]
|
||||
}
|
||||
|
||||
override Cryptography::BlockMode getBlockMode() { none() }
|
||||
|
||||
@@ -2385,15 +2385,16 @@ module StdlibPrivate {
|
||||
}
|
||||
|
||||
/** A method call on a HttpConnection that sends off a request */
|
||||
private class RequestCall extends Http::Client::Request::Range, DataFlow::MethodCallNode {
|
||||
private class RequestCall extends Http::Client::Request::Range instanceof DataFlow::MethodCallNode
|
||||
{
|
||||
RequestCall() { this.calls(instance(_), ["request", "_send_request", "putrequest"]) }
|
||||
|
||||
DataFlow::Node getUrlArg() { result in [this.getArg(1), this.getArgByName("url")] }
|
||||
DataFlow::Node getUrlArg() { result in [super.getArg(1), super.getArgByName("url")] }
|
||||
|
||||
override DataFlow::Node getAUrlPart() {
|
||||
result = this.getUrlArg()
|
||||
or
|
||||
this.getObject() = instance(result)
|
||||
super.getObject() = instance(result)
|
||||
}
|
||||
|
||||
override string getFramework() { result = "http.client.HTTP[S]Connection" }
|
||||
@@ -2430,7 +2431,8 @@ module StdlibPrivate {
|
||||
// a request method
|
||||
exists(RequestCall call |
|
||||
nodeFrom = call.getUrlArg() and
|
||||
nodeTo.(DataFlow::PostUpdateNode).getPreUpdateNode() = call.getObject()
|
||||
nodeTo.(DataFlow::PostUpdateNode).getPreUpdateNode() =
|
||||
call.(DataFlow::MethodCallNode).getObject()
|
||||
)
|
||||
or
|
||||
// `getresponse` call
|
||||
@@ -2797,7 +2799,7 @@ module StdlibPrivate {
|
||||
/**
|
||||
* A hashing operation by supplying initial data when calling the `hashlib.new` function.
|
||||
*/
|
||||
class HashlibNewCall extends Cryptography::CryptographicOperation::Range, API::CallNode {
|
||||
class HashlibNewCall extends Cryptography::CryptographicOperation::Range instanceof API::CallNode {
|
||||
string hashName;
|
||||
|
||||
HashlibNewCall() {
|
||||
@@ -2810,7 +2812,7 @@ module StdlibPrivate {
|
||||
|
||||
override Cryptography::CryptographicAlgorithm getAlgorithm() { result.matchesName(hashName) }
|
||||
|
||||
override DataFlow::Node getAnInput() { result = this.getParameter(1, "data").asSink() }
|
||||
override DataFlow::Node getAnInput() { result = super.getParameter(1, "data").asSink() }
|
||||
|
||||
override Cryptography::BlockMode getBlockMode() { none() }
|
||||
}
|
||||
@@ -2818,7 +2820,8 @@ module StdlibPrivate {
|
||||
/**
|
||||
* A hashing operation by using the `update` method on the result of calling the `hashlib.new` function.
|
||||
*/
|
||||
class HashlibNewUpdateCall extends Cryptography::CryptographicOperation::Range, API::CallNode {
|
||||
class HashlibNewUpdateCall extends Cryptography::CryptographicOperation::Range instanceof API::CallNode
|
||||
{
|
||||
API::CallNode init;
|
||||
string hashName;
|
||||
|
||||
@@ -2831,7 +2834,7 @@ module StdlibPrivate {
|
||||
|
||||
override Cryptography::CryptographicAlgorithm getAlgorithm() { result.matchesName(hashName) }
|
||||
|
||||
override DataFlow::Node getAnInput() { result = this.getArg(0) }
|
||||
override DataFlow::Node getAnInput() { result = super.getArg(0) }
|
||||
|
||||
override Cryptography::BlockMode getBlockMode() { none() }
|
||||
}
|
||||
@@ -2848,8 +2851,7 @@ module StdlibPrivate {
|
||||
* (such as `hashlib.md5`). `hashlib.new` is not included, since it is handled by
|
||||
* `HashlibNewCall` and `HashlibNewUpdateCall`.
|
||||
*/
|
||||
abstract class HashlibGenericHashOperation extends Cryptography::CryptographicOperation::Range,
|
||||
DataFlow::CallCfgNode
|
||||
abstract class HashlibGenericHashOperation extends Cryptography::CryptographicOperation::Range instanceof DataFlow::CallCfgNode
|
||||
{
|
||||
string hashName;
|
||||
API::Node hashClass;
|
||||
@@ -2876,7 +2878,7 @@ module StdlibPrivate {
|
||||
|
||||
override DataFlow::Node getInitialization() { result = init }
|
||||
|
||||
override DataFlow::Node getAnInput() { result = this.getArg(0) }
|
||||
override DataFlow::Node getAnInput() { result = this.(DataFlow::CallCfgNode).getArg(0) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2888,24 +2890,28 @@ module StdlibPrivate {
|
||||
// we only want to model calls to classes such as `hashlib.md5()` if initial data
|
||||
// is passed as an argument
|
||||
this = hashClass.getACall() and
|
||||
exists([this.getArg(0), this.getArgByName("string")])
|
||||
exists(
|
||||
[
|
||||
this.(DataFlow::CallCfgNode).getArg(0),
|
||||
this.(DataFlow::CallCfgNode).getArgByName("string")
|
||||
]
|
||||
)
|
||||
}
|
||||
|
||||
override DataFlow::Node getInitialization() { result = this }
|
||||
|
||||
override DataFlow::Node getAnInput() {
|
||||
result = this.getArg(0)
|
||||
result = this.(DataFlow::CallCfgNode).getArg(0)
|
||||
or
|
||||
// in Python 3.9, you are allowed to use `hashlib.md5(string=<bytes-like>)`.
|
||||
result = this.getArgByName("string")
|
||||
result = this.(DataFlow::CallCfgNode).getArgByName("string")
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// hmac
|
||||
// ---------------------------------------------------------------------------
|
||||
abstract class HmacCryptographicOperation extends Cryptography::CryptographicOperation::Range,
|
||||
API::CallNode
|
||||
abstract class HmacCryptographicOperation extends Cryptography::CryptographicOperation::Range instanceof API::CallNode
|
||||
{
|
||||
abstract API::Node getDigestArg();
|
||||
|
||||
@@ -2937,14 +2943,16 @@ module StdlibPrivate {
|
||||
HmacNewCall() {
|
||||
this = getHmacConstructorCall(digestArg) and
|
||||
// we only want to consider it as an cryptographic operation if the input is available
|
||||
exists(this.getParameter(1, "msg").asSink())
|
||||
exists(this.(API::CallNode).getParameter(1, "msg").asSink())
|
||||
}
|
||||
|
||||
override DataFlow::Node getInitialization() { result = this }
|
||||
|
||||
override API::Node getDigestArg() { result = digestArg }
|
||||
|
||||
override DataFlow::Node getAnInput() { result = this.getParameter(1, "msg").asSink() }
|
||||
override DataFlow::Node getAnInput() {
|
||||
result = this.(API::CallNode).getParameter(1, "msg").asSink()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2965,7 +2973,9 @@ module StdlibPrivate {
|
||||
|
||||
override API::Node getDigestArg() { result = digestArg }
|
||||
|
||||
override DataFlow::Node getAnInput() { result = this.getParameter(0, "msg").asSink() }
|
||||
override DataFlow::Node getAnInput() {
|
||||
result = this.(API::CallNode).getParameter(0, "msg").asSink()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2978,9 +2988,11 @@ module StdlibPrivate {
|
||||
|
||||
override DataFlow::Node getInitialization() { result = this }
|
||||
|
||||
override API::Node getDigestArg() { result = this.getParameter(2, "digest") }
|
||||
override API::Node getDigestArg() { result = this.(API::CallNode).getParameter(2, "digest") }
|
||||
|
||||
override DataFlow::Node getAnInput() { result = this.getParameter(1, "msg").asSink() }
|
||||
override DataFlow::Node getAnInput() {
|
||||
result = this.(API::CallNode).getParameter(1, "msg").asSink()
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
@@ -31,12 +31,14 @@ private module Urllib {
|
||||
* See
|
||||
* - https://docs.python.org/3.9/library/urllib.request.html#urllib.request.Request
|
||||
*/
|
||||
private class RequestCall extends Http::Client::Request::Range, DataFlow::CallCfgNode {
|
||||
private class RequestCall extends Http::Client::Request::Range instanceof 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 DataFlow::Node getAUrlPart() {
|
||||
result in [super.getArg(0), super.getArgByName("url")]
|
||||
}
|
||||
|
||||
override string getFramework() { result = "urllib.request.Request" }
|
||||
|
||||
@@ -53,12 +55,14 @@ private module Urllib {
|
||||
* See
|
||||
* - https://docs.python.org/3.9/library/urllib.request.html#urllib.request.urlopen
|
||||
*/
|
||||
private class UrlOpenCall extends Http::Client::Request::Range, DataFlow::CallCfgNode {
|
||||
private class UrlOpenCall extends Http::Client::Request::Range instanceof 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 DataFlow::Node getAUrlPart() {
|
||||
result in [super.getArg(0), super.getArgByName("url")]
|
||||
}
|
||||
|
||||
override string getFramework() { result = "urllib.request.urlopen" }
|
||||
|
||||
|
||||
@@ -20,10 +20,10 @@ private module Urllib2 {
|
||||
* See
|
||||
* - https://docs.python.org/2/library/urllib2.html#urllib2.Request
|
||||
*/
|
||||
private class RequestCall extends Http::Client::Request::Range, DataFlow::CallCfgNode {
|
||||
private class RequestCall extends Http::Client::Request::Range instanceof DataFlow::CallCfgNode {
|
||||
RequestCall() { this = API::moduleImport("urllib2").getMember("Request").getACall() }
|
||||
|
||||
override DataFlow::Node getAUrlPart() { result in [this.getArg(0), this.getArgByName("url")] }
|
||||
override DataFlow::Node getAUrlPart() { result in [super.getArg(0), super.getArgByName("url")] }
|
||||
|
||||
override string getFramework() { result = "urllib2.Request" }
|
||||
|
||||
@@ -40,10 +40,10 @@ private module Urllib2 {
|
||||
* See
|
||||
* - https://docs.python.org/2/library/urllib2.html#urllib2.urlopen
|
||||
*/
|
||||
private class UrlOpenCall extends Http::Client::Request::Range, DataFlow::CallCfgNode {
|
||||
private class UrlOpenCall extends Http::Client::Request::Range instanceof DataFlow::CallCfgNode {
|
||||
UrlOpenCall() { this = API::moduleImport("urllib2").getMember("urlopen").getACall() }
|
||||
|
||||
override DataFlow::Node getAUrlPart() { result in [this.getArg(0), this.getArgByName("url")] }
|
||||
override DataFlow::Node getAUrlPart() { result in [super.getArg(0), super.getArgByName("url")] }
|
||||
|
||||
override string getFramework() { result = "urllib2.urlopen" }
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ module Urllib3 {
|
||||
* - https://urllib3.readthedocs.io/en/stable/reference/urllib3.request.html#urllib3.request.RequestMethods
|
||||
* - https://urllib3.readthedocs.io/en/stable/reference/urllib3.connectionpool.html#urllib3.HTTPConnectionPool.urlopen
|
||||
*/
|
||||
private class RequestCall extends Http::Client::Request::Range, API::CallNode {
|
||||
private class RequestCall extends Http::Client::Request::Range instanceof API::CallNode {
|
||||
RequestCall() {
|
||||
this =
|
||||
classRef()
|
||||
@@ -63,7 +63,9 @@ module Urllib3 {
|
||||
.getACall()
|
||||
}
|
||||
|
||||
override DataFlow::Node getAUrlPart() { result in [this.getArg(1), this.getArgByName("url")] }
|
||||
override DataFlow::Node getAUrlPart() {
|
||||
result in [super.getArg(1), super.getArgByName("url")]
|
||||
}
|
||||
|
||||
override string getFramework() { result = "urllib3.PoolManager" }
|
||||
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
/**
|
||||
* This file contains imports required for the Python version of `ConceptsShared.qll`.
|
||||
* Since they are language-specific, they can't be placed directly in that file, as it is shared between languages.
|
||||
*/
|
||||
|
||||
import semmle.python.dataflow.new.DataFlow
|
||||
import codeql.concepts.CryptoAlgorithms as CryptoAlgorithms
|
||||
@@ -1,181 +0,0 @@
|
||||
/**
|
||||
* Provides Concepts which are shared across languages.
|
||||
*
|
||||
* Each language has a language specific `Concepts.qll` file that can import the
|
||||
* shared concepts from this file. A language can either re-export the concept directly,
|
||||
* or can add additional member-predicates that are needed for that language.
|
||||
*
|
||||
* Moving forward, `Concepts.qll` will be the staging ground for brand new concepts from
|
||||
* each language, but we will maintain a discipline of moving those concepts to
|
||||
* `ConceptsShared.qll` ASAP.
|
||||
*/
|
||||
|
||||
private import ConceptsImports
|
||||
|
||||
/**
|
||||
* Provides models for cryptographic concepts.
|
||||
*
|
||||
* Note: The `CryptographicAlgorithm` class currently doesn't take weak keys into
|
||||
* consideration for the `isWeak` member predicate. So RSA is always considered
|
||||
* secure, although using a low number of bits will actually make it insecure. We plan
|
||||
* to improve our libraries in the future to more precisely capture this aspect.
|
||||
*/
|
||||
module Cryptography {
|
||||
class CryptographicAlgorithm = CryptoAlgorithms::CryptographicAlgorithm;
|
||||
|
||||
class EncryptionAlgorithm = CryptoAlgorithms::EncryptionAlgorithm;
|
||||
|
||||
class HashingAlgorithm = CryptoAlgorithms::HashingAlgorithm;
|
||||
|
||||
class PasswordHashingAlgorithm = CryptoAlgorithms::PasswordHashingAlgorithm;
|
||||
|
||||
/**
|
||||
* A data flow node that is an application of a cryptographic algorithm. For example,
|
||||
* encryption, decryption, signature-validation.
|
||||
*
|
||||
* Extend this class to refine existing API models. If you want to model new APIs,
|
||||
* extend `CryptographicOperation::Range` instead.
|
||||
*/
|
||||
class CryptographicOperation extends DataFlow::Node instanceof CryptographicOperation::Range {
|
||||
/** Gets the algorithm used, if it matches a known `CryptographicAlgorithm`. */
|
||||
CryptographicAlgorithm getAlgorithm() { result = super.getAlgorithm() }
|
||||
|
||||
/** Gets the data flow node where the cryptographic algorithm used in this operation is configured. */
|
||||
DataFlow::Node getInitialization() { result = super.getInitialization() }
|
||||
|
||||
/** Gets an input the algorithm is used on, for example the plain text input to be encrypted. */
|
||||
DataFlow::Node getAnInput() { result = super.getAnInput() }
|
||||
|
||||
/**
|
||||
* Gets the block mode used to perform this cryptographic operation.
|
||||
*
|
||||
* This predicate is only expected to have a result if two conditions hold:
|
||||
* 1. The operation is an encryption operation, i.e. the algorithm used is an `EncryptionAlgorithm`, and
|
||||
* 2. The algorithm used is a block cipher (not a stream cipher).
|
||||
*
|
||||
* If either of these conditions do not hold, then this predicate should have no result.
|
||||
*/
|
||||
BlockMode getBlockMode() { result = super.getBlockMode() }
|
||||
}
|
||||
|
||||
/** Provides classes for modeling new applications of a cryptographic algorithms. */
|
||||
module CryptographicOperation {
|
||||
/**
|
||||
* A data flow node that is an application of a cryptographic algorithm. For example,
|
||||
* encryption, decryption, signature-validation.
|
||||
*
|
||||
* Extend this class to model new APIs. If you want to refine existing API models,
|
||||
* extend `CryptographicOperation` instead.
|
||||
*/
|
||||
abstract class Range extends DataFlow::Node {
|
||||
/** Gets the data flow node where the cryptographic algorithm used in this operation is configured. */
|
||||
abstract DataFlow::Node getInitialization();
|
||||
|
||||
/** Gets the algorithm used, if it matches a known `CryptographicAlgorithm`. */
|
||||
abstract CryptographicAlgorithm getAlgorithm();
|
||||
|
||||
/** Gets an input the algorithm is used on, for example the plain text input to be encrypted. */
|
||||
abstract DataFlow::Node getAnInput();
|
||||
|
||||
/**
|
||||
* Gets the block mode used to perform this cryptographic operation.
|
||||
*
|
||||
* This predicate is only expected to have a result if two conditions hold:
|
||||
* 1. The operation is an encryption operation, i.e. the algorithm used is an `EncryptionAlgorithm`, and
|
||||
* 2. The algorithm used is a block cipher (not a stream cipher).
|
||||
*
|
||||
* If either of these conditions do not hold, then this predicate should have no result.
|
||||
*/
|
||||
abstract BlockMode getBlockMode();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A cryptographic block cipher mode of operation. This can be used to encrypt
|
||||
* data of arbitrary length using a block encryption algorithm.
|
||||
*/
|
||||
class BlockMode extends string {
|
||||
BlockMode() {
|
||||
this =
|
||||
[
|
||||
"ECB", "CBC", "GCM", "CCM", "CFB", "OFB", "CTR", "OPENPGP",
|
||||
"XTS", // https://csrc.nist.gov/publications/detail/sp/800-38e/final
|
||||
"EAX" // https://en.wikipedia.org/wiki/EAX_mode
|
||||
]
|
||||
}
|
||||
|
||||
/** Holds if this block mode is considered to be insecure. */
|
||||
predicate isWeak() { this = "ECB" }
|
||||
|
||||
/** Holds if the given string appears to match this block mode. */
|
||||
bindingset[s]
|
||||
predicate matchesString(string s) { s.toUpperCase().matches("%" + this + "%") }
|
||||
}
|
||||
}
|
||||
|
||||
/** Provides classes for modeling HTTP-related APIs. */
|
||||
module Http {
|
||||
/** Provides classes for modeling HTTP clients. */
|
||||
module Client {
|
||||
/**
|
||||
* A data flow node that makes an outgoing HTTP request.
|
||||
*
|
||||
* Extend this class to refine existing API models. If you want to model new APIs,
|
||||
* extend `Http::Client::Request::Range` instead.
|
||||
*/
|
||||
class Request extends DataFlow::Node instanceof Request::Range {
|
||||
/**
|
||||
* Gets a data flow node that contributes to the URL of the request.
|
||||
* Depending on the framework, a request may have multiple nodes which contribute to the URL.
|
||||
*/
|
||||
DataFlow::Node getAUrlPart() { result = super.getAUrlPart() }
|
||||
|
||||
/** Gets a string that identifies the framework used for this request. */
|
||||
string getFramework() { result = super.getFramework() }
|
||||
|
||||
/**
|
||||
* Holds if this request is made using a mode that disables SSL/TLS
|
||||
* certificate validation, where `disablingNode` represents the point at
|
||||
* which the validation was disabled, and `argumentOrigin` represents the origin
|
||||
* of the argument that disabled the validation (which could be the same node as
|
||||
* `disablingNode`).
|
||||
*/
|
||||
predicate disablesCertificateValidation(
|
||||
DataFlow::Node disablingNode, DataFlow::Node argumentOrigin
|
||||
) {
|
||||
super.disablesCertificateValidation(disablingNode, argumentOrigin)
|
||||
}
|
||||
}
|
||||
|
||||
/** Provides a class for modeling new HTTP requests. */
|
||||
module Request {
|
||||
/**
|
||||
* A data flow node that makes an outgoing HTTP request.
|
||||
*
|
||||
* Extend this class to model new APIs. If you want to refine existing API models,
|
||||
* extend `Http::Client::Request` instead.
|
||||
*/
|
||||
abstract class Range extends DataFlow::Node {
|
||||
/**
|
||||
* Gets a data flow node that contributes to the URL of the request.
|
||||
* Depending on the framework, a request may have multiple nodes which contribute to the URL.
|
||||
*/
|
||||
abstract DataFlow::Node getAUrlPart();
|
||||
|
||||
/** Gets a string that identifies the framework used for this request. */
|
||||
abstract string getFramework();
|
||||
|
||||
/**
|
||||
* Holds if this request is made using a mode that disables SSL/TLS
|
||||
* certificate validation, where `disablingNode` represents the point at
|
||||
* which the validation was disabled, and `argumentOrigin` represents the origin
|
||||
* of the argument that disabled the validation (which could be the same node as
|
||||
* `disablingNode`).
|
||||
*/
|
||||
abstract predicate disablesCertificateValidation(
|
||||
DataFlow::Node disablingNode, DataFlow::Node argumentOrigin
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user