{ "info": { "author": "", "author_email": "", "bugtrack_url": null, "classifiers": [ "Development Status :: 3 - Alpha", "Environment :: Console", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python :: 3", "Topic :: Security" ], "description": "# pytm\n\nA Pythonic framework for threat modeling\n\nFor the security practitioner, add threats to the Threat object:\n\n```python\nThreats = {\n \"DF1\": {\n \"description\": \"Dataflow not authenticated\",\n \"target\": Dataflow,\n \"condition\": \"target.authenticatedWith is False\"\n },\n \"SR1\": {\n \"description\": \"Server not hardened\",\n \"target\": Server,\n \"condition\": \"target.isHardened is False\"\n }\n}\n```\n\n**CAVEAT**\n\nThe threat.py file contains strings that run through eval\\(\\) -> make sure the file has correct permissions or risk having an attacker change the strings and cause you to run code on their behalf. The logic lives in the \"condition\", where members of \"target\" can be logically evaluated. Returning a true means the rule generates a finding, otherwise, it is not a finding.**\n\n**Usage**\n\nIn order to start a threat model, the minimum amount of code is:\n\n```python\n\n# !/usr/bin/env python3\n\nfrom pytm.pytm import TM, Server, Datastore, Dataflow, Boundary, Actor\n\ntm = TM(\"my test tm\")\ntm.description = \"another test tm\"\n\ntm.process()\n\n```\nThis provides the most popular elements, as well as the command line argument processing.\n\nDefine your system in code as a collection of objects and annotate them with properties, then call out TM.process\\(\\) to identify threats and TM.report\\(\\) to write out the report. Helper operations can be chosen on the command line:\n\n```text\nusage: tm.py [-h] [--debug] [--dfd] [--report REPORT] [--exclude EXCLUDE]\n [--seq] [--list]\n\noptional arguments:\n -h, --help show this help message and exit\n --debug print debug messages\n --dfd output DFD (default)\n --report REPORT output report using the named template file\n --exclude EXCLUDE specify threat IDs to be ignored\n --seq output sequential diagram\n --list list known threats\n --describe DESCRIBE describe the contents of a given class\n\n```\n\nCurrently available elements are: Element, Server, ExternalEntity, Datastpre. Actor. Process, SetOfProcesses, Dataflow, Boundary.\nThe available properties of an element can be listed by using --describe followed by the name of an element:\n\n```text\n\n(pytm) \u279c pytm git:(master) \u2717 ./tm.py --describe Element\nElement\n\tOS\n\tcheck\n\tdefinesConnectionTimeout\n\tdescription\n\tdfd\n\thandlesResources\n\timplementsAuthenticationScheme\n\timplementsNonce\n\tinBoundary\n\tinScope\n\tisAdmin\n\tisHardened\n\tname\n\tonAWS\n\n```\n\nCurrently available elements are: TM, Element, Server, ExternalEntity, Datastore, Actor, Process, SetOfProcesses, Dataflow, Boundary.\n\nDiagrams output as [Dot](https://graphviz.gitlab.io/) and [PlantUML](https://plantuml.com/). Source files are output to stdout, Dataflow and PlantUML are not expected to be installed and do not run in lieu of the user.\n\n\n\n```python\n\n# !/usr/bin/env python3\n\nfrom pytm.pytm import TM, Server, Datastore, Dataflow, Boundary, Actor\n\ntm = TM(\"my test tm\")\ntm.description = \"another test tm\"\n\nUser_Web = Boundary(\"User/Web\")\nWeb_DB = Boundary(\"Web/DB\")\n\nuser = Actor(\"User\")\nuser.inBoundary = User_Web\n\nweb = Server(\"Web Server\")\nweb.OS = \"CloudOS\"\nweb.isHardened = True\n\ndb = Datastore(\"SQL Database (*)\")\ndb.OS = \"CentOS\"\ndb.isHardened = False\ndb.inBoundary = Web_DB\ndb.isSql = True\ndb.inScope = False\n\nmy_lambda = Lambda(\"cleanDBevery6hours\")\nmy_lambda.hasAccessControl = True\nmy_lambda.inBoundary = Web_DB\n\nmy_lambda_to_db = Dataflow(my_lambda, db, \"(λ)Periodically cleans DB\")\nmy_lambda_to_db.protocol = \"SQL\"\nmy_lambda_to_db.dstPort = 3306\n\nuser_to_web = Dataflow(user, web, \"User enters comments (*)\")\nuser_to_web.protocol = \"HTTP\"\nuser_to_web.dstPort = 80\nuser_to_web.data = 'Comments in HTML or Markdown'\nuser_to_web.order = 1\n\nweb_to_user = Dataflow(web, user, \"Comments saved (*)\")\nweb_to_user.protocol = \"HTTP\"\nweb_to_user.data = 'Ack of saving or error message, in JSON'\nweb_to_user.order = 2\n\nweb_to_db = Dataflow(web, db, \"Insert query with comments\")\nweb_to_db.protocol = \"MySQL\"\nweb_to_db.dstPort = 3306\nweb_to_db.data = 'MySQL insert statement, all literals'\nweb_to_db.order = 3\n\ndb_to_web = Dataflow(db, web, \"Comments contents\")\ndb_to_web.protocol = \"MySQL\"\ndb_to_web.data = 'Results of insert op'\ndb_to_web.order = 4\n\ntm.process()\n\n```\n\nThis input generates output to stdout, which is fed to Graphviz's dot:\n\n```bash\n\ntm.py --dfd | dot -Tpng -o sample.png\n\n```\n\nGenerates this diagram:\n\n![dfd.png](.gitbook/assets/dfd.png)\n\nDataflows can be ordered and sequence diagrams can be generated:\n\n```python\n\nuser_to_web = Dataflow(user, web, \"User enters comments (*)\")\nuser_to_web.protocol = \"HTTP\"\nuser_to_web.dstPort = 80\nuser_to_web.data = 'Comments in HTML or Markdown'\nuser_to_web.order = 1\n\n```\n\n```bash\n\ntm.py --seq | java -Djava.awt.headless=true -jar ~/bin/plantuml.jar -tpng -pipe > seq.png\n\n```\n\nGenerates this diagram:\n\n![seq.png](.gitbook/assets/seq.png)\n\nThe diagrams and findings can be included in the template to create a final report:\n\n```bash\n\ntm.py --report template.md | pandoc -f markdown -t html > report.html\n\n```\nThe templating format used in the report template is very simple:\n\n```text\n\n# Threat Model Sample\n***\n\n## System Description\n\n{tm.description}\n\n## Dataflow Diagram\n\n![Level 0 DFD](dfd.png)\n\n## Dataflows\n\nName|From|To |Data|Protocol|Port\n----|----|---|----|--------|----\n{dataflows:repeat:{{item.name}}|{{item.source.name}}|{{item.sink.name}}|{{item.data}}|{{item.protocol}}|{{item.dstPort}}\n}\n\n## Findings\n\n{findings:repeat:* {{item.description}} on element \"{{item.target}}\n}\n\n```\n\n**Currently supported threats**\n\n```text\n\nAA01 - Dataflow not authenticated\nHA01 - Server not hardened\nAU01 - Logs created: verify if sensitive data is stored\nAU02 - Potential weak protections for audit data\nAC01 - Process Memory Tampered\nAC02 - Replay Attacks\nCR01 - Collision Attacks\nAU03 - Risks from logging\nAA02 - Authenticated Data Flow Compromised\nIN01 - Potential SQL Injection Vulnerability\nIN02 - XML DTD and XSLT Processing\nIN03 - JavaScript Object Notation Processing/XSS\nIN04 - Cross Site Scripting\nAC03 - The Data Store Could Be Corrupted\nAA03 - Weakness in SSO Authorization\nAC04 - Elevation Using Impersonation\nAC05 - Elevation by Changing the Execution Flow in a process\nOT01 - Cross Site Request Forgery\nDO01 - Potential Excessive Resource Consumption\nDO02 - Potential Process Crash or Stop\nDO03 - Data Flow Is Potentially Interrupted\nDO04 - Data Store Inaccessible\nAA04 - Authorization Bypass\nDE01 - Data Flow Sniffing\nAC06 - Weak Access Control for a Resource\nDS01 - Weak Credential Storage\nDE02 - Weak Credential Transit\nAA05 - Weak Authentication Scheme\nLB01 - Lambda does not authenticate source of request\nLB02 - Lambda has no access control\nLB03 - Lambda does not handle resource consumption\n\n```\n\n\n", "description_content_type": "", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/izar/pytm", "keywords": "", "license": "MIT License", "maintainer": "", "maintainer_email": "", "name": "pytm", "package_url": "https://pypi.org/project/pytm/", "platform": "", "project_url": "https://pypi.org/project/pytm/", "project_urls": { "Homepage": "https://github.com/izar/pytm" }, "release_url": "https://pypi.org/project/pytm/0.4/", "requires_dist": null, "requires_python": ">=3", "summary": "", "version": "0.4" }, "last_serial": 4649077, "releases": { "0.3": [ { "comment_text": "", "digests": { "md5": "2cf42bcacbcb40c195bfb138ead07596", "sha256": "c183aaf1de247d21fdc2ed74df075012b8cfcf61ef9f15d1e2c28450636a22a5" }, "downloads": -1, "filename": "pytm-0.3-py3-none-any.whl", "has_sig": false, "md5_digest": "2cf42bcacbcb40c195bfb138ead07596", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3", "size": 9750, "upload_time": "2018-10-17T20:34:55", "url": "https://files.pythonhosted.org/packages/66/3b/6899bfbb604124f403c3bbc6a89b184a184741a86cd51cd892c6cba427c2/pytm-0.3-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "ba7900a28e01748bcfb144fb86aaaeb8", "sha256": "9e01396df86308134bd91fa65a7bf5df1e24bc6fd0fd292355800743623e639e" }, "downloads": -1, "filename": "pytm-0.3.tar.gz", "has_sig": false, "md5_digest": "ba7900a28e01748bcfb144fb86aaaeb8", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3", "size": 8953, "upload_time": "2018-10-17T20:34:56", "url": "https://files.pythonhosted.org/packages/14/cb/3ed2635949b3b9c3a121582690fc597d8a8bfb8c7ec44b98e049adba3a82/pytm-0.3.tar.gz" } ], "0.4": [ { "comment_text": "", "digests": { "md5": "c66fa8d25cbf9c7ecca02a5d511ce016", "sha256": "79bcc208fb7a587ad7da2fb5050fc928abb6a68e38a8518c174ffd092c6da729" }, "downloads": -1, "filename": "pytm-0.4-py3-none-any.whl", "has_sig": false, "md5_digest": "c66fa8d25cbf9c7ecca02a5d511ce016", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3", "size": 39025, "upload_time": "2018-12-31T22:18:15", "url": "https://files.pythonhosted.org/packages/6d/8d/1b96af978ec1f696a8f686e7b8c0bf811cacef4483ca69a2c98f68d2a325/pytm-0.4-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "f91ec950c753e1f0136ccec1f0fc080b", "sha256": "b91d9f24ba6521b3e23e1218a19295213d4174e1a4b0b11ba347cd56367a044b" }, "downloads": -1, "filename": "pytm-0.4.tar.gz", "has_sig": false, "md5_digest": "f91ec950c753e1f0136ccec1f0fc080b", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3", "size": 39428, "upload_time": "2018-12-31T22:18:16", "url": "https://files.pythonhosted.org/packages/88/28/45599ccd29a30ba7ad5d27c1bb0c7354536fe4578579835ef47268f860aa/pytm-0.4.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "c66fa8d25cbf9c7ecca02a5d511ce016", "sha256": "79bcc208fb7a587ad7da2fb5050fc928abb6a68e38a8518c174ffd092c6da729" }, "downloads": -1, "filename": "pytm-0.4-py3-none-any.whl", "has_sig": false, "md5_digest": "c66fa8d25cbf9c7ecca02a5d511ce016", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3", "size": 39025, "upload_time": "2018-12-31T22:18:15", "url": "https://files.pythonhosted.org/packages/6d/8d/1b96af978ec1f696a8f686e7b8c0bf811cacef4483ca69a2c98f68d2a325/pytm-0.4-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "f91ec950c753e1f0136ccec1f0fc080b", "sha256": "b91d9f24ba6521b3e23e1218a19295213d4174e1a4b0b11ba347cd56367a044b" }, "downloads": -1, "filename": "pytm-0.4.tar.gz", "has_sig": false, "md5_digest": "f91ec950c753e1f0136ccec1f0fc080b", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3", "size": 39428, "upload_time": "2018-12-31T22:18:16", "url": "https://files.pythonhosted.org/packages/88/28/45599ccd29a30ba7ad5d27c1bb0c7354536fe4578579835ef47268f860aa/pytm-0.4.tar.gz" } ] }