Python: Adjust InsecureProtocol query.

This commit is contained in:
Anders Schack-Mulligen
2023-03-01 13:36:10 +01:00
parent 5469a82efb
commit 34cc93846b
5 changed files with 146 additions and 76 deletions

View File

@@ -20,48 +20,100 @@ import TlsLibraryModel
* Since we really want "the last unrestriction, not nullified by a restriction",
* we also disallow flow into restrictions.
*/
class InsecureContextConfiguration extends DataFlow::Configuration {
TlsLibrary library;
ProtocolVersion tracked_version;
module InsecureContextConfiguration2 implements DataFlow::StateConfigSig {
private newtype TFlowState =
TMkFlowState(TlsLibrary library, int bits) {
bits in [0 .. max(any(ProtocolVersion v).getBit()) * 2 - 1]
}
InsecureContextConfiguration() {
this = library + "Allows" + tracked_version and
tracked_version.isInsecure()
class FlowState extends TFlowState {
int getBits() { this = TMkFlowState(_, result) }
TlsLibrary getLibrary() { this = TMkFlowState(result, _) }
predicate allowsInsecureVersion(ProtocolVersion v) {
v.isInsecure() and this.getBits().bitAnd(v.getBit()) != 0
}
string toString() {
result =
"FlowState(" + this.getLibrary().toString() + ", " +
concat(ProtocolVersion v | this.allowsInsecureVersion(v) | v, ", ") + ")"
}
}
ProtocolVersion getTrackedVersion() { result = tracked_version }
override predicate isSource(DataFlow::Node source) { this.isUnrestriction(source) }
override predicate isSink(DataFlow::Node sink) {
sink = library.connection_creation().getContext()
}
override predicate isBarrierIn(DataFlow::Node node) {
this.isRestriction(node)
private predicate relevantState(FlowState state) {
isSource(_, state)
or
this.isUnrestriction(node)
}
private predicate isRestriction(DataFlow::Node node) {
exists(ProtocolRestriction r |
r = library.protocol_restriction() and
r.getRestriction() = tracked_version
|
node = r.getContext()
exists(FlowState state0 | relevantState(state0) |
exists(ProtocolRestriction r |
r = state0.getLibrary().protocol_restriction() and
state.getBits() = state0.getBits().bitAnd(sum(r.getRestriction().getBit()).bitNot()) and
state0.getLibrary() = state.getLibrary()
)
or
exists(ProtocolUnrestriction pu |
pu = state0.getLibrary().protocol_unrestriction() and
state.getBits() = state0.getBits().bitOr(sum(pu.getUnrestriction().getBit())) and
state0.getLibrary() = state.getLibrary()
)
)
}
private predicate isUnrestriction(DataFlow::Node node) {
exists(ProtocolUnrestriction pu |
pu = library.protocol_unrestriction() and
pu.getUnrestriction() = tracked_version
|
node = pu.getContext()
predicate isSource(DataFlow::Node source, FlowState state) {
exists(ProtocolFamily family |
source = state.getLibrary().unspecific_context_creation(family) and
state.getBits() = family.getBits()
)
}
predicate isSink(DataFlow::Node sink, FlowState state) {
sink = state.getLibrary().connection_creation().getContext() and
state.allowsInsecureVersion(_)
}
predicate isAdditionalFlowStep(
DataFlow::Node node1, FlowState state1, DataFlow::Node node2, FlowState state2
) {
DataFlow::localFlowStep(node1, node2) and
relevantState(state1) and
(
exists(ProtocolRestriction r |
r = state1.getLibrary().protocol_restriction() and
node2 = r.getContext() and
state2.getBits() = state1.getBits().bitAnd(sum(r.getRestriction().getBit()).bitNot()) and
state1.getLibrary() = state2.getLibrary()
)
or
exists(ProtocolUnrestriction pu |
pu = state1.getLibrary().protocol_unrestriction() and
node2 = pu.getContext() and
state2.getBits() = state1.getBits().bitOr(sum(pu.getUnrestriction().getBit())) and
state1.getLibrary() = state2.getLibrary()
)
)
}
predicate isBarrier(DataFlow::Node node, FlowState state) {
relevantState(state) and
(
exists(ProtocolRestriction r |
r = state.getLibrary().protocol_restriction() and
node = r.getContext() and
state.allowsInsecureVersion(r.getRestriction())
)
or
exists(ProtocolUnrestriction pu |
pu = state.getLibrary().protocol_unrestriction() and
node = pu.getContext() and
not state.allowsInsecureVersion(pu.getUnrestriction())
)
)
}
}
private module InsecureContextFlow = DataFlow::MakeWithState<InsecureContextConfiguration2>;
/**
* Holds if `conectionCreation` marks the creation of a connection based on the contex
* found at `contextOrigin` and allowing `insecure_version`.
@@ -74,8 +126,11 @@ predicate unsafe_connection_creation_with_context(
boolean specific
) {
// Connection created from a context allowing `insecure_version`.
exists(InsecureContextConfiguration c | c.hasFlow(contextOrigin, connectionCreation) |
insecure_version = c.getTrackedVersion() and
exists(InsecureContextFlow::PathNode src, InsecureContextFlow::PathNode sink |
InsecureContextFlow::hasFlowPath(src, sink) and
src.getNode() = contextOrigin and
sink.getNode() = connectionCreation and
sink.getState().allowsInsecureVersion(insecure_version) and
specific = false
)
or

View File

@@ -52,7 +52,7 @@ class SetOptionsCall extends ProtocolRestriction, DataFlow::CallCfgNode {
}
class UnspecificPyOpenSslContextCreation extends PyOpenSslContextCreation, UnspecificContextCreation {
UnspecificPyOpenSslContextCreation() { library instanceof PyOpenSsl }
// UnspecificPyOpenSslContextCreation() { library instanceof PyOpenSsl }
}
class PyOpenSsl extends TlsLibrary {

View File

@@ -162,23 +162,21 @@ class ContextSetVersion extends ProtocolRestriction, ProtocolUnrestriction, Data
}
class UnspecificSslContextCreation extends SslContextCreation, UnspecificContextCreation {
UnspecificSslContextCreation() { library instanceof Ssl }
override ProtocolVersion getUnrestriction() {
result = UnspecificContextCreation.super.getUnrestriction() and
// These are turned off by default since Python 3.6
// see https://docs.python.org/3.6/library/ssl.html#ssl.SSLContext
not result in ["SSLv2", "SSLv3"]
}
// UnspecificSslContextCreation() { library instanceof Ssl }
// override ProtocolVersion getUnrestriction() {
// result = UnspecificContextCreation.super.getUnrestriction() and
// // These are turned off by default since Python 3.6
// // see https://docs.python.org/3.6/library/ssl.html#ssl.SSLContext
// not result in ["SSLv2", "SSLv3"]
// }
}
class UnspecificSslDefaultContextCreation extends SslDefaultContextCreation, ProtocolUnrestriction {
override DataFlow::Node getContext() { result = this }
// see https://docs.python.org/3/library/ssl.html#ssl.create_default_context
override ProtocolVersion getUnrestriction() {
result in ["TLSv1", "TLSv1_1", "TLSv1_2", "TLSv1_3"]
}
class UnspecificSslDefaultContextCreation extends SslDefaultContextCreation {
// override DataFlow::Node getContext() { result = this }
// // see https://docs.python.org/3/library/ssl.html#ssl.create_default_context
// override ProtocolVersion getUnrestriction() {
// result in ["TLSv1", "TLSv1_1", "TLSv1_2", "TLSv1_3"]
// }
}
class Ssl extends TlsLibrary {

View File

@@ -15,18 +15,45 @@ class ProtocolVersion extends string {
or
this = "TLSv1" and version = ["TLSv1_1", "TLSv1_2", "TLSv1_3"]
or
this = ["TLSv1", "TLSv1_1"] and version = ["TLSv1_2", "TLSv1_3"]
this = "TLSv1_1" and version = ["TLSv1_2", "TLSv1_3"]
or
this = ["TLSv1", "TLSv1_1", "TLSv1_2"] and version = "TLSv1_3"
this = "TLSv1_2" and version = "TLSv1_3"
}
/** Holds if this protocol version is known to be insecure. */
predicate isInsecure() { this in ["SSLv2", "SSLv3", "TLSv1", "TLSv1_1"] }
/** Gets the bit mask for this protocol version. */
int getBit() {
this = "SSLv2" and result = 1
or
this = "SSLv3" and result = 2
or
this = "TLSv1" and result = 4
or
this = "TLSv1_1" and result = 8
or
this = "TLSv1_2" and result = 16
or
this = "TLSv1_3" and result = 32
}
/** Gets the protocol family for this protocol version. */
ProtocolFamily getFamily() {
result = "SSLv23" and this in ["SSLv2", "SSLv3"]
or
result = "TLS" and this in ["TLSv1", "TLSv1_1", "TLSv1_2", "TLSv1_3"]
}
}
/** An unspecific protocol version */
class ProtocolFamily extends string {
ProtocolFamily() { this in ["SSLv23", "TLS"] }
/** Gets the bit mask for this protocol family. */
int getBits() {
result = sum(ProtocolVersion version | version.getFamily() = this | version.getBit())
}
}
/** The creation of a context. */
@@ -63,21 +90,14 @@ abstract class ProtocolUnrestriction extends DataFlow::Node {
* A context is being created with a range of allowed protocols.
* This also serves as unrestricting these protocols.
*/
abstract class UnspecificContextCreation extends ContextCreation, ProtocolUnrestriction {
TlsLibrary library;
ProtocolFamily family;
UnspecificContextCreation() { this.getProtocol() = family }
override DataFlow::CfgNode getContext() { result = this }
override ProtocolVersion getUnrestriction() {
// There is only one family, the two names are aliases in OpenSSL.
// see https://github.com/openssl/openssl/blob/13888e797c5a3193e91d71e5f5a196a2d68d266f/include/openssl/ssl.h.in#L1953-L1955
family in ["SSLv23", "TLS"] and
// see https://docs.python.org/3/library/ssl.html#ssl-contexts
result in ["SSLv2", "SSLv3", "TLSv1", "TLSv1_1", "TLSv1_2", "TLSv1_3"]
}
abstract class UnspecificContextCreation extends ContextCreation {
// override ProtocolVersion getUnrestriction() {
// // There is only one family, the two names are aliases in OpenSSL.
// // see https://github.com/openssl/openssl/blob/13888e797c5a3193e91d71e5f5a196a2d68d266f/include/openssl/ssl.h.in#L1953-L1955
// family in ["SSLv23", "TLS"] and
// // see https://docs.python.org/3/library/ssl.html#ssl-contexts
// result in ["SSLv2", "SSLv3", "TLSv1", "TLSv1_1", "TLSv1_2", "TLSv1_3"]
// }
}
/** A model of a SSL/TLS library. */

View File

@@ -12,28 +12,25 @@
| InsecureProtocol.py:24:1:24:35 | ControlFlowNode for SSLContext() | Insecure SSL/TLS protocol version SSLv2 specified by $@. | InsecureProtocol.py:24:1:24:35 | ControlFlowNode for SSLContext() | call to SSLContext |
| pyOpenSSL_fluent.py:8:27:8:33 | ControlFlowNode for context | Insecure SSL/TLS protocol version SSLv2 allowed by $@. | pyOpenSSL_fluent.py:6:15:6:44 | ControlFlowNode for Attribute() | call to SSL.Context |
| pyOpenSSL_fluent.py:8:27:8:33 | ControlFlowNode for context | Insecure SSL/TLS protocol version SSLv3 allowed by $@. | pyOpenSSL_fluent.py:6:15:6:44 | ControlFlowNode for Attribute() | call to SSL.Context |
| pyOpenSSL_fluent.py:8:27:8:33 | ControlFlowNode for context | Insecure SSL/TLS protocol version TLSv1 allowed by $@. | pyOpenSSL_fluent.py:6:15:6:44 | ControlFlowNode for Attribute() | call to SSL.Context |
| pyOpenSSL_fluent.py:8:27:8:33 | ControlFlowNode for context | Insecure SSL/TLS protocol version TLSv1_1 allowed by $@. | pyOpenSSL_fluent.py:6:15:6:44 | ControlFlowNode for Attribute() | call to SSL.Context |
| pyOpenSSL_fluent.py:18:27:18:33 | ControlFlowNode for context | Insecure SSL/TLS protocol version SSLv2 allowed by $@. | pyOpenSSL_fluent.py:15:15:15:44 | ControlFlowNode for Attribute() | call to SSL.Context |
| pyOpenSSL_fluent.py:18:27:18:33 | ControlFlowNode for context | Insecure SSL/TLS protocol version SSLv3 allowed by $@. | pyOpenSSL_fluent.py:15:15:15:44 | ControlFlowNode for Attribute() | call to SSL.Context |
| pyOpenSSL_fluent.py:18:27:18:33 | ControlFlowNode for context | Insecure SSL/TLS protocol version TLSv1_1 allowed by $@. | pyOpenSSL_fluent.py:15:15:15:44 | ControlFlowNode for Attribute() | call to SSL.Context |
| ssl_fluent.py:9:14:9:20 | ControlFlowNode for context | Insecure SSL/TLS protocol version TLSv1 allowed by $@. | ssl_fluent.py:6:15:6:46 | ControlFlowNode for Attribute() | call to ssl.SSLContext |
| ssl_fluent.py:9:14:9:20 | ControlFlowNode for context | Insecure SSL/TLS protocol version TLSv1_1 allowed by $@. | ssl_fluent.py:6:15:6:46 | ControlFlowNode for Attribute() | call to ssl.SSLContext |
| ssl_fluent.py:19:14:19:20 | ControlFlowNode for context | Insecure SSL/TLS protocol version TLSv1_1 allowed by $@. | ssl_fluent.py:15:15:15:46 | ControlFlowNode for Attribute() | call to ssl.SSLContext |
| ssl_fluent.py:28:14:28:20 | ControlFlowNode for context | Insecure SSL/TLS protocol version TLSv1_1 allowed by $@. | ssl_fluent.py:24:15:24:53 | ControlFlowNode for Attribute() | call to ssl.SSLContext |
| ssl_fluent.py:37:14:37:20 | ControlFlowNode for context | Insecure SSL/TLS protocol version TLSv1_1 allowed by $@. | ssl_fluent.py:33:15:33:53 | ControlFlowNode for Attribute() | call to ssl.SSLContext |
| ssl_fluent.py:57:14:57:20 | ControlFlowNode for context | Insecure SSL/TLS protocol version TLSv1 allowed by $@. | ssl_fluent.py:54:15:54:49 | ControlFlowNode for Attribute() | call to ssl.SSLContext |
| ssl_fluent.py:57:14:57:20 | ControlFlowNode for context | Insecure SSL/TLS protocol version TLSv1_1 allowed by $@. | ssl_fluent.py:54:15:54:49 | ControlFlowNode for Attribute() | call to ssl.SSLContext |
| ssl_fluent.py:57:14:57:20 | ControlFlowNode for context | Insecure SSL/TLS protocol version SSLv2 allowed by $@. | ssl_fluent.py:54:15:54:49 | ControlFlowNode for Attribute() | call to ssl.SSLContext |
| ssl_fluent.py:57:14:57:20 | ControlFlowNode for context | Insecure SSL/TLS protocol version SSLv3 allowed by $@. | ssl_fluent.py:54:15:54:49 | ControlFlowNode for Attribute() | call to ssl.SSLContext |
| ssl_fluent.py:71:14:71:20 | ControlFlowNode for context | Insecure SSL/TLS protocol version TLSv1 allowed by $@. | ssl_fluent.py:62:12:62:43 | ControlFlowNode for Attribute() | call to ssl.SSLContext |
| ssl_fluent.py:71:14:71:20 | ControlFlowNode for context | Insecure SSL/TLS protocol version TLSv1 allowed by $@. | ssl_fluent.py:101:15:101:46 | ControlFlowNode for Attribute() | call to ssl.SSLContext |
| ssl_fluent.py:71:14:71:20 | ControlFlowNode for context | Insecure SSL/TLS protocol version TLSv1_1 allowed by $@. | ssl_fluent.py:62:12:62:43 | ControlFlowNode for Attribute() | call to ssl.SSLContext |
| ssl_fluent.py:71:14:71:20 | ControlFlowNode for context | Insecure SSL/TLS protocol version TLSv1_1 allowed by $@. | ssl_fluent.py:65:15:65:46 | ControlFlowNode for Attribute() | call to ssl.SSLContext |
| ssl_fluent.py:71:14:71:20 | ControlFlowNode for context | Insecure SSL/TLS protocol version TLSv1_1 allowed by $@. | ssl_fluent.py:101:15:101:46 | ControlFlowNode for Attribute() | call to ssl.SSLContext |
| ssl_fluent.py:71:14:71:20 | ControlFlowNode for context | Insecure SSL/TLS protocol version TLSv1_1 allowed by $@. | ssl_fluent.py:117:5:117:11 | ControlFlowNode for context | context modification |
| ssl_fluent.py:71:14:71:20 | ControlFlowNode for context | Insecure SSL/TLS protocol version TLSv1_1 allowed by $@. | ssl_fluent.py:135:5:135:11 | ControlFlowNode for context | context modification |
| ssl_fluent.py:71:14:71:20 | ControlFlowNode for context | Insecure SSL/TLS protocol version TLSv1_1 allowed by $@. | ssl_fluent.py:115:15:115:46 | ControlFlowNode for Attribute() | call to ssl.SSLContext |
| ssl_fluent.py:77:14:77:20 | ControlFlowNode for context | Insecure SSL/TLS protocol version TLSv1 allowed by $@. | ssl_fluent.py:62:12:62:43 | ControlFlowNode for Attribute() | call to ssl.SSLContext |
| ssl_fluent.py:77:14:77:20 | ControlFlowNode for context | Insecure SSL/TLS protocol version TLSv1_1 allowed by $@. | ssl_fluent.py:62:12:62:43 | ControlFlowNode for Attribute() | call to ssl.SSLContext |
| ssl_fluent.py:97:14:97:20 | ControlFlowNode for context | Insecure SSL/TLS protocol version TLSv1_1 allowed by $@. | ssl_fluent.py:95:5:95:11 | ControlFlowNode for context | context modification |
| ssl_fluent.py:146:14:146:20 | ControlFlowNode for context | Insecure SSL/TLS protocol version TLSv1_1 allowed by $@. | ssl_fluent.py:143:5:143:11 | ControlFlowNode for context | context modification |
| ssl_fluent.py:165:14:165:20 | ControlFlowNode for context | Insecure SSL/TLS protocol version SSLv3 allowed by $@. | ssl_fluent.py:162:5:162:11 | ControlFlowNode for context | context modification |
| ssl_fluent.py:97:14:97:20 | ControlFlowNode for context | Insecure SSL/TLS protocol version TLSv1_1 allowed by $@. | ssl_fluent.py:65:15:65:46 | ControlFlowNode for Attribute() | call to ssl.SSLContext |
| ssl_fluent.py:146:14:146:20 | ControlFlowNode for context | Insecure SSL/TLS protocol version TLSv1_1 allowed by $@. | ssl_fluent.py:142:15:142:46 | ControlFlowNode for Attribute() | call to ssl.SSLContext |
| ssl_fluent.py:165:14:165:20 | ControlFlowNode for context | Insecure SSL/TLS protocol version SSLv3 allowed by $@. | ssl_fluent.py:161:15:161:65 | ControlFlowNode for Attribute() | call to ssl.create_default_context |
| ssl_fluent.py:165:14:165:20 | ControlFlowNode for context | Insecure SSL/TLS protocol version TLSv1 allowed by $@. | ssl_fluent.py:161:15:161:65 | ControlFlowNode for Attribute() | call to ssl.create_default_context |
| ssl_fluent.py:165:14:165:20 | ControlFlowNode for context | Insecure SSL/TLS protocol version TLSv1_1 allowed by $@. | ssl_fluent.py:161:15:161:65 | ControlFlowNode for Attribute() | call to ssl.create_default_context |