diff --git a/docs/basic_template.md b/docs/basic_template.md index 451711b..9596051 100644 --- a/docs/basic_template.md +++ b/docs/basic_template.md @@ -62,8 +62,11 @@ Name|Description|Classification

{{item.mitigations}}

References

{{item.references}}

+
Source
+

{{item.source}}

      }| + diff --git a/docs/pytm/index.html b/docs/pytm/index.html index 25d09c8..aa5b5cf 100644 --- a/docs/pytm/index.html +++ b/docs/pytm/index.html @@ -35,6 +35,7 @@

Package pytm

"Data", "Dataflow", "Datastore", + "DatastoreType", "Element", "ExternalEntity", "Finding", @@ -61,6 +62,7 @@

Package pytm

Data, Dataflow, Datastore, + DatastoreType, Element, ExternalEntity, Finding, @@ -94,6 +96,13 @@

Package pytm

+

Sub-modules

+
+
pytm.report_util
+
+
+
+
@@ -194,19 +203,7 @@

Class variables

data = varData([], doc="pytm.Data object(s) in outgoing data flows") inputs = varElements([], doc="incoming Dataflows") outputs = varElements([], doc="outgoing Dataflows") - authenticatesDestination = varBool( - False, - doc="""Verifies the identity of the destination, -for example by verifying the authenticity of a digital certificate.""", - ) - checksDestinationRevocation = varBool( - False, - doc="""Correctly checks the revocation status -of credentials used to authenticate the destination""", - ) isAdmin = varBool(False) - # should not be settable, but accessible - providesIntegrity = False def __init__(self, name, **kwargs): super().__init__(name, **kwargs) @@ -216,49 +213,8 @@

Ancestors

-

Class variables

-
-
var providesIntegrity
-
-
-
-

Instance variables

-
var authenticatesDestination
-
-

Verifies the identity of the destination, -for example by verifying the authenticity of a digital certificate.

-
- -Expand source code - -
def __get__(self, instance, owner):
-    # when x.d is called we get here
-    # instance = x
-    # owner = type(x)
-    if instance is None:
-        return self
-    return self.data.get(instance, self.default)
-
-
-
var checksDestinationRevocation
-
-

Correctly checks the revocation status -of credentials used to authenticate the destination

-
- -Expand source code - -
def __get__(self, instance, owner):
-    # when x.d is called we get here
-    # instance = x
-    # owner = type(x)
-    if instance is None:
-        return self
-    return self.data.get(instance, self.default)
-
-
var data

pytm.Data object(s) in outgoing data flows

@@ -804,7 +760,6 @@

Instance variables

responseTo = varElement(None, doc="Is a response to this data flow") srcPort = varInt(-1, doc="Source TCP port") dstPort = varInt(-1, doc="Destination TCP port") - isEncrypted = varBool(False, doc="Is the data encrypted") tlsVersion = varTLSVersion( TLSVersion.NONE, required=True, @@ -812,23 +767,10 @@

Instance variables

) protocol = varString("", doc="Protocol used in this data flow") data = varData([], doc="pytm.Data object(s) in incoming data flows") - authenticatesDestination = varBool( - False, - doc="""Verifies the identity of the destination, -for example by verifying the authenticity of a digital certificate.""", - ) - checksDestinationRevocation = varBool( - False, - doc="""Correctly checks the revocation status -of credentials used to authenticate the destination""", - ) - authenticatedWith = varBool(False) order = varInt(-1, doc="Number of this data flow in the threat model") - implementsAuthenticationScheme = varBool(False) implementsCommunicationProtocol = varBool(False) note = varString("") usesVPN = varBool(False) - authorizesSource = varBool(False) usesSessionTokens = varBool(False) def __init__(self, source, sink, name, **kwargs): @@ -890,72 +832,6 @@

Ancestors

Instance variables

-
var authenticatedWith
-
-
-
- -Expand source code - -
def __get__(self, instance, owner):
-    # when x.d is called we get here
-    # instance = x
-    # owner = type(x)
-    if instance is None:
-        return self
-    return self.data.get(instance, self.default)
-
-
-
var authenticatesDestination
-
-

Verifies the identity of the destination, -for example by verifying the authenticity of a digital certificate.

-
- -Expand source code - -
def __get__(self, instance, owner):
-    # when x.d is called we get here
-    # instance = x
-    # owner = type(x)
-    if instance is None:
-        return self
-    return self.data.get(instance, self.default)
-
-
-
var authorizesSource
-
-
-
- -Expand source code - -
def __get__(self, instance, owner):
-    # when x.d is called we get here
-    # instance = x
-    # owner = type(x)
-    if instance is None:
-        return self
-    return self.data.get(instance, self.default)
-
-
-
var checksDestinationRevocation
-
-

Correctly checks the revocation status -of credentials used to authenticate the destination

-
- -Expand source code - -
def __get__(self, instance, owner):
-    # when x.d is called we get here
-    # instance = x
-    # owner = type(x)
-    if instance is None:
-        return self
-    return self.data.get(instance, self.default)
-
-
var data

pytm.Data object(s) in incoming data flows

@@ -988,22 +864,6 @@

Instance variables

return self.data.get(instance, self.default)
-
var implementsAuthenticationScheme
-
-
-
- -Expand source code - -
def __get__(self, instance, owner):
-    # when x.d is called we get here
-    # instance = x
-    # owner = type(x)
-    if instance is None:
-        return self
-    return self.data.get(instance, self.default)
-
-
var implementsCommunicationProtocol
@@ -1020,22 +880,6 @@

Instance variables

return self.data.get(instance, self.default)
-
var isEncrypted
-
-

Is the data encrypted

-
- -Expand source code - -
def __get__(self, instance, owner):
-    # when x.d is called we get here
-    # instance = x
-    # owner = type(x)
-    if instance is None:
-        return self
-    return self.data.get(instance, self.default)
-
-
var isResponse

Is a response to another data flow

@@ -1288,24 +1132,17 @@

Methods

) storesSensitiveData = varBool(False) isSQL = varBool(True) - providesConfidentiality = varBool(False) - providesIntegrity = varBool(False) isShared = varBool(False) hasWriteAccess = varBool(False) - handlesResourceConsumption = varBool(False) - isResilient = varBool(False) - handlesInterruptions = varBool(False) - usesEncryptionAlgorithm = varString("") - implementsPOLP = varBool( - False, - doc="""The principle of least privilege (PoLP), -also known as the principle of minimal privilege or the principle of least authority, -requires that in a particular abstraction layer of a computing environment, -every module (such as a process, a user, or a program, depending on the subject) -must be able to access only the information and resources -that are necessary for its legitimate purpose.""", + type = varDatastoreType( + DatastoreType.UNKNOWN, + doc="""The type of Datastore, values may be one of: +* UNKNOWN - unknown applicable +* FILE_SYSTEM - files on a file system +* SQL - A SQL Database +* LDAP - An LDAP Server +* AWS_S3 - An S3 Bucket within AWS""" ) - isEncryptedAtRest = varBool(False, doc="Stored data is encrypted at rest") def __init__(self, name, **kwargs): super().__init__(name, **kwargs) @@ -1348,7 +1185,7 @@

Ancestors

Instance variables

-
var handlesInterruptions
+
var hasWriteAccess
@@ -1364,7 +1201,7 @@

Instance variables

return self.data.get(instance, self.default)
-
var handlesResourceConsumption
+
var isSQL
@@ -1380,7 +1217,7 @@

Instance variables

return self.data.get(instance, self.default)
-
var hasWriteAccess
+
var isShared
@@ -1396,14 +1233,9 @@

Instance variables

return self.data.get(instance, self.default)
-
var implementsPOLP
+
var onRDS
-

The principle of least privilege (PoLP), -also known as the principle of minimal privilege or the principle of least authority, -requires that in a particular abstraction layer of a computing environment, -every module (such as a process, a user, or a program, depending on the subject) -must be able to access only the information and resources -that are necessary for its legitimate purpose.

+
Expand source code @@ -1417,9 +1249,9 @@

Instance variables

return self.data.get(instance, self.default)
-
var isEncryptedAtRest
+
var storesLogData
-

Stored data is encrypted at rest

+
Expand source code @@ -1433,9 +1265,10 @@

Instance variables

return self.data.get(instance, self.default)
-
var isResilient
+
var storesPII
-
+

Personally Identifiable Information +is any information relating to an identifiable person.

Expand source code @@ -1449,7 +1282,7 @@

Instance variables

return self.data.get(instance, self.default)
-
var isSQL
+
var storesSensitiveData
@@ -1465,9 +1298,15 @@

Instance variables

return self.data.get(instance, self.default)
-
var isShared
+
var type
-
+

The +type of Datastore, values may be one of: +* UNKNOWN - unknown applicable +* FILE_SYSTEM - files on a file system +* SQL - A SQL Database +* LDAP - An LDAP Server +* AWS_S3 - An S3 Bucket within AWS

Expand source code @@ -1481,117 +1320,68 @@

Instance variables

return self.data.get(instance, self.default)
-
var onRDS
+
+
+
+class DatastoreType +(value, names=None, *, module=None, qualname=None, type=None, start=1) +
-
+

An enumeration.

Expand source code -
def __get__(self, instance, owner):
-    # when x.d is called we get here
-    # instance = x
-    # owner = type(x)
-    if instance is None:
-        return self
-    return self.data.get(instance, self.default)
+
class DatastoreType(Enum):
+    UNKNOWN = "UNKNOWN"
+    FILE_SYSTEM = "FILE_SYSTEM"
+    SQL = "SQL"
+    LDAP = "LDAP"
+    AWS_S3 = "AWS_S3"
+
+    def label(self):
+        return self.value.lower().replace("_", " ")
-
-
var providesConfidentiality
+

Ancestors

+
    +
  • enum.Enum
  • +
+

Class variables

+
+
var AWS_S3
-
- -Expand source code - -
def __get__(self, instance, owner):
-    # when x.d is called we get here
-    # instance = x
-    # owner = type(x)
-    if instance is None:
-        return self
-    return self.data.get(instance, self.default)
-
-
var providesIntegrity
+
var FILE_SYSTEM
-
- -Expand source code - -
def __get__(self, instance, owner):
-    # when x.d is called we get here
-    # instance = x
-    # owner = type(x)
-    if instance is None:
-        return self
-    return self.data.get(instance, self.default)
-
-
var storesLogData
+
var LDAP
-
- -Expand source code - -
def __get__(self, instance, owner):
-    # when x.d is called we get here
-    # instance = x
-    # owner = type(x)
-    if instance is None:
-        return self
-    return self.data.get(instance, self.default)
-
-
var storesPII
+
var SQL
-

Personally Identifiable Information -is any information relating to an identifiable person.

-
- -Expand source code - -
def __get__(self, instance, owner):
-    # when x.d is called we get here
-    # instance = x
-    # owner = type(x)
-    if instance is None:
-        return self
-    return self.data.get(instance, self.default)
-
+
-
var storesSensitiveData
+
var UNKNOWN
-
- -Expand source code - -
def __get__(self, instance, owner):
-    # when x.d is called we get here
-    # instance = x
-    # owner = type(x)
-    if instance is None:
-        return self
-    return self.data.get(instance, self.default)
-
-
var usesEncryptionAlgorithm
+
+

Methods

+
+
+def label(self) +
Expand source code -
def __get__(self, instance, owner):
-    # when x.d is called we get here
-    # instance = x
-    # owner = type(x)
-    if instance is None:
-        return self
-    return self.data.get(instance, self.default)
+
def label(self):
+    return self.value.lower().replace("_", " ")
@@ -1635,11 +1425,13 @@

Instance variables

required=False, doc="Location of the source code that describes this element relative to the directory of the model script.", ) + controls = varControls(None) def __init__(self, name, **kwargs): for key, value in kwargs.items(): setattr(self, key, value) self.name = name + self.controls = Controls() self.uuid = uuid.UUID(int=random.getrandbits(128)) self._is_drawn = False TM._elements.append(self) @@ -1784,6 +1576,22 @@

Subclasses

Instance variables

+
var controls
+
+
+
+ +Expand source code + +
def __get__(self, instance, owner):
+    # when x.d is called we get here
+    # instance = x
+    # owner = type(x)
+    if instance is None:
+        return self
+    return self.data.get(instance, self.default)
+
+
var description
@@ -2134,17 +1942,17 @@

Instance variables

"""Represents a Finding - the element in question and a description of the finding""" - element = varElement(None, required=True, doc="Element this finding applies to") + element = varElement(None, required=False, doc="Element this finding applies to") target = varString("", doc="Name of the element this finding applies to") description = varString("", required=True, doc="Threat description") details = varString("", required=True, doc="Threat details") - severity = varString("", required=True, doc="Threat severity") - mitigations = varString("", required=True, doc="Threat mitigations") - example = varString("", required=True, doc="Threat example") + severity = varString("", required=False, doc="Threat severity") + mitigations = varString("", required=False, doc="Threat mitigations") + example = varString("", required=False, doc="Threat example") id = varString("", required=True, doc="Finding ID") - threat_id = varString("", required=True, doc="Threat ID") - references = varString("", required=True, doc="Threat references") - condition = varString("", required=True, doc="Threat condition") + threat_id = varString("", required=False, doc="Threat ID") + references = varString("", required=False, doc="Threat references") + condition = varString("", required=False, doc="Threat condition") response = varString( "", required=False, @@ -2157,6 +1965,7 @@

Instance variables

""", ) cvss = varString("", required=False, doc="The CVSS score and/or vector") + source = varString("manual", required=False, doc="The source of the Finding.") def __init__( self, @@ -2166,10 +1975,12 @@

Instance variables

if args: element = args[0] else: - element = kwargs.pop("element", Element("invalid")) + element = kwargs.pop("element", None) + + if (element): + self.target = element.name + self.element = element - self.target = element.name - self.element = element attrs = [ "description", "details", @@ -2187,25 +1998,30 @@

Instance variables

kwargs[a] = getattr(threat, a) threat_id = kwargs.get("threat_id", None) - for f in element.overrides: - if f.threat_id != threat_id: - continue - for i in dir(f.__class__): - attr = getattr(f.__class__, i) - if ( - i in ("element", "target") - or i.startswith("_") - or callable(attr) - or not isinstance(attr, var) - ): + + if (element): + for f in element.overrides: + if f.threat_id != threat_id: continue - if f in attr.data: - kwargs[i] = attr.data[f] - break - + for i in dir(f.__class__): + attr = getattr(f.__class__, i) + if ( + i in ("element", "target") + or i.startswith("_") + or callable(attr) + or not isinstance(attr, var) + ): + continue + if f in attr.data: + kwargs[i] = attr.data[f] + break + for k, v in kwargs.items(): setattr(self, k, v) + TM._findings.append(self) + + def _safeset(self, attr, value): try: setattr(self, attr, value) @@ -2403,6 +2219,22 @@

Instance variables

return self.data.get(instance, self.default)
+
var source
+
+

The source of the Finding.

+
+ +Expand source code + +
def __get__(self, instance, owner):
+    # when x.d is called we get here
+    # instance = x
+    # owner = type(x)
+    if instance is None:
+        return self
+    return self.data.get(instance, self.default)
+
+
var target

Name of the element this finding applies to

@@ -2474,635 +2306,19 @@

Instance variables

def dfd(self, **kwargs): self._is_drawn = True - levels = kwargs.get("levels", None) - if levels and not levels & self.levels: - return "" - - return self._dfd_template().format( - uniq_name=self._uniq_name(), - label=self._label(), - color=self._color(), - shape=self._shape(), - ) - - def _shape(self): - return "rectangle; style=rounded" - -

Ancestors

-
    -
  • pytm.pytm.Asset
  • -
  • pytm.pytm.Element
  • -
-

Instance variables

-
-
var environment
-
-
-
- -Expand source code - -
def __get__(self, instance, owner):
-    # when x.d is called we get here
-    # instance = x
-    # owner = type(x)
-    if instance is None:
-        return self
-    return self.data.get(instance, self.default)
-
-
-
var implementsAPI
-
-
-
- -Expand source code - -
def __get__(self, instance, owner):
-    # when x.d is called we get here
-    # instance = x
-    # owner = type(x)
-    if instance is None:
-        return self
-    return self.data.get(instance, self.default)
-
-
-
var onAWS
-
-
-
- -Expand source code - -
def __get__(self, instance, owner):
-    # when x.d is called we get here
-    # instance = x
-    # owner = type(x)
-    if instance is None:
-        return self
-    return self.data.get(instance, self.default)
-
-
-
-
-
-class Lifetime -(value, names=None, *, module=None, qualname=None, type=None, start=1) -
-
-

An enumeration.

-
- -Expand source code - -
class Lifetime(Enum):
-    # not applicable
-    NONE = "NONE"
-    # unknown lifetime
-    UNKNOWN = "UNKNOWN"
-    # relatively short expiration date (time to live)
-    SHORT = "SHORT_LIVED"
-    # long or no expiration date
-    LONG = "LONG_LIVED"
-    # no expiration date but revoked/invalidated automatically in some conditions
-    AUTO = "AUTO_REVOKABLE"
-    # no expiration date but can be invalidated manually
-    MANUAL = "MANUALLY_REVOKABLE"
-    # cannot be invalidated at all
-    HARDCODED = "HARDCODED"
-
-    def label(self):
-        return self.value.lower().replace("_", " ")
-
-

Ancestors

-
    -
  • enum.Enum
  • -
-

Class variables

-
-
var AUTO
-
-
-
-
var HARDCODED
-
-
-
-
var LONG
-
-
-
-
var MANUAL
-
-
-
-
var NONE
-
-
-
-
var SHORT
-
-
-
-
var UNKNOWN
-
-
-
-
-

Methods

-
-
-def label(self) -
-
-
-
- -Expand source code - -
def label(self):
-    return self.value.lower().replace("_", " ")
-
-
-
-
-
-class Process -(name, **kwargs) -
-
-

An entity processing data

-
- -Expand source code - -
class Process(Asset):
-    """An entity processing data"""
-
-    codeType = varString("Unmanaged")
-    implementsCommunicationProtocol = varBool(False)
-    providesConfidentiality = varBool(False)
-    providesIntegrity = varBool(False)
-    isResilient = varBool(False)
-    tracksExecutionFlow = varBool(False)
-    implementsCSRFToken = varBool(False)
-    handlesResourceConsumption = varBool(False)
-    handlesCrashes = varBool(False)
-    handlesInterruptions = varBool(False)
-    implementsAPI = varBool(False)
-    usesSecureFunctions = varBool(False)
-    environment = varString("")
-    disablesiFrames = varBool(False)
-    implementsPOLP = varBool(
-        False,
-        doc="""The principle of least privilege (PoLP),
-also known as the principle of minimal privilege or the principle of least authority,
-requires that in a particular abstraction layer of a computing environment,
-every module (such as a process, a user, or a program, depending on the subject)
-must be able to access only the information and resources
-that are necessary for its legitimate purpose.""",
-    )
-    usesParameterizedInput = varBool(False)
-    allowsClientSideScripting = varBool(False)
-    usesStrongSessionIdentifiers = varBool(False)
-    encryptsCookies = varBool(False)
-    usesMFA = varBool(
-        False,
-        doc="""Multi-factor authentication is an authentication method
-in which a computer user is granted access only after successfully presenting two
-or more pieces of evidence (or factors) to an authentication mechanism: knowledge
-(something the user and only the user knows), possession (something the user
-and only the user has), and inherence (something the user and only the user is).""",
-    )
-    encryptsSessionData = varBool(False)
-    verifySessionIdentifiers = varBool(False)
-
-    def __init__(self, name, **kwargs):
-        super().__init__(name, **kwargs)
-
-    def _shape(self):
-        return "circle"
-
-

Ancestors

-
    -
  • pytm.pytm.Asset
  • -
  • pytm.pytm.Element
  • -
-

Subclasses

-
    -
  • pytm.pytm.SetOfProcesses
  • -
-

Instance variables

-
-
var allowsClientSideScripting
-
-
-
- -Expand source code - -
def __get__(self, instance, owner):
-    # when x.d is called we get here
-    # instance = x
-    # owner = type(x)
-    if instance is None:
-        return self
-    return self.data.get(instance, self.default)
-
-
-
var codeType
-
-
-
- -Expand source code - -
def __get__(self, instance, owner):
-    # when x.d is called we get here
-    # instance = x
-    # owner = type(x)
-    if instance is None:
-        return self
-    return self.data.get(instance, self.default)
-
-
-
var disablesiFrames
-
-
-
- -Expand source code - -
def __get__(self, instance, owner):
-    # when x.d is called we get here
-    # instance = x
-    # owner = type(x)
-    if instance is None:
-        return self
-    return self.data.get(instance, self.default)
-
-
-
var encryptsCookies
-
-
-
- -Expand source code - -
def __get__(self, instance, owner):
-    # when x.d is called we get here
-    # instance = x
-    # owner = type(x)
-    if instance is None:
-        return self
-    return self.data.get(instance, self.default)
-
-
-
var encryptsSessionData
-
-
-
- -Expand source code - -
def __get__(self, instance, owner):
-    # when x.d is called we get here
-    # instance = x
-    # owner = type(x)
-    if instance is None:
-        return self
-    return self.data.get(instance, self.default)
-
-
-
var environment
-
-
-
- -Expand source code - -
def __get__(self, instance, owner):
-    # when x.d is called we get here
-    # instance = x
-    # owner = type(x)
-    if instance is None:
-        return self
-    return self.data.get(instance, self.default)
-
-
-
var handlesCrashes
-
-
-
- -Expand source code - -
def __get__(self, instance, owner):
-    # when x.d is called we get here
-    # instance = x
-    # owner = type(x)
-    if instance is None:
-        return self
-    return self.data.get(instance, self.default)
-
-
-
var handlesInterruptions
-
-
-
- -Expand source code - -
def __get__(self, instance, owner):
-    # when x.d is called we get here
-    # instance = x
-    # owner = type(x)
-    if instance is None:
-        return self
-    return self.data.get(instance, self.default)
-
-
-
var handlesResourceConsumption
-
-
-
- -Expand source code - -
def __get__(self, instance, owner):
-    # when x.d is called we get here
-    # instance = x
-    # owner = type(x)
-    if instance is None:
-        return self
-    return self.data.get(instance, self.default)
-
-
-
var implementsAPI
-
-
-
- -Expand source code - -
def __get__(self, instance, owner):
-    # when x.d is called we get here
-    # instance = x
-    # owner = type(x)
-    if instance is None:
-        return self
-    return self.data.get(instance, self.default)
-
-
-
var implementsCSRFToken
-
-
-
- -Expand source code - -
def __get__(self, instance, owner):
-    # when x.d is called we get here
-    # instance = x
-    # owner = type(x)
-    if instance is None:
-        return self
-    return self.data.get(instance, self.default)
-
-
-
var implementsCommunicationProtocol
-
-
-
- -Expand source code - -
def __get__(self, instance, owner):
-    # when x.d is called we get here
-    # instance = x
-    # owner = type(x)
-    if instance is None:
-        return self
-    return self.data.get(instance, self.default)
-
-
-
var implementsPOLP
-
-

The principle of least privilege (PoLP), -also known as the principle of minimal privilege or the principle of least authority, -requires that in a particular abstraction layer of a computing environment, -every module (such as a process, a user, or a program, depending on the subject) -must be able to access only the information and resources -that are necessary for its legitimate purpose.

-
- -Expand source code - -
def __get__(self, instance, owner):
-    # when x.d is called we get here
-    # instance = x
-    # owner = type(x)
-    if instance is None:
-        return self
-    return self.data.get(instance, self.default)
-
-
-
var isResilient
-
-
-
- -Expand source code - -
def __get__(self, instance, owner):
-    # when x.d is called we get here
-    # instance = x
-    # owner = type(x)
-    if instance is None:
-        return self
-    return self.data.get(instance, self.default)
-
-
-
var providesConfidentiality
-
-
-
- -Expand source code - -
def __get__(self, instance, owner):
-    # when x.d is called we get here
-    # instance = x
-    # owner = type(x)
-    if instance is None:
-        return self
-    return self.data.get(instance, self.default)
-
-
-
var providesIntegrity
-
-
-
- -Expand source code - -
def __get__(self, instance, owner):
-    # when x.d is called we get here
-    # instance = x
-    # owner = type(x)
-    if instance is None:
-        return self
-    return self.data.get(instance, self.default)
-
-
-
var tracksExecutionFlow
-
-
-
- -Expand source code - -
def __get__(self, instance, owner):
-    # when x.d is called we get here
-    # instance = x
-    # owner = type(x)
-    if instance is None:
-        return self
-    return self.data.get(instance, self.default)
-
-
-
var usesMFA
-
-

Multi-factor authentication is an authentication method -in which a computer user is granted access only after successfully presenting two -or more pieces of evidence (or factors) to an authentication mechanism: knowledge -(something the user and only the user knows), possession (something the user -and only the user has), and inherence (something the user and only the user is).

-
- -Expand source code - -
def __get__(self, instance, owner):
-    # when x.d is called we get here
-    # instance = x
-    # owner = type(x)
-    if instance is None:
-        return self
-    return self.data.get(instance, self.default)
-
-
-
var usesParameterizedInput
-
-
-
- -Expand source code - -
def __get__(self, instance, owner):
-    # when x.d is called we get here
-    # instance = x
-    # owner = type(x)
-    if instance is None:
-        return self
-    return self.data.get(instance, self.default)
-
-
-
var usesSecureFunctions
-
-
-
- -Expand source code - -
def __get__(self, instance, owner):
-    # when x.d is called we get here
-    # instance = x
-    # owner = type(x)
-    if instance is None:
-        return self
-    return self.data.get(instance, self.default)
-
-
-
var usesStrongSessionIdentifiers
-
-
-
- -Expand source code - -
def __get__(self, instance, owner):
-    # when x.d is called we get here
-    # instance = x
-    # owner = type(x)
-    if instance is None:
-        return self
-    return self.data.get(instance, self.default)
-
-
-
var verifySessionIdentifiers
-
-
-
- -Expand source code - -
def __get__(self, instance, owner):
-    # when x.d is called we get here
-    # instance = x
-    # owner = type(x)
-    if instance is None:
-        return self
-    return self.data.get(instance, self.default)
-
-
-
-
-
-class Server -(name, **kwargs) -
-
-

An entity processing data

-
- -Expand source code - -
class Server(Asset):
-    """An entity processing data"""
-
-    providesConfidentiality = varBool(False)
-    providesIntegrity = varBool(False)
-    validatesHeaders = varBool(False)
-    encodesHeaders = varBool(False)
-    implementsCSRFToken = varBool(False)
-    isResilient = varBool(False)
-    usesSessionTokens = varBool(False)
-    usesEncryptionAlgorithm = varString("")
-    usesCache = varBool(False)
-    usesVPN = varBool(False)
-    usesCodeSigning = varBool(False)
-    validatesContentType = varBool(False)
-    invokesScriptFilters = varBool(False)
-    usesStrongSessionIdentifiers = varBool(False)
-    implementsServerSideValidation = varBool(False)
-    usesXMLParser = varBool(False)
-    disablesDTD = varBool(False)
-    implementsStrictHTTPValidation = varBool(False)
-    implementsPOLP = varBool(
-        False,
-        doc="""The principle of least privilege (PoLP),
-also known as the principle of minimal privilege or the principle of least authority,
-requires that in a particular abstraction layer of a computing environment,
-every module (such as a process, a user, or a program, depending on the subject)
-must be able to access only the information and resources
-that are necessary for its legitimate purpose.""",
-    )
+        levels = kwargs.get("levels", None)
+        if levels and not levels & self.levels:
+            return ""
 
-    def __init__(self, name, **kwargs):
-        super().__init__(name, **kwargs)
+        return self._dfd_template().format(
+            uniq_name=self._uniq_name(),
+            label=self._label(),
+            color=self._color(),
+            shape=self._shape(),
+        )
 
     def _shape(self):
-        return "circle"
+ return "rectangle; style=rounded"

Ancestors

    @@ -3111,7 +2327,7 @@

    Ancestors

Instance variables

-
var disablesDTD
+
var environment
@@ -3127,7 +2343,7 @@

Instance variables

return self.data.get(instance, self.default)
-
var encodesHeaders
+
var implementsAPI
@@ -3143,7 +2359,7 @@

Instance variables

return self.data.get(instance, self.default)
-
var implementsCSRFToken
+
var onAWS
@@ -3159,92 +2375,127 @@

Instance variables

return self.data.get(instance, self.default)
-
var implementsPOLP
+
+
+
+class Lifetime +(value, names=None, *, module=None, qualname=None, type=None, start=1) +
-

The principle of least privilege (PoLP), -also known as the principle of minimal privilege or the principle of least authority, -requires that in a particular abstraction layer of a computing environment, -every module (such as a process, a user, or a program, depending on the subject) -must be able to access only the information and resources -that are necessary for its legitimate purpose.

+

An enumeration.

Expand source code -
def __get__(self, instance, owner):
-    # when x.d is called we get here
-    # instance = x
-    # owner = type(x)
-    if instance is None:
-        return self
-    return self.data.get(instance, self.default)
+
class Lifetime(Enum):
+    # not applicable
+    NONE = "NONE"
+    # unknown lifetime
+    UNKNOWN = "UNKNOWN"
+    # relatively short expiration date (time to live)
+    SHORT = "SHORT_LIVED"
+    # long or no expiration date
+    LONG = "LONG_LIVED"
+    # no expiration date but revoked/invalidated automatically in some conditions
+    AUTO = "AUTO_REVOKABLE"
+    # no expiration date but can be invalidated manually
+    MANUAL = "MANUALLY_REVOKABLE"
+    # cannot be invalidated at all
+    HARDCODED = "HARDCODED"
+
+    def label(self):
+        return self.value.lower().replace("_", " ")
+

Ancestors

+
    +
  • enum.Enum
  • +
+

Class variables

+
+
var AUTO
+
+
+
+
var HARDCODED
+
+
-
var implementsServerSideValidation
+
var LONG
-
- -Expand source code - -
def __get__(self, instance, owner):
-    # when x.d is called we get here
-    # instance = x
-    # owner = type(x)
-    if instance is None:
-        return self
-    return self.data.get(instance, self.default)
-
-
var implementsStrictHTTPValidation
+
var MANUAL
+
+
+
+
var NONE
+
+
+
+
var SHORT
+
+
+
+
var UNKNOWN
-
- -Expand source code - -
def __get__(self, instance, owner):
-    # when x.d is called we get here
-    # instance = x
-    # owner = type(x)
-    if instance is None:
-        return self
-    return self.data.get(instance, self.default)
-
-
var invokesScriptFilters
+
+

Methods

+
+
+def label(self) +
Expand source code -
def __get__(self, instance, owner):
-    # when x.d is called we get here
-    # instance = x
-    # owner = type(x)
-    if instance is None:
-        return self
-    return self.data.get(instance, self.default)
+
def label(self):
+    return self.value.lower().replace("_", " ")
-
var isResilient
+
+
+
+class Process +(name, **kwargs) +
-
+

An entity processing data

Expand source code -
def __get__(self, instance, owner):
-    # when x.d is called we get here
-    # instance = x
-    # owner = type(x)
-    if instance is None:
-        return self
-    return self.data.get(instance, self.default)
+
class Process(Asset):
+    """An entity processing data"""
+
+    codeType = varString("Unmanaged")
+    implementsCommunicationProtocol = varBool(False)
+    tracksExecutionFlow = varBool(False)
+    implementsAPI = varBool(False)
+    environment = varString("")
+    allowsClientSideScripting = varBool(False)
+
+    def __init__(self, name, **kwargs):
+        super().__init__(name, **kwargs)
+
+    def _shape(self):
+        return "circle"
-
-
var providesConfidentiality
+

Ancestors

+
    +
  • pytm.pytm.Asset
  • +
  • pytm.pytm.Element
  • +
+

Subclasses

+
    +
  • pytm.pytm.SetOfProcesses
  • +
+

Instance variables

+
+
var allowsClientSideScripting
@@ -3260,7 +2511,7 @@

Instance variables

return self.data.get(instance, self.default)
-
var providesIntegrity
+
var codeType
@@ -3276,7 +2527,7 @@

Instance variables

return self.data.get(instance, self.default)
-
var usesCache
+
var environment
@@ -3292,7 +2543,7 @@

Instance variables

return self.data.get(instance, self.default)
-
var usesCodeSigning
+
var implementsAPI
@@ -3308,7 +2559,7 @@

Instance variables

return self.data.get(instance, self.default)
-
var usesEncryptionAlgorithm
+
var implementsCommunicationProtocol
@@ -3324,7 +2575,7 @@

Instance variables

return self.data.get(instance, self.default)
-
var usesSessionTokens
+
var tracksExecutionFlow
@@ -3340,23 +2591,40 @@

Instance variables

return self.data.get(instance, self.default)
-
var usesStrongSessionIdentifiers
+
+
+
+class Server +(name, **kwargs) +
-
+

An entity processing data

Expand source code -
def __get__(self, instance, owner):
-    # when x.d is called we get here
-    # instance = x
-    # owner = type(x)
-    if instance is None:
-        return self
-    return self.data.get(instance, self.default)
+
class Server(Asset):
+    """An entity processing data"""
+
+    usesSessionTokens = varBool(False)
+    usesCache = varBool(False)
+    usesVPN = varBool(False)
+    usesXMLParser = varBool(False)
+
+    def __init__(self, name, **kwargs):
+        super().__init__(name, **kwargs)
+
+    def _shape(self):
+        return "circle"
-
-
var usesVPN
+

Ancestors

+ +

Instance variables

+
+
var usesCache
@@ -3372,7 +2640,7 @@

Instance variables

return self.data.get(instance, self.default)
-
var usesXMLParser
+
var usesSessionTokens
@@ -3388,7 +2656,7 @@

Instance variables

return self.data.get(instance, self.default)
-
var validatesContentType
+
var usesVPN
@@ -3404,7 +2672,7 @@

Instance variables

return self.data.get(instance, self.default)
-
var validatesHeaders
+
var usesXMLParser
@@ -3531,7 +2799,8 @@

Class variables

_data = [] _threatsExcluded = [] _sf = None - _duplicate_ignored_attrs = "name", "note", "order", "response", "responseTo" + _duplicate_ignored_attrs = "name", "note", "order", "response", "responseTo", "controls" + _findings = [] name = varString("", required=True, doc="Model name") description = varString("", required=True, doc="Model description") threatsFile = varString( @@ -3572,6 +2841,8 @@

Class variables

cls._threats = [] cls._boundaries = [] cls._data = [] + cls._findings = [] + cls._threatsExcluded = [] def _init_threats(self): TM._threats = [] @@ -3588,10 +2859,30 @@

Class variables

finding_count = 0 findings = [] elements = defaultdict(list) + + #Manually added findings with element as arg to Finding object + for f in TM._findings: + if (f.element): + finding_count += 1 + f._safeset("id", str(finding_count)) + findings.append(f) + elements[f.element].append(f) + for e in TM._elements: if not e.inScope: continue + #Manually added findings, added to an element's finding attribute + if (len(e.findings) > 0): + + for f in e.findings: + finding_count += 1 + f._safeset("id", str(finding_count)) + f._safeset("element", e) + f._safeset("target", e.name) + findings.append(f) + elements[e].append(f) + override_ids = set(f.threat_id for f in e.overrides) # if element is a dataflow filter out overrides from source and sink # because they will be always applied there anyway @@ -3602,18 +2893,24 @@

Class variables

except AttributeError: pass + #Findings added by pytm using threatlib for t in TM._threats: if not t.apply(e) and t.id not in override_ids: continue + if t.id in TM._threatsExcluded: + continue + finding_count += 1 - f = Finding(e, id=str(finding_count), threat=t) + f = Finding(e, id=str(finding_count), threat=t, source="pytm") logger.debug(f"new finding: {f}") findings.append(f) elements[e].append(f) + self.findings = findings + for e, findings in elements.items(): - e.findings = findings + e._safeset("findings", findings) def check(self): if self.description is None: @@ -3673,6 +2970,17 @@

Class variables

right._is_drawn = True continue + left_controls_attrs = left.controls._attr_values() + right_controls_attrs = right.controls._attr_values() + #for a in self._duplicate_ignored_attrs: + # del left_controls_attrs[a], right_controls_attrs[a] + if left_controls_attrs != right_controls_attrs: + continue + if self.onDuplicates == Action.IGNORE: + right._is_drawn = True + continue + + raise ValueError( "Duplicate Dataflow found between {} and {}: " "{} is same as {}".format( @@ -3793,15 +3101,21 @@

Class variables

threats = encode_threat_data(TM._threats) findings = encode_threat_data(self.findings) + elements = encode_element_threat_data(TM._elements) + assets = encode_element_threat_data(TM._assets) + actors = encode_element_threat_data(TM._actors) + boundaries = encode_element_threat_data(TM._boundaries) + flows = encode_element_threat_data(TM._flows) + data = { "tm": self, - "dataflows": TM._flows, + "dataflows": flows, "threats": threats, "findings": findings, - "elements": TM._elements, - "assets": TM._assets, - "actors": TM._actors, - "boundaries": TM._boundaries, + "elements": elements, + "assets": assets, + "actors": actors, + "boundaries": boundaries, "data": TM._data, } @@ -3815,6 +3129,9 @@

Class variables

if result.debug: logger.setLevel(logging.DEBUG) + if result.exclude is not None: + TM._threatsExcluded = result.exclude.split(",") + if result.seq is True: print(self.seq()) @@ -3839,9 +3156,6 @@

Class variables

if result.report is not None: print(self.report(result.report)) - if result.exclude is not None: - TM._threatsExcluded = result.exclude.split(",") - if result.describe is not None: _describe_classes(result.describe.split()) @@ -3964,7 +3278,9 @@

Static methods

cls._assets = [] cls._threats = [] cls._boundaries = [] - cls._data = [] + cls._data = [] + cls._findings = [] + cls._threatsExcluded = []
@@ -4155,6 +3471,9 @@

Methods

if result.debug: logger.setLevel(logging.DEBUG) + if result.exclude is not None: + TM._threatsExcluded = result.exclude.split(",") + if result.seq is True: print(self.seq()) @@ -4179,9 +3498,6 @@

Methods

if result.report is not None: print(self.report(result.report)) - if result.exclude is not None: - TM._threatsExcluded = result.exclude.split(",") - if result.describe is not None: _describe_classes(result.describe.split()) @@ -4211,15 +3527,21 @@

Methods

threats = encode_threat_data(TM._threats) findings = encode_threat_data(self.findings) + elements = encode_element_threat_data(TM._elements) + assets = encode_element_threat_data(TM._assets) + actors = encode_element_threat_data(TM._actors) + boundaries = encode_element_threat_data(TM._boundaries) + flows = encode_element_threat_data(TM._flows) + data = { "tm": self, - "dataflows": TM._flows, + "dataflows": flows, "threats": threats, "findings": findings, - "elements": TM._elements, - "assets": TM._assets, - "actors": TM._actors, - "boundaries": TM._boundaries, + "elements": elements, + "assets": assets, + "actors": actors, + "boundaries": boundaries, "data": TM._data, } @@ -4239,10 +3561,30 @@

Methods

finding_count = 0 findings = [] elements = defaultdict(list) + + #Manually added findings with element as arg to Finding object + for f in TM._findings: + if (f.element): + finding_count += 1 + f._safeset("id", str(finding_count)) + findings.append(f) + elements[f.element].append(f) + for e in TM._elements: if not e.inScope: continue + #Manually added findings, added to an element's finding attribute + if (len(e.findings) > 0): + + for f in e.findings: + finding_count += 1 + f._safeset("id", str(finding_count)) + f._safeset("element", e) + f._safeset("target", e.name) + findings.append(f) + elements[e].append(f) + override_ids = set(f.threat_id for f in e.overrides) # if element is a dataflow filter out overrides from source and sink # because they will be always applied there anyway @@ -4253,18 +3595,24 @@

Methods

except AttributeError: pass + #Findings added by pytm using threatlib for t in TM._threats: if not t.apply(e) and t.id not in override_ids: continue + if t.id in TM._threatsExcluded: + continue + finding_count += 1 - f = Finding(e, id=str(finding_count), threat=t) + f = Finding(e, id=str(finding_count), threat=t, source="pytm") logger.debug(f"new finding: {f}") findings.append(f) elements[e].append(f) + self.findings = findings + for e, findings in elements.items(): - e.findings = findings + e._safeset("findings", findings)
@@ -4548,6 +3896,11 @@

Index

      +
    • Sub-modules

      + +
    • Functions

      • load
      • @@ -4566,16 +3919,13 @@

        Action

      • Actor

        -
          -
        • authenticatesDestination
        • -
        • checksDestinationRevocation
        • +
        • @@ -4615,17 +3965,11 @@

          Data

        • Dataflow

            -
          • authenticatedWith
          • -
          • authenticatesDestination
          • -
          • authorizesSource
          • -
          • checksDestinationRevocation
          • data
          • display_name
          • dstPort
          • hasDataLeaks
          • -
          • implementsAuthenticationScheme
          • implementsCommunicationProtocol
          • -
          • isEncrypted
          • isResponse
          • note
          • order
          • @@ -4642,28 +3986,33 @@

            Dataflow

          • Datastore

            -
              -
            • handlesInterruptions
            • -
            • handlesResourceConsumption
            • + + +
            • +

              DatastoreType

              +
            • Element

              @@ -4732,50 +4082,19 @@

              Process

            • Server

            • diff --git a/docs/pytm/report_util.html b/docs/pytm/report_util.html new file mode 100644 index 0000000..4cd1210 --- /dev/null +++ b/docs/pytm/report_util.html @@ -0,0 +1,241 @@ + + + + + + +pytm.report_util API documentation + + + + + + + + + + + +
              +
              +
              +

              Module pytm.report_util

              +
              +
              +
              + +Expand source code + +
              class ReportUtils:
              +    @staticmethod
              +    def getParentName(element):
              +        from pytm import Boundary
              +        if (isinstance(element, Boundary)):
              +            parent = element.inBoundary
              +            if (parent is not None):
              +                return parent.name
              +            else:
              +                return str("")
              +        else:
              +            return "ERROR: getParentName method is not valid for " + element.__class__.__name__
              +
              +
              +    @staticmethod
              +    def getNamesOfParents(element):
              +        from pytm import Boundary
              +        if (isinstance(element, Boundary)):
              +            parents = [p.name for p in element.parents()] 
              +            return parents 
              +        else:
              +            return "ERROR: getNamesOfParents method is not valid for " + element.__class__.__name__
              +
              +    @staticmethod
              +    def getFindingCount(element):
              +        from pytm import Element
              +        if (isinstance(element, Element)):
              +            return str(len(list(element.findings)))
              +        else:
              +            return "ERROR: getFindingCount method is not valid for " + element.__class__.__name__
              +
              +    @staticmethod
              +    def getElementType(element):
              +        from pytm import Element
              +        if (isinstance(element, Element)):
              +            return str(element.__class__.__name__)
              +        else:
              +            return "ERROR: getElementType method is not valid for " + element.__class__.__name__
              +
              +
              +
              +
              +
              +
              +
              +
              +
              +

              Classes

              +
              +
              +class ReportUtils +
              +
              +
              +
              + +Expand source code + +
              class ReportUtils:
              +    @staticmethod
              +    def getParentName(element):
              +        from pytm import Boundary
              +        if (isinstance(element, Boundary)):
              +            parent = element.inBoundary
              +            if (parent is not None):
              +                return parent.name
              +            else:
              +                return str("")
              +        else:
              +            return "ERROR: getParentName method is not valid for " + element.__class__.__name__
              +
              +
              +    @staticmethod
              +    def getNamesOfParents(element):
              +        from pytm import Boundary
              +        if (isinstance(element, Boundary)):
              +            parents = [p.name for p in element.parents()] 
              +            return parents 
              +        else:
              +            return "ERROR: getNamesOfParents method is not valid for " + element.__class__.__name__
              +
              +    @staticmethod
              +    def getFindingCount(element):
              +        from pytm import Element
              +        if (isinstance(element, Element)):
              +            return str(len(list(element.findings)))
              +        else:
              +            return "ERROR: getFindingCount method is not valid for " + element.__class__.__name__
              +
              +    @staticmethod
              +    def getElementType(element):
              +        from pytm import Element
              +        if (isinstance(element, Element)):
              +            return str(element.__class__.__name__)
              +        else:
              +            return "ERROR: getElementType method is not valid for " + element.__class__.__name__
              +
              +

              Static methods

              +
              +
              +def getElementType(element) +
              +
              +
              +
              + +Expand source code + +
              @staticmethod
              +def getElementType(element):
              +    from pytm import Element
              +    if (isinstance(element, Element)):
              +        return str(element.__class__.__name__)
              +    else:
              +        return "ERROR: getElementType method is not valid for " + element.__class__.__name__
              +
              +
              +
              +def getFindingCount(element) +
              +
              +
              +
              + +Expand source code + +
              @staticmethod
              +def getFindingCount(element):
              +    from pytm import Element
              +    if (isinstance(element, Element)):
              +        return str(len(list(element.findings)))
              +    else:
              +        return "ERROR: getFindingCount method is not valid for " + element.__class__.__name__
              +
              +
              +
              +def getNamesOfParents(element) +
              +
              +
              +
              + +Expand source code + +
              @staticmethod
              +def getNamesOfParents(element):
              +    from pytm import Boundary
              +    if (isinstance(element, Boundary)):
              +        parents = [p.name for p in element.parents()] 
              +        return parents 
              +    else:
              +        return "ERROR: getNamesOfParents method is not valid for " + element.__class__.__name__
              +
              +
              +
              +def getParentName(element) +
              +
              +
              +
              + +Expand source code + +
              @staticmethod
              +def getParentName(element):
              +    from pytm import Boundary
              +    if (isinstance(element, Boundary)):
              +        parent = element.inBoundary
              +        if (parent is not None):
              +            return parent.name
              +        else:
              +            return str("")
              +    else:
              +        return "ERROR: getParentName method is not valid for " + element.__class__.__name__
              +
              +
              +
              +
              +
              +
              +
              + +
              + + + \ No newline at end of file diff --git a/docs/threats.md b/docs/threats.md index 33853d0..ad38381 100644 --- a/docs/threats.md +++ b/docs/threats.md @@ -20,7 +20,7 @@ This attack pattern involves causing a buffer overflow through manipulation of e
              https://capec.mitre.org/data/definitions/10.html, CVE-1999-0906, CVE-1999-0046, http://cwe.mitre.org/data/definitions/120.html, http://cwe.mitre.org/data/definitions/119.html, http://cwe.mitre.org/data/definitions/680.html
              Condition
              -
              target.usesEnvironmentVariables is True and target.sanitizesInput is False and target.checksInputBounds is False
              +
              target.usesEnvironmentVariables is True and target.controls.sanitizesInput is False and target.controls.checksInputBounds is False
    @@ -46,7 +46,7 @@ Buffer Overflow attacks target improper or missing bounds checking on buffer ope
    https://capec.mitre.org/data/definitions/100.html, http://cwe.mitre.org/data/definitions/120.html, http://cwe.mitre.org/data/definitions/119.html, http://cwe.mitre.org/data/definitions/680.html
    Condition
    -
    target.checksInputBounds is False
    +
    target.controls.checksInputBounds is False
    @@ -72,7 +72,7 @@ An attacker can use Server Side Include (SSI) Injection to send code to a web ap
    https://capec.mitre.org/data/definitions/101.html, http://cwe.mitre.org/data/definitions/97.html, http://cwe.mitre.org/data/definitions/74.html, http://cwe.mitre.org/data/definitions/20.html, http://cwe.mitre.org/data/definitions/713.html
    Condition
    -
    target.sanitizesInput is False or target.encodesOutput is False
    +
    target.controls.sanitizesInput is False or target.controls.encodesOutput is False
    @@ -124,7 +124,7 @@ HTTP Request Splitting (also known as HTTP Request Smuggling) is an attack patte
    https://capec.mitre.org/data/definitions/105.html, http://cwe.mitre.org/data/definitions/436.html, http://cwe.mitre.org/data/definitions/444.html
    Condition
    -
    (target.validatesInput is False or target.validatesHeaders is False) and target.protocol =='HTTP'
    +
    (target.controls.validatesInput is False or target.controls.validatesHeaders is False) and target.protocol =='HTTP'
    @@ -150,7 +150,7 @@ Cross Site Tracing (XST) enables an adversary to steal the victim's session cook
    https://capec.mitre.org/data/definitions/107.html, http://cwe.mitre.org/data/definitions/693.html, http://cwe.mitre.org/data/definitions/648.html
    Condition
    -
    (target.protocol == 'HTTP' and target.usesSessionTokens is True) and (target.sanitizesInput is False or target.validatesInput is False)
    +
    (target.protocol == 'HTTP' and target.usesSessionTokens is True) and (target.controls.sanitizesInput is False or target.controls.validatesInput is False)
    @@ -176,7 +176,7 @@ An attacker uses standard SQL injection methods to inject data into the command
    https://capec.mitre.org/data/definitions/108.html, http://cwe.mitre.org/data/definitions/89.html, http://cwe.mitre.org/data/definitions/74.html, http://cwe.mitre.org/data/definitions/20.html, http://cwe.mitre.org/data/definitions/78.html, http://cwe.mitre.org/data/definitions/114.html
    Condition
    -
    target.validatesInput is False
    +
    target.controls.validatesInput is False
    @@ -202,7 +202,7 @@ An attacker modifies the parameters of the SOAP message that is sent from the se
    https://capec.mitre.org/data/definitions/110.html, http://cwe.mitre.org/data/definitions/89.html, http://cwe.mitre.org/data/definitions/20.html
    Condition
    -
    target.protocol == 'SOAP' and (target.sanitizesInput is False or target.validatesInput is False)
    +
    target.protocol == 'SOAP' and (target.controls.sanitizesInput is False or target.controls.validatesInput is False)
    @@ -228,7 +228,7 @@ An attacker targets a system that uses JavaScript Object Notation (JSON) as a tr
    https://capec.mitre.org/data/definitions/111.html, http://cwe.mitre.org/data/definitions/345.html, http://cwe.mitre.org/data/definitions/346.html, http://cwe.mitre.org/data/definitions/352.html
    Condition
    -
    target.implementsNonce is False and any(d.format == 'JSON' for d in target.data)
    +
    target.controls.implementsNonce is False and any(d.format == 'JSON' for d in target.data)
    @@ -254,7 +254,7 @@ An adversary manipulates the use or processing of an Application Programming Int
    https://capec.mitre.org/data/definitions/113.html, http://cwe.mitre.org/data/definitions/227.html
    Condition
    -
    target.implementsAPI is True and (target.validatesInput is False or target.sanitizesInput is False)
    +
    target.implementsAPI is True and (target.controls.validatesInput is False or target.controls.sanitizesInput is False)
    @@ -280,7 +280,7 @@ An attacker obtains unauthorized access to an application, service or device eit
    https://capec.mitre.org/data/definitions/114.html, http://cwe.mitre.org/data/definitions/287.html
    Condition
    -
    target.authenticatesSource is False
    +
    target.controls.authenticatesSource is False
    @@ -306,7 +306,7 @@ An adversary actively probes the target in a manner that is designed to solicit
    https://capec.mitre.org/data/definitions/116.html, http://cwe.mitre.org/data/definitions/200.html
    Condition
    -
    (target.sanitizesInput is False or target.validatesInput is False) or target.encodesOutput is False
    +
    (target.controls.sanitizesInput is False or target.controls.validatesInput is False) or target.controls.encodesOutput is False
    @@ -332,7 +332,7 @@ An adversary monitors data streams to or from the target for information gatheri
    https://capec.mitre.org/data/definitions/117.html, http://cwe.mitre.org/data/definitions/319.html, https://cwe.mitre.org/data/definitions/299.html
    Condition
    -
    not target.isEncrypted or (target.source.inScope and not target.isResponse and (not target.authenticatesDestination or not target.checksDestinationRevocation)) or target.tlsVersion < target.sink.minTLSVersion
    +
    not target.controls.isEncrypted or (target.source.inScope and not target.isResponse and (not target.controls.authenticatesDestination or not target.checksDestinationRevocation)) or target.tlsVersion < target.sink.minTLSVersion
    @@ -358,7 +358,7 @@ The adversary utilizes a repeating of the encoding process for a set of characte
    https://capec.mitre.org/data/definitions/120.html, http://cwe.mitre.org/data/definitions/173.html, http://cwe.mitre.org/data/definitions/177.html
    Condition
    -
    target.validatesInput is False or target.sanitizesInput is False
    +
    target.controls.validatesInput is False or target.controls.sanitizesInput is False
    @@ -410,7 +410,7 @@ An adversary is able to exploit features of the target that should be reserved f
    https://capec.mitre.org/data/definitions/122.html, http://cwe.mitre.org/data/definitions/732.html, http://cwe.mitre.org/data/definitions/269.html
    Condition
    -
    target.hasAccessControl is False or target.authorizesSource is False
    +
    target.controls.hasAccessControl is False or target.controls.authorizesSource is False
    @@ -436,7 +436,7 @@ An adversary manipulates an application's interaction with a buffer in an attemp
    https://capec.mitre.org/data/definitions/123.html, http://cwe.mitre.org/data/definitions/119.html
    Condition
    -
    target.usesSecureFunctions is False
    +
    target.controls.usesSecureFunctions is False
    @@ -488,7 +488,7 @@ An adversary consumes the resources of a target by rapidly engaging in a large n
    https://capec.mitre.org/data/definitions/125.html, http://cwe.mitre.org/data/definitions/404.html, http://cwe.mitre.org/data/definitions/770.html
    Condition
    -
    target.handlesResourceConsumption is False or target.isResilient is False
    +
    target.controls.handlesResourceConsumption is False or target.controls.isResilient is False
    @@ -514,7 +514,7 @@ An adversary uses path manipulation methods to exploit insufficient input valida
    https://capec.mitre.org/data/definitions/126.html, http://cwe.mitre.org/data/definitions/22.html
    Condition
    -
    target.validatesInput is False and target.sanitizesInput is False
    +
    target.controls.validatesInput is False and target.controls.sanitizesInput is False
    @@ -540,7 +540,7 @@ The attacker directly or indirectly modifies environment variables used by or co
    https://capec.mitre.org/data/definitions/13.html, http://cwe.mitre.org/data/definitions/353.html, http://cwe.mitre.org/data/definitions/15.html, http://cwe.mitre.org/data/definitions/74.html, http://cwe.mitre.org/data/definitions/302.html
    Condition
    -
    target.usesEnvironmentVariables is True and (target.implementsAuthenticationScheme is False or target.validatesInput is False or target.authorizesSource is False)
    +
    target.usesEnvironmentVariables is True and (target.controls.implementsAuthenticationScheme is False or target.controls.validatesInput is False or target.controls.authorizesSource is False)
    @@ -566,7 +566,7 @@ An adversary causes the target to allocate excessive resources to servicing the
    https://capec.mitre.org/data/definitions/130.html, http://cwe.mitre.org/data/definitions/770.html, http://cwe.mitre.org/data/definitions/404.html
    Condition
    -
    target.handlesResourceConsumption is False
    +
    target.controls.handlesResourceConsumption is False
    @@ -618,7 +618,7 @@ An adversary includes formatting characters in a string input field on the targe
    https://capec.mitre.org/data/definitions/135.html, http://cwe.mitre.org/data/definitions/134.html, http://cwe.mitre.org/data/definitions/133.html
    Condition
    -
    target.validatesInput is False or target.sanitizesInput is False
    +
    target.controls.validatesInput is False or target.controls.sanitizesInput is False
    @@ -644,7 +644,7 @@ An attacker manipulates or crafts an LDAP query for the purpose of undermining t
    https://capec.mitre.org/data/definitions/136.html, http://cwe.mitre.org/data/definitions/77.html, http://cwe.mitre.org/data/definitions/90.html, http://cwe.mitre.org/data/definitions/20.html
    Condition
    -
    target.validatesInput is False
    +
    target.controls.validatesInput is False
    @@ -670,7 +670,7 @@ An adversary manipulates the content of request parameters for the purpose of un
    https://capec.mitre.org/data/definitions/137.html, http://cwe.mitre.org/data/definitions/88.html
    Condition
    -
    target.validatesInput is False
    +
    target.controls.validatesInput is False
    @@ -696,7 +696,7 @@ An attacker exploits a weakness in input validation on the target by supplying a
    https://capec.mitre.org/data/definitions/139.html, http://cwe.mitre.org/data/definitions/23.html
    Condition
    -
    target.validatesInput is False or target.sanitizesInput is False
    +
    target.controls.validatesInput is False or target.controls.sanitizesInput is False
    @@ -722,7 +722,7 @@ This type of attack exploits a buffer overflow vulnerability in targeted client
    https://capec.mitre.org/data/definitions/14.html, http://cwe.mitre.org/data/definitions/74.html, http://cwe.mitre.org/data/definitions/353.html
    Condition
    -
    target.checksInputBounds is False and target.validatesInput is False
    +
    target.controls.checksInputBounds is False and target.controls.validatesInput is False
    @@ -748,7 +748,7 @@ An adversary corrupts or modifies the content of XML schema information passed b
    https://capec.mitre.org/data/definitions/146.html, http://cwe.mitre.org/data/definitions/15.html, http://cwe.mitre.org/data/definitions/472.html
    Condition
    -
    any(d.format == 'XML' for d in target.data) and target.authorizesSource is False
    +
    any(d.format == 'XML' for d in target.data) and target.controls.authorizesSource is False
    @@ -800,7 +800,7 @@ An adversary modifies content to make it contain something other than what the o
    https://capec.mitre.org/data/definitions/148.html, http://cwe.mitre.org/data/definitions/345.html, https://cwe.mitre.org/data/definitions/299.html
    Condition
    -
    ((not target.source.providesIntegrity or not target.sink.providesIntegrity) and not target.isEncrypted) or (target.source.inScope and not target.isResponse and (not target.authenticatesDestination or not target.checksDestinationRevocation))
    +
    ((not target.source.controls.providesIntegrity or not target.sink.controls.providesIntegrity) and not target.controls.isEncrypted) or (target.source.inScope and not target.isResponse and (not target.controls.authenticatesDestination or not target.checksDestinationRevocation))
    @@ -826,7 +826,7 @@ An attack of this type exploits a programs' vulnerabilities that allows an attac
    https://capec.mitre.org/data/definitions/15.html, http://cwe.mitre.org/data/definitions/146.html, http://cwe.mitre.org/data/definitions/77.html, http://cwe.mitre.org/data/definitions/157.html, http://cwe.mitre.org/data/definitions/154.html
    Condition
    -
    target.validatesInput is False
    +
    target.controls.validatesInput is False
    @@ -852,7 +852,7 @@ An attacker exploits a weakness in input validation by controlling the format, s
    https://capec.mitre.org/data/definitions/153.html, http://cwe.mitre.org/data/definitions/20.html
    Condition
    -
    target.validatesInput is False
    +
    target.controls.validatesInput is False
    @@ -878,7 +878,7 @@ In this attack pattern, the adversary intercepts information transmitted between
    https://capec.mitre.org/data/definitions/157.html, http://cwe.mitre.org/data/definitions/311.html
    Condition
    -
    (target.protocol == 'HTTP' or target.isEncrypted is False) or target.usesVPN is False
    +
    (target.protocol == 'HTTP' or target.controls.isEncrypted is False) or target.usesVPN is False
    @@ -904,7 +904,7 @@ An attacker tries each of the words in a dictionary as passwords to gain access
    https://capec.mitre.org/data/definitions/16.html, http://cwe.mitre.org/data/definitions/521.html, http://cwe.mitre.org/data/definitions/262.html, http://cwe.mitre.org/data/definitions/263.html
    Condition
    -
    target.implementsAuthenticationScheme is False
    +
    target.controls.implementsAuthenticationScheme is False
    @@ -930,7 +930,7 @@ Some APIs support scripting instructions as arguments. Methods that take scripte
    https://capec.mitre.org/data/definitions/160.html, http://cwe.mitre.org/data/definitions/346.html
    Condition
    -
    target.implementsAPI is True and target.validatesInput is False
    +
    target.implementsAPI is True and target.controls.validatesInput is False
    @@ -982,7 +982,7 @@ An adversary engages in probing and exploration activities to identify constitue
    https://capec.mitre.org/data/definitions/169.html, http://cwe.mitre.org/data/definitions/200.html
    Condition
    -
    target.isHardened is False
    +
    target.controls.isHardened is False
    @@ -1008,7 +1008,7 @@ An attack of this type exploits a system's configuration that allows an attacker
    https://capec.mitre.org/data/definitions/17.html, http://cwe.mitre.org/data/definitions/732.html, http://cwe.mitre.org/data/definitions/272.html, http://cwe.mitre.org/data/definitions/270.html
    Condition
    -
    target.isHardened is False or target.hasAccessControl is False
    +
    target.controls.isHardened is False or target.controls.hasAccessControl is False
    @@ -1034,7 +1034,7 @@ An attacker sends a series of probes to a web application in order to elicit ver
    https://capec.mitre.org/data/definitions/170.html, http://cwe.mitre.org/data/definitions/497.html
    Condition
    -
    target.validatesHeaders is False or target.encodesOutput is False or target.isHardened is False
    +
    target.controls.validatesHeaders is False or target.controls.encodesOutput is False or target.controls.isHardened is False
    @@ -1060,7 +1060,7 @@ This attack is a form of Cross-Site Scripting (XSS) where malicious scripts are
    https://capec.mitre.org/data/definitions/18.html, http://cwe.mitre.org/data/definitions/80.html
    Condition
    -
    target.validatesInput is False or target.encodesOutput is False
    +
    target.controls.validatesInput is False or target.controls.encodesOutput is False
    @@ -1074,7 +1074,7 @@ An attacker exploits a weakness in the configuration of access controls and is a
    Medium
    Prerequisites
    -
    The target must apply access controls, but incorrectly configure them. However, not all incorrect configurations can be exploited by an attacker. If the incorrect configuration applies too little security to some functionality, then the attacker may be able to exploit it if the access control would be the only thing preventing an attacker's access and it no longer does so. If the incorrect configuration applies too much security, it must prevent legitimate activity and the attacker must be able to force others to require this activity..
    +
    The target must apply access controls, but incorrectly configure them. However, not all incorrect configurations can be exploited by an attacker. If the incorrect configuration applies too little security to some functionality, then the attacker may be able to exploit it if the access control would be the only thing preventing an attacker's access and it no longer does so. If the incorrect configuration applies too much security, it must prevent legitimate activity and the attacker must be able to force others to require this activity.
    Example
    For example, an incorrectly configured Web server, may allow unauthorized access to it, thus threaten the security of the Web application.
    @@ -1086,7 +1086,7 @@ An attacker exploits a weakness in the configuration of access controls and is a
    https://capec.mitre.org/data/definitions/180.html, http://cwe.mitre.org/data/definitions/732.html
    Condition
    -
    target.hasAccessControl is False
    +
    target.controls.hasAccessControl is False
    @@ -1112,7 +1112,7 @@ An attacker exploits weaknesses in input validation on IMAP/SMTP servers to exec
    https://capec.mitre.org/data/definitions/183.html, http://cwe.mitre.org/data/definitions/77.html
    Condition
    -
    (target.protocol == 'IMAP' or target.protocol == 'SMTP') and target.sanitizesInput is False
    +
    (target.protocol == 'IMAP' or target.protocol == 'SMTP') and target.controls.sanitizesInput is False
    @@ -1164,7 +1164,7 @@ An attack of this type exploits a programs' vulnerabilities that are brought on
    https://capec.mitre.org/data/definitions/19.html, http://cwe.mitre.org/data/definitions/284.html
    Condition
    -
    target.validatesInput is False or target.sanitizesInput is False or target.hasAccessControl is False
    +
    target.controls.validatesInput is False or target.controls.sanitizesInput is False or target.controls.hasAccessControl is False
    @@ -1190,7 +1190,7 @@ In this pattern the adversary is able to load and execute arbitrary code remotel
    https://capec.mitre.org/data/definitions/193.html, http://cwe.mitre.org/data/definitions/98.html, http://cwe.mitre.org/data/definitions/80.html, http://cwe.mitre.org/data/definitions/714.html
    Condition
    -
    target.validatesInput is False
    +
    target.controls.validatesInput is False
    @@ -1216,7 +1216,7 @@ A Principal Spoof is a form of Identity Spoofing where an adversary pretends to
    https://capec.mitre.org/data/definitions/195.html
    Condition
    -
    target.authenticatesSource is False
    +
    target.controls.authenticatesSource is False
    @@ -1242,7 +1242,7 @@ An attacker creates a false but functional session credential in order to gain o
    https://capec.mitre.org/data/definitions/196.html, http://cwe.mitre.org/data/definitions/384.html, http://cwe.mitre.org/data/definitions/664.html
    Condition
    -
    target.usesSessionTokens is True and target.implementsNonce is False
    +
    target.usesSessionTokens is True and target.controls.implementsNonce is False
    @@ -1294,7 +1294,7 @@ An adversary distributes a link (or possibly some other query structure) with a
    https://capec.mitre.org/data/definitions/198.html, http://cwe.mitre.org/data/definitions/81.html
    Condition
    -
    target.encodesOutput is False or target.validatesInput is False or target.sanitizesInput is False
    +
    target.controls.encodesOutput is False or target.controls.validatesInput is False or target.controls.sanitizesInput is False
    @@ -1320,7 +1320,7 @@ An adversary uses alternate forms of keywords or commands that result in the sam
    https://capec.mitre.org/data/definitions/199.html, http://cwe.mitre.org/data/definitions/87.html
    Condition
    -
    target.sanitizesInput is False or target.validatesInput is False or target.encodesOutput is False
    +
    target.controls.sanitizesInput is False or target.controls.validatesInput is False or target.controls.encodesOutput is False
    @@ -1346,7 +1346,7 @@ An attacker, armed with the cipher text and the encryption algorithm used, perfo
    https://capec.mitre.org/data/definitions/20.html, http://cwe.mitre.org/data/definitions/326.html, http://cwe.mitre.org/data/definitions/327.html, http://cwe.mitre.org/data/definitions/693.html, http://cwe.mitre.org/data/definitions/719.html
    Condition
    -
    target.usesEncryptionAlgorithm != 'RSA' and target.usesEncryptionAlgorithm != 'AES'
    +
    target.controls.usesEncryptionAlgorithm != 'RSA' and target.controls.usesEncryptionAlgorithm != 'AES'
    @@ -1372,7 +1372,7 @@ An adversary exploits a weakness in authorization in order to modify content wit
    https://capec.mitre.org/data/definitions/203.html, http://cwe.mitre.org/data/definitions/15.html
    Condition
    -
    target.hasAccessControl is False
    +
    target.controls.hasAccessControl is False
    @@ -1424,7 +1424,7 @@ An attacker removes or disables functionality on the client that the server assu
    http://cwe.mitre.org/data/definitions/602.html
    Condition
    -
    target.providesIntegrity is False or target.usesCodeSigning is False
    +
    target.controls.providesIntegrity is False or target.controls.usesCodeSigning is False
    @@ -1450,7 +1450,7 @@ An adversary creates a file with scripting content but where the specified MIME
    http://cwe.mitre.org/data/definitions/79.html, http://cwe.mitre.org/data/definitions/20.html, http://cwe.mitre.org/data/definitions/646.html
    Condition
    -
    target.validatesContentType is False or target.invokesScriptFilters is False
    +
    target.controls.validatesContentType is False or target.controls.invokesScriptFilters is False
    @@ -1476,7 +1476,7 @@ Attacks on session IDs and resource IDs take advantage of the fact that some sof
    https://capec.mitre.org/data/definitions/21.html, http://cwe.mitre.org/data/definitions/290.html, http://cwe.mitre.org/data/definitions/346.html, http://cwe.mitre.org/data/definitions/664.html
    Condition
    -
    target.providesIntegrity is False or target.authenticatesSource is False or target.usesStrongSessionIdentifiers is False
    +
    target.controls.providesIntegrity is False or target.controls.authenticatesSource is False or target.controls.usesStrongSessionIdentifiers is False
    @@ -1502,7 +1502,7 @@ An adversary leverages a legitimate capability of an application in such a way a
    https://capec.mitre.org/data/definitions/212.html
    Condition
    -
    target.hasAccessControl is False or target.authorizesSource is False
    +
    target.controls.hasAccessControl is False or target.controls.authorizesSource is False
    @@ -1528,7 +1528,7 @@ An attacker sends random, malformed, or otherwise unexpected messages to a targe
    https://capec.mitre.org/data/definitions/215.html, http://cwe.mitre.org/data/definitions/209.html, http://cwe.mitre.org/data/definitions/532.html
    Condition
    -
    target.sanitizesInput is False or target.encodesOutput is False
    +
    target.controls.sanitizesInput is False or target.controls.encodesOutput is False
    @@ -1554,7 +1554,7 @@ An adversary manipulates a setting or parameter on communications channel in ord
    https://capec.mitre.org/data/definitions/216.html
    Condition
    -
    (target.protocol != 'HTTPS' or target.usesVPN is False) and (target.implementsAuthenticationScheme is False or target.authorizesSource is False)
    +
    (target.protocol != 'HTTPS' or target.usesVPN is False) and (target.controls.implementsAuthenticationScheme is False or target.controls.authorizesSource is False)
    @@ -1580,7 +1580,7 @@ An adversary takes advantage of incorrectly configured SSL communications that e
    https://capec.mitre.org/data/definitions/217.html, http://cwe.mitre.org/data/definitions/201.html
    Condition
    -
    target.checkTLSVersion(target.inputs) and (not target.implementsAuthenticationScheme or not target.authorizesSource)
    +
    target.checkTLSVersion(target.inputs) and (not target.controls.implementsAuthenticationScheme or not target.controls.authorizesSource)
    @@ -1632,7 +1632,7 @@ An attack of this type exploits vulnerabilities in client/server communication c
    https://capec.mitre.org/data/definitions/22.html, http://cwe.mitre.org/data/definitions/287.html
    Condition
    -
    target.implementsServerSideValidation is False and (target.providesIntegrity is False or target.authorizesSource is False)
    +
    target.controls.implementsServerSideValidation is False and (target.controls.providesIntegrity is False or target.controls.authorizesSource is False)
    @@ -1658,7 +1658,7 @@ An adversary takes advantage of weaknesses in the protocol by which a client and
    https://capec.mitre.org/data/definitions/220.html, http://cwe.mitre.org/data/definitions/757.html
    Condition
    -
    not target.isEncrypted or target.tlsVersion < target.sink.minTLSVersion
    +
    not target.controls.isEncrypted or target.tlsVersion < target.sink.minTLSVersion
    @@ -1684,7 +1684,7 @@ This attack takes advantage of the entity replacement property of XML where the
    https://capec.mitre.org/data/definitions/221.html, http://cwe.mitre.org/data/definitions/611.html
    Condition
    -
    target.usesXMLParser is False or target.disablesDTD is False
    +
    target.usesXMLParser is False or target.controls.disablesDTD is False
    @@ -1710,7 +1710,7 @@ In an iFrame overlay attack the victim is tricked into unknowingly initiating so
    https://capec.mitre.org/data/definitions/222.html, http://cwe.mitre.org/data/definitions/1021.html
    Condition
    -
    target.disablesiFrames is False
    +
    target.controls.disablesiFrames is False
    @@ -1736,7 +1736,7 @@ An attacker manipulates an existing credential in order to gain access to a targ
    https://capec.mitre.org/data/definitions/226.html, http://cwe.mitre.org/data/definitions/565.html, http://cwe.mitre.org/data/definitions/472.html
    Condition
    -
    target.usesStrongSessionIdentifiers is False
    +
    target.controls.usesStrongSessionIdentifiers is False
    @@ -1762,7 +1762,7 @@ An attacker injects malicious content into an application's DTD in an attempt to
    https://capec.mitre.org/data/definitions/228.html, http://cwe.mitre.org/data/definitions/829.html
    Condition
    -
    target.usesXMLParser is False or target.disablesDTD is False
    +
    target.usesXMLParser is False or target.controls.disablesDTD is False
    @@ -1788,7 +1788,7 @@ This attack exploits certain XML parsers which manage data in an inefficient man
    https://capec.mitre.org/data/definitions/229.html, http://cwe.mitre.org/data/definitions/770.html
    Condition
    -
    target.usesXMLParser is False or target.disablesDTD is False
    +
    target.usesXMLParser is False or target.controls.disablesDTD is False
    @@ -1814,7 +1814,7 @@ An attack of this type exploits the host's trust in executing remote content, in
    https://capec.mitre.org/data/definitions/23.html, http://cwe.mitre.org/data/definitions/20.html
    Condition
    -
    target.hasAccessControl is False and (target.sanitizesInput is False or target.validatesInput is False)
    +
    target.controls.hasAccessControl is False and (target.controls.sanitizesInput is False or target.controls.validatesInput is False)
    @@ -1840,7 +1840,7 @@ Applications often need to transform data in and out of the XML format by using
    https://capec.mitre.org/data/definitions/230.html, http://cwe.mitre.org/data/definitions/112.html, http://cwe.mitre.org/data/definitions/770.html
    Condition
    -
    target.usesXMLParser is True and (target.validatesInput is False or target.sanitizesInput is False)
    +
    target.usesXMLParser is True and (target.controls.validatesInput is False or target.controls.sanitizesInput is False)
    @@ -1866,7 +1866,7 @@ An adversary exploits a weakness enabling them to elevate their privilege and pe
    https://capec.mitre.org/data/definitions/233.html, http://cwe.mitre.org/data/definitions/269.html
    Condition
    -
    target.hasAccessControl is False or target.implementsPOLP is False
    +
    target.controls.hasAccessControl is False or target.controls.implementsPOLP is False
    @@ -1892,7 +1892,7 @@ An attacker gains control of a process that is assigned elevated privileges in o
    https://capec.mitre.org/data/definitions/234.html, http://cwe.mitre.org/data/definitions/732.html, http://cwe.mitre.org/data/definitions/648.html
    Condition
    -
    target.hasAccessControl is False or target.implementsPOLP is False
    +
    target.controls.hasAccessControl is False or target.controls.implementsPOLP is False
    @@ -1918,7 +1918,7 @@ Attackers can sometimes hijack a privileged thread from the underlying system th
    https://capec.mitre.org/data/definitions/236.html, http://cwe.mitre.org/data/definitions/270.html
    Condition
    -
    target.implementsPOLP is False and (target.usesEnvironmentVariables is True or target.validatesInput is False)
    +
    target.controls.implementsPOLP is False and (target.usesEnvironmentVariables is True or target.controls.validatesInput is False)
    @@ -1944,7 +1944,7 @@ In this attack, the idea is to cause an active filter to fail by causing an over
    https://capec.mitre.org/data/definitions/24.html, http://cwe.mitre.org/data/definitions/120.html, http://cwe.mitre.org/data/definitions/680.html, http://cwe.mitre.org/data/definitions/20.html
    Condition
    -
    target.checksInputBounds is False or target.validatesInput is False
    +
    target.controls.checksInputBounds is False or target.controls.validatesInput is False
    @@ -1970,7 +1970,7 @@ An adversary exploits weaknesses in input validation by manipulating resource id
    https://capec.mitre.org/data/definitions/240.html, https://capec.mitre.org/data/definitions/240.html
    Condition
    -
    target.validatesInput is False or target.sanitizesInput is False
    +
    target.controls.validatesInput is False or target.controls.sanitizesInput is False
    @@ -1996,7 +1996,7 @@ An adversary exploits a weakness in input validation on the target to inject new
    https://capec.mitre.org/data/definitions/242.html, http://cwe.mitre.org/data/definitions/94.html
    Condition
    -
    target.validatesInput is False or target.sanitizesInput is False
    +
    target.controls.validatesInput is False or target.controls.sanitizesInput is False
    @@ -2022,7 +2022,7 @@ An adversary inserts commands to perform cross-site scripting (XSS) actions in H
    https://capec.mitre.org/data/definitions/243.html
    Condition
    -
    target.validatesInput is False or target.sanitizesInput is False
    +
    target.controls.validatesInput is False or target.controls.sanitizesInput is False
    @@ -2048,7 +2048,7 @@ An attack of this type exploits the ability of most browsers to interpret data,
    https://capec.mitre.org/data/definitions/244.html, http://cwe.mitre.org/data/definitions/83.html
    Condition
    -
    target.validatesInput is False or target.sanitizesInput is False or target.encodesOutput is False
    +
    target.controls.validatesInput is False or target.controls.sanitizesInput is False or target.controls.encodesOutput is False
    @@ -2074,7 +2074,7 @@ The attacker bypasses input validation by using doubled characters in order to p
    https://capec.mitre.org/data/definitions/245.html
    Condition
    -
    target.validatesInput is False or target.sanitizesInput is False or target.encodesOutput is False
    +
    target.controls.validatesInput is False or target.controls.sanitizesInput is False or target.controls.encodesOutput is False
    @@ -2100,7 +2100,7 @@ An adversary inserts invalid characters in identifiers to bypass application fil
    https://capec.mitre.org/data/definitions/247.html, https://cwe.mitre.org/data/definitions/86.html
    Condition
    -
    target.validatesInput is False or target.sanitizesInput is False
    +
    target.controls.validatesInput is False or target.controls.sanitizesInput is False
    @@ -2126,7 +2126,7 @@ An adversary looking to execute a command of their choosing, injects new items i
    https://capec.mitre.org/data/definitions/248.html
    Condition
    -
    target.usesParameterizedInput is False and (target.validatesInput is False or target.sanitizesInput is False)
    +
    target.controls.usesParameterizedInput is False and (target.controls.validatesInput is False or target.controls.sanitizesInput is False)
    @@ -2152,7 +2152,7 @@ An attacker utilizes crafted XML user-controllable input to probe, attack, and i
    https://capec.mitre.org/data/definitions/250.html
    Condition
    -
    target.validatesInput is False or target.sanitizesInput is False or target.encodesOutput is False
    +
    target.controls.validatesInput is False or target.controls.sanitizesInput is False or target.controls.encodesOutput is False
    @@ -2178,7 +2178,7 @@ The attacker forces an application to load arbitrary code files from a remote lo
    https://capec.mitre.org/data/definitions/253.html
    Condition
    -
    target.validatesInput is False or target.sanitizesInput is False
    +
    target.controls.validatesInput is False or target.controls.sanitizesInput is False
    @@ -2204,7 +2204,7 @@ An attacker sends a SOAP request with an array whose actual length exceeds the l
    https://capec.mitre.org/data/definitions/256.html
    Condition
    -
    target.checksInputBounds is False
    +
    target.controls.checksInputBounds is False
    @@ -2230,7 +2230,7 @@ An adversary leverages the possibility to encode potentially harmful input or co
    https://capec.mitre.org/data/definitions/267.html
    Condition
    -
    target.validatesInput is False or target.sanitizesInput is False
    +
    target.controls.validatesInput is False or target.controls.sanitizesInput is False
    @@ -2256,7 +2256,7 @@ The attacker injects, manipulates, deletes, or forges malicious log entries into
    https://capec.mitre.org/data/definitions/268.html, https://capec.mitre.org/data/definitions/93.html
    Condition
    -
    target.validatesInput is False or target.implementsPOLP is False
    +
    target.controls.validatesInput is False or target.controls.implementsPOLP is False
    @@ -2282,7 +2282,7 @@ An adversary corrupts or modifies the content of a schema for the purpose of und
    https://capec.mitre.org/data/definitions/271.html
    Condition
    -
    target.implementsPOLP is False
    +
    target.controls.implementsPOLP is False
    @@ -2308,7 +2308,7 @@ An attacker injects content into a server response that is interpreted different
    https://capec.mitre.org/data/definitions/273.html
    Condition
    -
    target.implementsStrictHTTPValidation is False and target.encodesHeaders is False
    +
    target.controls.implementsStrictHTTPValidation is False and target.controls.encodesHeaders is False
    @@ -2334,7 +2334,7 @@ HTTP Request Smuggling results from the discrepancies in parsing HTTP requests b
    https://capec.mitre.org/data/definitions/33.html
    Condition
    -
    target.implementsStrictHTTPValidation is False and target.encodesHeaders is False
    +
    target.controls.implementsStrictHTTPValidation is False and target.controls.encodesHeaders is False
    @@ -2360,7 +2360,7 @@ This type of attack is a form of Cross-Site Scripting (XSS) where a malicious sc
    https://capec.mitre.org/data/definitions/588.html
    Condition
    -
    target.allowsClientSideScripting is True and (target.sanitizesInput is False or target.validatesInput is False)
    +
    target.allowsClientSideScripting is True and (target.controls.sanitizesInput is False or target.controls.validatesInput is False)
    @@ -2386,7 +2386,7 @@ This attack targets predictable session ID in order to gain privileges. The atta
    https://capec.mitre.org/data/definitions/59.html
    Condition
    -
    target.usesStrongSessionIdentifiers is False
    +
    target.controls.usesStrongSessionIdentifiers is False
    @@ -2412,7 +2412,7 @@ This type of attack is a form of Cross-Site Scripting (XSS) where a malicious sc
    https://capec.mitre.org/data/definitions/591.html
    Condition
    -
    target.allowsClientSideScripting is True and (target.sanitizesInput is False or target.validatesInput is False)
    +
    target.allowsClientSideScripting is True and (target.controls.sanitizesInput is False or target.controls.validatesInput is False)
    @@ -2438,7 +2438,7 @@ This type of attack is a form of Cross-site Scripting (XSS) where a malicious sc
    https://capec.mitre.org/data/definitions/592.html
    Condition
    -
    target.allowsClientSideScripting is True and (target.sanitizesInput is False or target.validatesInput is False)
    +
    target.allowsClientSideScripting is True and (target.controls.sanitizesInput is False or target.controls.validatesInput is False)
    @@ -2464,7 +2464,7 @@ This type of attack involves an adversary that exploits weaknesses in an applica
    https://capec.mitre.org/data/definitions/593.html
    Condition
    -
    target.usesStrongSessionIdentifiers is False
    +
    target.controls.usesStrongSessionIdentifiers is False
    @@ -2490,7 +2490,7 @@ This type of attack involves an adversary that exploits weaknesses in an applica
    https://capec.mitre.org/data/definitions/593.html
    Condition
    -
    (target.usesStrongSessionIdentifiers is False or target.encryptsCookies is False) and target.definesConnectionTimeout is False
    +
    (target.controls.usesStrongSessionIdentifiers is False or target.controls.encryptsCookies is False) and target.controls.definesConnectionTimeout is False
    @@ -2516,7 +2516,7 @@ An attacker changes the behavior or state of a targeted application through inje
    https://capec.mitre.org/data/definitions/6.html
    Condition
    -
    target.validatesInput is False or target.sanitizesInput is False
    +
    target.controls.validatesInput is False or target.controls.sanitizesInput is False
    @@ -2542,7 +2542,7 @@ This attack targets the reuse of valid session ID to spoof the target system in
    https://capec.mitre.org/data/definitions/60.html
    Condition
    -
    target.usesSessionTokens is True and target.implementsNonce is False
    +
    target.usesSessionTokens is True and target.controls.implementsNonce is False
    @@ -2568,7 +2568,7 @@ This attack targets the reuse of valid session ID to spoof the target system in
    https://capec.mitre.org/data/definitions/60.html
    Condition
    -
    target.definesConnectionTimeout is False and (target.usesMFA is False or target.encryptsSessionData is False)
    +
    target.controls.definesConnectionTimeout is False and (target.controls.usesMFA is False or target.controls.encryptsSessionData is False)
    @@ -2594,7 +2594,7 @@ An attacker crafts malicious web links and distributes them (via web pages, emai
    https://capec.mitre.org/data/definitions/62.html
    Condition
    -
    target.implementsCSRFToken is False or target.verifySessionIdentifiers is False
    +
    target.controls.implementsCSRFToken is False or target.controls.verifySessionIdentifiers is False
    @@ -2646,7 +2646,7 @@ An attacker can access data in transit or at rest that is not sufficiently prote
    https://cwe.mitre.org/data/definitions/311.html, https://cwe.mitre.org/data/definitions/312.html, https://cwe.mitre.org/data/definitions/916.html, https://cwe.mitre.org/data/definitions/653.html
    Condition
    -
    (target.hasDataLeaks() or any(d.isCredentials or d.isPII for d in target.data)) and (not target.isEncrypted or (not target.isResponse and any(d.isStored and d.isDestEncryptedAtRest for d in target.data)) or (target.isResponse and any(d.isStored and d.isSourceEncryptedAtRest for d in target.data)))
    +
    (target.hasDataLeaks() or any(d.isCredentials or d.isPII for d in target.data)) and (not target.controls.isEncrypted or (not target.isResponse and any(d.isStored and d.isDestEncryptedAtRest for d in target.data)) or (target.isResponse and any(d.isStored and d.isSourceEncryptedAtRest for d in target.data)))
    diff --git a/pytm/pytm.py b/pytm/pytm.py index b18a197..65a5b97 100644 --- a/pytm/pytm.py +++ b/pytm/pytm.py @@ -629,17 +629,17 @@ class Finding: """Represents a Finding - the element in question and a description of the finding""" - element = varElement(None, required=True, doc="Element this finding applies to") + element = varElement(None, required=False, doc="Element this finding applies to") target = varString("", doc="Name of the element this finding applies to") description = varString("", required=True, doc="Threat description") details = varString("", required=True, doc="Threat details") - severity = varString("", required=True, doc="Threat severity") - mitigations = varString("", required=True, doc="Threat mitigations") - example = varString("", required=True, doc="Threat example") + severity = varString("", required=False, doc="Threat severity") + mitigations = varString("", required=False, doc="Threat mitigations") + example = varString("", required=False, doc="Threat example") id = varString("", required=True, doc="Finding ID") - threat_id = varString("", required=True, doc="Threat ID") - references = varString("", required=True, doc="Threat references") - condition = varString("", required=True, doc="Threat condition") + threat_id = varString("", required=False, doc="Threat ID") + references = varString("", required=False, doc="Threat references") + condition = varString("", required=False, doc="Threat condition") response = varString( "", required=False, @@ -652,6 +652,7 @@ class Finding: """, ) cvss = varString("", required=False, doc="The CVSS score and/or vector") + source = varString("manual", required=False, doc="The source of the Finding.") def __init__( self, @@ -661,10 +662,12 @@ def __init__( if args: element = args[0] else: - element = kwargs.pop("element", Element("invalid")) + element = kwargs.pop("element", None) + + if (element): + self.target = element.name + self.element = element - self.target = element.name - self.element = element attrs = [ "description", "details", @@ -682,25 +685,30 @@ def __init__( kwargs[a] = getattr(threat, a) threat_id = kwargs.get("threat_id", None) - for f in element.overrides: - if f.threat_id != threat_id: - continue - for i in dir(f.__class__): - attr = getattr(f.__class__, i) - if ( - i in ("element", "target") - or i.startswith("_") - or callable(attr) - or not isinstance(attr, var) - ): + + if (element): + for f in element.overrides: + if f.threat_id != threat_id: continue - if f in attr.data: - kwargs[i] = attr.data[f] - break - + for i in dir(f.__class__): + attr = getattr(f.__class__, i) + if ( + i in ("element", "target") + or i.startswith("_") + or callable(attr) + or not isinstance(attr, var) + ): + continue + if f in attr.data: + kwargs[i] = attr.data[f] + break + for k, v in kwargs.items(): setattr(self, k, v) + TM._findings.append(self) + + def _safeset(self, attr, value): try: setattr(self, attr, value) @@ -730,6 +738,7 @@ class TM: _threatsExcluded = [] _sf = None _duplicate_ignored_attrs = "name", "note", "order", "response", "responseTo", "controls" + _findings = [] name = varString("", required=True, doc="Model name") description = varString("", required=True, doc="Model description") threatsFile = varString( @@ -770,6 +779,7 @@ def reset(cls): cls._threats = [] cls._boundaries = [] cls._data = [] + cls._findings = [] cls._threatsExcluded = [] def _init_threats(self): @@ -787,10 +797,30 @@ def resolve(self): finding_count = 0 findings = [] elements = defaultdict(list) + + #Manually added findings with element as arg to Finding object + for f in TM._findings: + if (f.element): + finding_count += 1 + f._safeset("id", str(finding_count)) + findings.append(f) + elements[f.element].append(f) + for e in TM._elements: if not e.inScope: continue + #Manually added findings, added to an element's finding attribute + if (len(e.findings) > 0): + + for f in e.findings: + finding_count += 1 + f._safeset("id", str(finding_count)) + f._safeset("element", e) + f._safeset("target", e.name) + findings.append(f) + elements[e].append(f) + override_ids = set(f.threat_id for f in e.overrides) # if element is a dataflow filter out overrides from source and sink # because they will be always applied there anyway @@ -801,6 +831,7 @@ def resolve(self): except AttributeError: pass + #Findings added by pytm using threatlib for t in TM._threats: if not t.apply(e) and t.id not in override_ids: continue @@ -809,13 +840,15 @@ def resolve(self): continue finding_count += 1 - f = Finding(e, id=str(finding_count), threat=t) + f = Finding(e, id=str(finding_count), threat=t, source="pytm") logger.debug(f"new finding: {f}") findings.append(f) elements[e].append(f) + self.findings = findings + for e, findings in elements.items(): - e.findings = findings + e._safeset("findings", findings) def check(self): if self.description is None: @@ -1909,6 +1942,7 @@ def encode_threat_data(obj): "threat_id", "references", "condition", + "source", ] if type(obj) is Finding or (len(obj) != 0 and type(obj[0]) is Finding): diff --git a/tm.py b/tm.py index 68a4197..e6d9c8a 100755 --- a/tm.py +++ b/tm.py @@ -10,6 +10,7 @@ Datastore, Lambda, Server, + Finding, DatastoreType, ) @@ -39,6 +40,19 @@ web.controls.encodesOutput = True web.controls.authorizesSource = False web.sourceFiles = ["pytm/json.py", "docs/template.md"] +web.findings = [ + Finding( + description = "foo_description_3", + details = "foo_details_3", + ), +] + +Finding(web, + description = "foo_description_4", + details = "foo_details_4", + ) + + db = Datastore("SQL Database") db.OS = "CentOS" @@ -114,6 +128,30 @@ my_lambda_to_db.protocol = "MySQL" my_lambda_to_db.dstPort = 3306 my_lambda_to_db.data = clear_op +my_lambda_to_db.findings = [ + Finding( + description = "foo_description_1", + details = "foo_details", + severity = "HIGH", + mitigations = "foo_mitigations", + example = "foo_example", + threat_id = "foo_threat_id_1", + references = "foo_references", + response = "accepted", + ), + Finding( + description = "foo_description_2", + details = "foo_details", + severity = "HIGH", + mitigations = "foo_mitigations", + example = "foo_example", + threat_id = "foo_threat_id_2", + references = "foo_references", + response = "accepted", + source = "Product Security" + ) + +] userIdToken = Data( name="User ID Token",