From e0b5c1a01279fec1ce86b8107149a9b0616de698 Mon Sep 17 00:00:00 2001 From: izar tarandach Date: Wed, 12 Feb 2025 14:55:40 -0500 Subject: [PATCH 1/8] feat: Support multiple threat files in threat management system --- pytm/pytm.py | 47 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 33 insertions(+), 14 deletions(-) diff --git a/pytm/pytm.py b/pytm/pytm.py index a711687..aef38da 100644 --- a/pytm/pytm.py +++ b/pytm/pytm.py @@ -787,11 +787,8 @@ class TM: ) name = varString("", required=True, doc="Model name") description = varString("", required=True, doc="Model description") - threatsFile = varString( - os.path.dirname(__file__) + "/threatlib/threats.json", - onSet=lambda i, v: i._init_threats(), - doc="JSON file with custom threats", - ) + threatsFile = varStrings("") + threatsFileInit = False isOrdered = varBool(False, doc="Automatically order all Dataflows") mergeResponses = varBool(False, doc="Merge response edges in DFDs") ignoreUnused = varBool(False, doc="Ignore elements not used in any Dataflow") @@ -838,16 +835,19 @@ def _init_threats(self): self._add_threats() def _add_threats(self): - try: - with open(self.threatsFile, "r", encoding="utf8") as threat_file: - threats_json = json.load(threat_file) - except (FileNotFoundError, PermissionError, IsADirectoryError) as e: - raise UIError( - e, f"while trying to open the the threat file ({self.threatsFile})." + + for threat_file_path in self.threatsFile: + try: + with open(self.threatsFile, "r", encoding="utf8") as threat_file: + threats_json = json.load(threat_file) + except (FileNotFoundError, PermissionError, IsADirectoryError) as e: + raise UIError( + e, f"while trying to open the the threat file ({self.threatsFile})." ) - active_threats = (threat for threat in threats_json if "DEPRECATED" not in threat) - for threat in active_threats: - TM._threats.append(Threat(**threat)) + + active_threats = (threat for threat in threats_json if "DEPRECATED" not in threat) + for threat in active_threats: + TM._threats.append(Threat(**threat)) def resolve(self): finding_count = 0 @@ -1129,6 +1129,19 @@ def _process(self): result = get_args() logging.basicConfig(level=logging.INFO, format="%(levelname)s: %(message)s") + # delaying loading of threats to accomodate multiple threat files in the + # command line + if self.threatsFileInit == False: + tfs = [os.path.dirname(__file__) + "/threatlib/threats.json"] + if result.threat_files: + tfs.extend(result.threat_files) + self.threatsFile = varStrings( + tfs, + onSet=lambda i, v: i._init_threats(), + doc="JSON file with custom threats", + ) + self.threatsFileInit = True + if result.debug: logger.setLevel(logging.DEBUG) @@ -1178,6 +1191,7 @@ def _process(self): if result.stale_days is not None: print(self._stale(result.stale_days)) + def _stale(self, days): try: base_path = os.path.dirname(sys.argv[0]) @@ -2158,6 +2172,11 @@ def get_args(): help="""checks if the delta between the TM script and the code described by it is bigger than the specified value in days""", type=int, ) + _parser.add_argument( + "--threat-files", + nargs="+", + help="Files containing libraries of threats." + ) _args = _parser.parse_args() return _args From 7be52ea9e904dc4a8d0d80078f790a2426f90d3b Mon Sep 17 00:00:00 2001 From: izar tarandach Date: Wed, 12 Feb 2025 14:55:40 -0500 Subject: [PATCH 2/8] fix: Correct threatsFile initialization to accept a list of strings --- pytm/pytm.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/pytm/pytm.py b/pytm/pytm.py index aef38da..74ae6f2 100644 --- a/pytm/pytm.py +++ b/pytm/pytm.py @@ -1135,11 +1135,8 @@ def _process(self): tfs = [os.path.dirname(__file__) + "/threatlib/threats.json"] if result.threat_files: tfs.extend(result.threat_files) - self.threatsFile = varStrings( - tfs, - onSet=lambda i, v: i._init_threats(), - doc="JSON file with custom threats", - ) + self.threatsFile = tfs + self._init_threats() self.threatsFileInit = True if result.debug: From 370ccb66c439a7d8a9ac4d0227df314311162afe Mon Sep 17 00:00:00 2001 From: izar tarandach Date: Wed, 12 Feb 2025 14:56:52 -0500 Subject: [PATCH 3/8] fix: Correct file opening in _add_threats to iterate over threat files --- pytm/pytm.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pytm/pytm.py b/pytm/pytm.py index 74ae6f2..be067f6 100644 --- a/pytm/pytm.py +++ b/pytm/pytm.py @@ -836,9 +836,9 @@ def _init_threats(self): def _add_threats(self): - for threat_file_path in self.threatsFile: + for threat_file in self.threatsFile: try: - with open(self.threatsFile, "r", encoding="utf8") as threat_file: + with open(threat_file, "r", encoding="utf8") as threat_file: threats_json = json.load(threat_file) except (FileNotFoundError, PermissionError, IsADirectoryError) as e: raise UIError( From 2ec73a6328ab523d43e8dbd8fbead4984073cd8e Mon Sep 17 00:00:00 2001 From: izar tarandach Date: Wed, 12 Feb 2025 15:16:02 -0500 Subject: [PATCH 4/8] test: Update threat count assertion and add test for multiple threat files --- tests/test_private_func.py | 2 +- tests/test_pytmfunc.py | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/tests/test_private_func.py b/tests/test_private_func.py index 4ce0816..858dd86 100644 --- a/tests/test_private_func.py +++ b/tests/test_private_func.py @@ -49,7 +49,7 @@ def test_kwargs(self): def test_load_threats(self): tm = TM("TM") - self.assertNotEqual(len(TM._threats), 0) + self.assertNotEqual(len(TM._threats), 1) with self.assertRaises(UIError): tm.threatsFile = "threats.json" diff --git a/tests/test_pytmfunc.py b/tests/test_pytmfunc.py index f94d042..dd0cbfa 100644 --- a/tests/test_pytmfunc.py +++ b/tests/test_pytmfunc.py @@ -414,6 +414,23 @@ def test_json_loads(self): [f.name for f in tm._flows], ["Request", "Insert", "Select", "Response"] ) + def test_threat_files(self): + dir_path = os.path.dirname(os.path.realpath(__file__)) + foo_file = f"{dir_path}/1.json" + bar_file = f"{dir_path}/2.json" + threat_files = [os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) + + "/pytm/threatlib/threats.json", foo_file, bar_file] + + TM.reset() + tm = TM("testing multiple threat library files", + description="aaa", + threatsFile=threat_files) + ctr = 0 + for t in TM._threats: + if t.id == "FOO" or t.id == "BAR": + ctr += 1 + self.assertTrue(ctr == 2) + def test_report(self): random.seed(0) dir_path = os.path.dirname(os.path.realpath(__file__)) From 544fa6fda55833ed161cf139e4eaaa7cff9fec43 Mon Sep 17 00:00:00 2001 From: izar tarandach Date: Thu, 20 Feb 2025 14:55:32 -0500 Subject: [PATCH 5/8] Adding support for multi threat libraries following issue #261 --- .gitignore | 1 + pytm/pytm.py | 29 +++++++++++++++++------------ sample.png | Bin 60312 -> 0 bytes tests/output.json | 2 +- tests/test_private_func.py | 6 +++++- 5 files changed, 24 insertions(+), 14 deletions(-) delete mode 100644 sample.png diff --git a/.gitignore b/.gitignore index dfbba4c..680bcf5 100644 --- a/.gitignore +++ b/.gitignore @@ -126,3 +126,4 @@ plantuml.jar tm/ /sqldump /tests/.config.pytm +.aider* diff --git a/pytm/pytm.py b/pytm/pytm.py index be067f6..149239b 100644 --- a/pytm/pytm.py +++ b/pytm/pytm.py @@ -51,6 +51,7 @@ def __init__(self, e, context): logger = logging.getLogger(__name__) +_defaultThreatsFile = os.path.dirname(__file__) + "/threatlib/threats.json" class var(object): @@ -787,8 +788,7 @@ class TM: ) name = varString("", required=True, doc="Model name") description = varString("", required=True, doc="Model description") - threatsFile = varStrings("") - threatsFileInit = False + threatsFile = varStrings([_defaultThreatsFile]) isOrdered = varBool(False, doc="Automatically order all Dataflows") mergeResponses = varBool(False, doc="Merge response edges in DFDs") ignoreUnused = varBool(False, doc="Ignore elements not used in any Dataflow") @@ -836,9 +836,9 @@ def _init_threats(self): def _add_threats(self): - for threat_file in self.threatsFile: + for tf in self.threatsFile: try: - with open(threat_file, "r", encoding="utf8") as threat_file: + with open(tf, "r", encoding="utf8") as threat_file: threats_json = json.load(threat_file) except (FileNotFoundError, PermissionError, IsADirectoryError) as e: raise UIError( @@ -1131,14 +1131,19 @@ def _process(self): # delaying loading of threats to accomodate multiple threat files in the # command line - if self.threatsFileInit == False: - tfs = [os.path.dirname(__file__) + "/threatlib/threats.json"] - if result.threat_files: - tfs.extend(result.threat_files) - self.threatsFile = tfs - self._init_threats() - self.threatsFileInit = True - + if result.threat_files: + # start by removing the default + del self.threatsFile[0] + if "default" in result.threat_files: + index = result.threat_files.index("default") + result.threat_files[index] = _defaultThreatsFile + for x in result.threat_files: + self.threatsFile.append(x) + else: + # it is just the default file, so no need to do anything + pass + self._init_threats() + if result.debug: logger.setLevel(logging.DEBUG) diff --git a/sample.png b/sample.png deleted file mode 100644 index dc7d815f824b1c4d3312547179b791e8cd4bf38a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 60312 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 e|GU`(lee Date: Thu, 20 Feb 2025 15:47:28 -0500 Subject: [PATCH 6/8] oops, these are needed for the tests --- tests/1.json | 19 +++++++++++++++++++ tests/2.json | 19 +++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 tests/1.json create mode 100644 tests/2.json diff --git a/tests/1.json b/tests/1.json new file mode 100644 index 0000000..2123e62 --- /dev/null +++ b/tests/1.json @@ -0,0 +1,19 @@ +[ + { + "SID": "FOO", + "target": [ + "Lambda", + "Process" + ], + "description": "FOOOOOOOOOOOOOO", + "details": "This attack pattern involves causing a buffer overflow through manipulation of environment variables. Once the attacker finds that they can modify an environment variable, they may try to overflow associated buffers. This attack leverages implicit trust often placed in environment variables.", + "Likelihood Of Attack": "High", + "severity": "High", + "condition": "target.usesEnvironmentVariables is True and target.controls.sanitizesInput is False and target.controls.checksInputBounds is False", + "prerequisites": "The application uses environment variables.An environment variable exposed to the user is vulnerable to a buffer overflow.The vulnerable environment variable uses untrusted data.Tainted data used in the environment variables is not properly validated. For instance boundary checking is not done before copying the input data to a buffer.", + "mitigations": "Do not expose environment variable to the user.Do not use untrusted data in your environment variables. Use a language or compiler that performs automatic bounds checking. There are tools such as Sharefuzz [R.10.3] which is an environment variable fuzzer for Unix that support loading a shared library. You can use Sharefuzz to determine if you are exposing an environment variable vulnerable to buffer overflow.", + "example": "Attack Example: Buffer Overflow in $HOME A buffer overflow in sccw allows local users to gain root access via the $HOME environmental variable. Attack Example: Buffer Overflow in TERM A buffer overflow in the rlogin program involves its consumption of the TERM environmental variable.", + "references": "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" + } +] + diff --git a/tests/2.json b/tests/2.json new file mode 100644 index 0000000..1d4cd78 --- /dev/null +++ b/tests/2.json @@ -0,0 +1,19 @@ +[ + { + "SID": "BAR", + "target": [ + "Lambda", + "Process" + ], + "description": "FOOOOOOOOOOOOOO", + "details": "This attack pattern involves causing a buffer overflow through manipulation of environment variables. Once the attacker finds that they can modify an environment variable, they may try to overflow associated buffers. This attack leverages implicit trust often placed in environment variables.", + "Likelihood Of Attack": "High", + "severity": "High", + "condition": "target.usesEnvironmentVariables is True and target.controls.sanitizesInput is False and target.controls.checksInputBounds is False", + "prerequisites": "The application uses environment variables.An environment variable exposed to the user is vulnerable to a buffer overflow.The vulnerable environment variable uses untrusted data.Tainted data used in the environment variables is not properly validated. For instance boundary checking is not done before copying the input data to a buffer.", + "mitigations": "Do not expose environment variable to the user.Do not use untrusted data in your environment variables. Use a language or compiler that performs automatic bounds checking. There are tools such as Sharefuzz [R.10.3] which is an environment variable fuzzer for Unix that support loading a shared library. You can use Sharefuzz to determine if you are exposing an environment variable vulnerable to buffer overflow.", + "example": "Attack Example: Buffer Overflow in $HOME A buffer overflow in sccw allows local users to gain root access via the $HOME environmental variable. Attack Example: Buffer Overflow in TERM A buffer overflow in the rlogin program involves its consumption of the TERM environmental variable.", + "references": "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" + } +] + From b546efb91c38f2348b153cacffb3eccbde72ecee Mon Sep 17 00:00:00 2001 From: izar tarandach Date: Fri, 21 Feb 2025 08:55:40 -0500 Subject: [PATCH 7/8] better have some documentation as well... --- README.md | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 5fbcdbf..191c1c7 100644 --- a/README.md +++ b/README.md @@ -60,10 +60,9 @@ make All available arguments: ```text -usage: tm.py [-h] [--sqldump SQLDUMP] [--debug] [--dfd] [--report REPORT] - [--exclude EXCLUDE] [--seq] [--list] [--describe DESCRIBE] - [--list-elements] [--json JSON] [--levels LEVELS [LEVELS ...]] - [--stale_days STALE_DAYS] +usage: tm.py [-h] [--sqldump SQLDUMP] [--debug] [--dfd] [--report REPORT] [--exclude EXCLUDE] [--seq] [--list] [--colormap] + [--describe DESCRIBE] [--list-elements] [--json JSON] [--levels LEVELS [LEVELS ...]] [--stale_days STALE_DAYS] + [--threat-files THREAT_FILES [THREAT_FILES ...]] optional arguments: -h, --help show this help message and exit @@ -87,10 +86,18 @@ optional arguments: checks if the delta between the TM script and the code described by it is bigger than the specified value in days + --threat-files THREAT_FILES [THREAT_FILES ...] + Files containing libraries of threats. ``` The *stale_days* argument tries to determine how far apart in days the model script (which you are writing) is from the code that implements the system being modeled. Ideally, they should be pretty close in most cases of an actively developed system. You can run this periodically to measure the pulse of your project and the 'freshness' of your threat model. +The *THREAT_FILES* argument can list proprietary threat files. The keyword 'default' stands for the pytm library when it is wanted together with the proprietary files: + + * nothing in the command line: uses the default library + * --threat-files foo.json : uses the threats in foo.json only + * --threat-files foo.json default : uses the threats in foo.json and the default ones + Currently available elements are: TM, Element, Server, ExternalEntity, Datastore, Actor, Process, SetOfProcesses, Dataflow, Boundary and Lambda. The available properties of an element can be listed by using `--describe` followed by the name of an element: From 9dc0f1f04f8dc5ac0126b7950fb91fafc49efbd4 Mon Sep 17 00:00:00 2001 From: izar Date: Fri, 21 Feb 2025 09:21:26 -0500 Subject: [PATCH 8/8] fixed wrong file in error message (thanks @raphaelahrens!) --- pytm/pytm.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pytm/pytm.py b/pytm/pytm.py index 149239b..77fa5e4 100644 --- a/pytm/pytm.py +++ b/pytm/pytm.py @@ -842,7 +842,7 @@ def _add_threats(self): threats_json = json.load(threat_file) except (FileNotFoundError, PermissionError, IsADirectoryError) as e: raise UIError( - e, f"while trying to open the the threat file ({self.threatsFile})." + e, f"while trying to open the the threat file ({tf})." ) active_threats = (threat for threat in threats_json if "DEPRECATED" not in threat)