
Python-фреймворк для моделирования угроз
Традиционное моделирование угроз часто приходит слишком поздно, а иногда и вовсе не происходит. Кроме того, создание ручных потоков данных и отчетов может занимать очень много времени. Цель pytm — сместить моделирование угроз влево, сделав его более автоматизированным и ориентированным на разработчиков.
На основе вашего ввода и определения архитектурного проекта, pytm может автоматически генерировать следующие элементы:
tm.py — это пример модели. Вы можете запустить его, чтобы сгенерировать отчет и файлы изображений диаграмм, на которые он ссылается:```
mkdir -p tm
./tm.py --report docs/basic_template.md | pandoc -f markdown -t html > tm/report.html
./tm.py --dfd | dot -Tpng -o tm/dfd.png
./tm.py --seq | java -Djava.awt.headless=true -jar $PLANTUML_PATH -tpng -pipe > tm/seq.png
Также есть пример `Makefile`, который объединяет всё это в цели, которые можно легко использовать для нескольких моделей. Если у вас установлен [GNU make](https://www.gnu.org/software/make/) (доступен по умолчанию в дистрибутивах Linux, но не в OSX), просто выполните:```
make MODEL=the_name_of_your_model_minus_.py
У вас должен быть либо plantuml.jar в той же директории, что и ваша модель, либо задан PLANTUML_PATH.
Чтобы избежать установки всех зависимостей, таких как pandoc или Java, скрипт можно запустить внутри контейнера:```
export USE_DOCKER=true make image
make
### Начало работы - Вариант с Devbox
Чтобы упростить использование `pytm`, хост-зависимости можно полностью изолировать
с помощью [`Devbox`](https://github.com/jetify-com/devbox). Обычно это более
легковесная и удобная альтернатива подходу с OCI-контейнерами.
- Установите Devbox на Linux/MacOS: `curl -fsSL https://get.jetify.com/devbox | bash`
- Установите Devbox на [Windows/WSL](https://www.jetify.com/docs/devbox/installing-devbox/index#installing-wsl2)
- Обновите до последней версии devbox: `devbox version update`
- Установите токен доступа GitHub в файле `~/.config/nix/nix.conf`: `access-tokens = github.com=YOUR_TOKEN_HERE`
- Создайте новую изолированную среду оболочки, включающую все инструменты и пакеты, указанные в файле `devbox.json` проекта: `devbox shell`
- Отобразите полный путь к исполняемому файлу Python, который будет использоваться при вводе `python` в терминале, с помощью команды which python. Результат должен быть следующим путем: `.devbox/nix/profile/default/bin/python`
- Проверьте, выполнив следующую команду, которая должна сгенерировать DFD в виде PNG-файла с именем `sample.png`: `./tm.py --dfd | dot -Tpng -o sample.png`
- Выйдите из среды оболочки Devbox: `exit`
## Использование
Все доступные аргументы:```text
usage: tm.py [-h] [--debug] [--dfd] [--report REPORT] [--exclude EXCLUDE]
[--seq] [--list] [--colormap] [--describe DESCRIBE]
[--list-elements] [--json JSON] [--levels LEVELS [LEVELS ...]]
[--stale_days STALE_DAYS]
options:
-h, --help show this help message and exit
--debug print debug messages
--dfd output DFD
--report REPORT output report using the named template file (sample
template file is under docs/template.md)
--exclude EXCLUDE specify threat IDs to be ignored
--seq output sequential diagram
--list list all available threats
--colormap color the risk in the diagram
--describe DESCRIBE describe the properties available for a given element
--list-elements list all elements which can be part of a threat model
--json JSON output a JSON file
--levels LEVELS [LEVELS ...]
Select levels to be drawn in the threat model (int
separated by comma).
--stale_days STALE_DAYS
checks if the delta between the TM script and the code
described by it is bigger than the specified value in
days
Аргумент stale_days пытается определить, насколько далеко по дням скрипт модели (который вы пишете) отстоит от кода, реализующего моделируемую систему. В идеале для активно разрабатываемой системы они должны быть достаточно близки в большинстве случаев. Вы можете запускать этот параметр периодически, чтобы измерять пульс вашего проекта и «свежесть» вашей модели угроз.
В настоящее время доступны следующие элементы: TM, Element, Server, ExternalEntity, Datastore, Actor, Process, SetOfProcesses, Dataflow, Boundary, Lambda, LLM и Agent.
Доступные свойства элемента можно вывести с помощью --describe, за которым следует имя элемента:```text
$ ./tm.py --describe Server
Server class attributes:
OS Operating system
default: ''
assumptions Assumptions about the element. These optionally allow to exclude threats with the given SIDs
default factory: list
controls Security controls for this element
default factory: Controls
data pytm.Data object(s) in incoming data flows
default factory: DataSet
description Description of the element
default: ''
findings Threats that apply to this element
default factory: list
handlesResources Does this asset handle resources?
default: False
inBoundary Trust boundary this element exists in
default: None
inScope Is the element in scope of the threat model
default: True
inputs incoming Dataflows
default factory: list
is_drawn default: False
levels List of levels (0, 1, 2, ...) to be drawn in the model
default factory:
maxClassification Maximum data classification this element can handle
default: <Classification.UNKNOWN: 0>
minTLSVersion Minimum TLS version required
default: <TLSVersion.NONE: 0>
name Name of the element
required
onAWS Is this asset on AWS?
default: False
outputs outgoing Dataflows
default factory: list
overrides Overrides to findings, allowing to set a custom response, CVSS score or override other attributes
default factory: list
port Default TCP port for incoming data flows
default: -1
protocol Default network protocol for incoming data flows
default: ''
severity Severity level of threats affecting this element
default: 0
sourceFiles Location of the source code that describes this element relative to the directory of the model script
default factory: list
usesCache Does this server use cache?
default: False
usesEnvironmentVariables Does this asset use environment variables?
default: False
usesSessionTokens Does this server use session tokens?
default: False
usesVPN Does this server use VPN?
default: False
usesXMLParser Does this server use XML parser?
default: False
uuid default factory:
Аргумент *colormap*, используемый вместе с *dfd*, выводит цветную DFD, где элементы окрашены в красный, жёлтый или зелёный цвет в зависимости от уровня риска (определяемого при выполнении правил).
## Usage - Devbox Variant
- `devbox shell`
- `pytm` usage as usual
- `exit`
## Создание модели угроз
Ниже приведён пример файла `tm.py`, описывающий простое приложение, в котором пользователь входит в приложение и оставляет комментарии. Сервер приложения сохраняет эти комментарии в базу данных. Существует AWS Lambda, которая периодически очищает базу данных.```python
#!/usr/bin/env python3
from pytm import TM, Server, Datastore, Dataflow, Boundary, Actor, Lambda, LLM, Data, Classification, DatastoreType
tm = TM("my test tm")
tm.description = "another test tm"
tm.isOrdered = True
User_Web = Boundary("User/Web")
Web_DB = Boundary("Web/DB")
user = Actor("User")
user.inBoundary = User_Web
web = Server("Web Server")
web.OS = "CloudOS"
web.controls.isHardened = True
web.sourceFiles = ["server/web.cc"]
db = Datastore("SQL Database (*)")
db.OS = "CentOS"
db.controls.isHardened = False
db.inBoundary = Web_DB
db.type = DatastoreType.SQL
db.inScope = False
db.sourceFiles = ["model/schema.sql"]
comments = Data(
name="Comments",
description="Comments in HTML or Markdown",
classification=Classification.PUBLIC,
isPII=False,
isCredentials=False,
# credentialsLife=Lifetime.LONG,
isStored=True,
isSourceEncryptedAtRest=False,
isDestEncryptedAtRest=True
)
results = Data(
name="results",
description="Results of insert op",
classification=Classification.SENSITIVE,
isPII=False,
isCredentials=False,
# credentialsLife=Lifetime.LONG,
isStored=True,
isSourceEncryptedAtRest=False,
isDestEncryptedAtRest=True
)
my_lambda = Lambda("cleanDBevery6hours")
my_lambda.controls.hasAccessControl = True
my_lambda.inBoundary = Web_DB
llm_api = LLM("AI Writing Assistant")
llm_api.isThirdParty = True
llm_api.processesPersonalData = True
llm_api.hasContentFiltering = False
llm_api.hasSystemPrompt = True
llm_api.processesUntrustedInput = True
my_lambda_to_db = Dataflow(my_lambda, db, "(λ)Periodically cleans DB")
my_lambda_to_db.protocol = "SQL"
my_lambda_to_db.dstPort = 3306
user_to_web = Dataflow(user, web, "User enters comments (*)")
user_to_web.protocol = "HTTP"
user_to_web.dstPort = 80
user_to_web.data = comments
web_to_user = Dataflow(web, user, "Comments saved (*)")
web_to_user.protocol = "HTTP"
web_to_db = Dataflow(web, db, "Insert query with comments")
web_to_db.protocol = "MySQL"
web_to_db.dstPort = 3306
db_to_web = Dataflow(db, web, "Comments contents")
db_to_web.protocol = "MySQL"
db_to_web.data = results
web_to_llm = Dataflow(web, llm_api, "Chat completion request")
web_to_llm.protocol = "HTTPS"
web_to_llm.dstPort = 443
tm.process()
У вас также есть возможность использовать pytmGPT для создания моделей из прозы!
Диаграммы выводятся в форматах Dot и PlantUML.
Когда аргумент --dfd передается указанному выше файлу tm.py, он генерирует вывод в stdout, который передается в Graphviz dot для создания диаграммы потоков данных:```bash
tm.py --dfd | dot -Tpng -o sample.png
Генерирует эту диаграмму:
dfd.png
Добавление атрибутов ".levels = [1,2]" к элементу приведёт к тому, что он (и связанные с ним потоки данных, если оба конца потока находятся на одном уровне DFD) будет отображаться (или нет) в зависимости от аргумента команды "--levels 1 2".
Следующая команда генерирует диаграмму последовательности.```bash
tm.py --seq | java -Djava.awt.headless=true -jar plantuml.jar -tpng -pipe > seq.png
Создает эту диаграмму:
seq.png
Диаграммы и результаты могут быть включены в шаблон для создания итогового отчета:```bash
tm.py --report docs/basic_template.md | pandoc -f markdown -t html > report.html
Формат шаблонов, используемый в шаблоне отчета, очень прост:```text
# Threat Model Sample
***
## System Description
{tm.description}
## Dataflow Diagram

## Dataflows
Name|From|To |Data|Protocol|Port
----|----|---|----|--------|----
{dataflows:repeat:{{item.name}}|{{item.source.name}}|{{item.sink.name}}|{{item.data}}|{{item.protocol}}|{{item.dstPort}}
}
## Findings
{findings:repeat:* {{item.description}} on element "{{item.target}}"
}
Чтобы сгруппировать результаты по элементам, используйте более продвинутый, вложенный цикл:```text
{elements🔁{{item.findings:if:
{{item.findings🔁 Threat: {{{{item.id}}}} - {{{{item.description}}}}
Severity: {{{{item.severity}}}}
Mitigations: {{{{item.mitigations}}}}
References: {{{{item.references}}}}
}}}}}
Все элементы внутри цикла должны быть экранированы, с удвоением фигурных скобок, так что `{item.name}` превращается в `{{item.name}}`.
В примере выше используются два вложенных цикла, поэтому элементы во внутреннем цикле должны быть экранированы дважды, вот почему используются четыре скобки.
### Переопределения
Вы можете переопределить атрибуты находок (угроз, соответствующих активам и/или потокам данных модели), например, чтобы установить пользовательскую оценку CVSS и/или текст ответа:```python
user_to_web = Dataflow(user, web, "User enters comments (*)", protocol="HTTP", dstPort="80")
user_to_web.overrides = [
Finding(
# Overflow Buffers
threat_id="INP02",
cvss="9.3",
response="""**To Mitigate**: run a memory sanitizer to validate the binary""",
severity="Very High",
)
]
Если вы добавляете Находку (Finding), обязательно укажите уровень серьезности: «Очень высокий», «Высокий», «Средний», «Низкий», «Очень низкий».
Для практикующего специалиста по безопасности вы можете предоставить собственный файл угроз, задав TM.threatsFile. Он должен содержать записи вида:```json
{
"SID":"INP01",
"target": ["Lambda","Process"],
"description": "Buffer Overflow via Environment Variables",
"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"
}
Поле `target` перечисляет классы элементов модели, с которыми сопоставляется данная угроза. Это могут быть активы, такие как: Actor, Datastore, Server, Process, SetOfProcesses, ExternalEntity, Lambda, LLM, Agent или Element (базовый класс, который соответствует любому элементу). Также это может быть поток данных (Dataflow), соединяющий два актива.
Все остальные поля (кроме `condition`) доступны для отображения и могут использоваться в шаблоне для перечисления находок в итоговом [отчёте](#report).
> **ПРЕДУПРЕЖДЕНИЕ**
>
> Файл `threats.json` содержит строки, которые обрабатываются через `eval()`. Убедитесь, что у файла правильные права доступа, иначе злоумышленник может изменить строки и заставить вас выполнить код от его имени.
Логика находится в `condition`, где члены `target` могут быть логически оценены. Возвращение true означает, что правило генерирует находку, в противном случае находки нет. Условие может сравнивать атрибуты `target` и/или атрибуты управления `target.control`, а также вызывать один из следующих методов:
* `target.oneOf(class, ...)` где `class` — один или несколько: Actor, Datastore, Server, Process, SetOfProcesses, ExternalEntity, Lambda, LLM, Agent или Dataflow,
* `target.crosses(Boundary)`,
* `target.enters(Boundary)`,
* `target.exits(Boundary)`,
* `target.inside(Boundary)`.
Если `target` является потоком данных (Dataflow), помните, что вы можете получить доступ к `target.source` и/или `target.sink`, а также к другим атрибутам.
Условия для активов могут анализировать все входящие и исходящие потоки данных, проверяя атрибуты `target.input` и `target.output`. Например, чтобы сопоставить угрозу только с серверами, имеющими входящий трафик, используйте `any(target.inputs)`. Более продвинутый пример, соответствующий элементам, подключающимся к SQL-хранилищам данных: `any(f.sink.oneOf(Datastore) and f.sink.type == DatastoreType.SQL for f in target.outputs)`.
## Импорт из JSON
С помощью небольшого кода на Python можно импортировать модель угроз из JSON (обратите внимание на специальный формат в примере, находящемся в `tests/input.json`). Следующий пример импортирует пример `input.json`, найденный в тестах. Сохраните следующий код как `tm2.py`.```python
#!/usr/bin/env python3
# Example tm2.py contents
# Run: python tm2.py --dfd | dot -Tpng -o sample_json.png
from pytm import (
TM,
Actor,
Boundary,
Classification,
Data,
Dataflow,
Datastore,
Lambda,
Server,
DatastoreType,
Assumption,
load,
)
json_file_string = './tests/input.json'
with open(json_file_string) as input_json:
TM.reset()
tm = load(input_json)
tm.process()
Мы можем вызвать tm2.py так же, как и раньше, здесь с --dfd, а затем перенаправить вывод в Graphviz (dot):```bash
python tm2.py --dfd | dot -Tpng -o sample_json.png
## Создание слайдов!
Как только модель угроз готова, наступает пугающий этап презентации — и теперь pytm может помочь и здесь, с шаблоном, который выражает вашу модель угроз в виде слайдов, используя возможности (RevealMD)[https://github.com/webpro/reveal-md]! Просто используйте шаблон docs/revealjs.md, и вы получите красивые слайды, полностью настраиваемые, которые можно показывать и делиться ими через браузер.
https://github.com/izar/pytm/assets/368769/30218241-c7cc-4085-91e9-bbec2843f838
## Поддерживаемые в настоящее время угрозы```text
INP01 - Buffer Overflow via Environment Variables
INP02 - Overflow Buffers
INP03 - Server Side Include (SSI) Injection
CR01 - Session Sidejacking
INP04 - HTTP Request Splitting
CR02 - Cross Site Tracing
INP05 - Command Line Execution through SQL Injection
INP06 - SQL Injection through SOAP Parameter Tampering
SC01 - JSON Hijacking (aka JavaScript Hijacking)
LB01 - API Manipulation
AA01 - Authentication Abuse/ByPass
DS01 - Excavation
DE01 - Interception
DE02 - Double Encoding
API01 - Exploit Test APIs
AC01 - Privilege Abuse
INP07 - Buffer Manipulation
AC02 - Shared Data Manipulation
DO01 - Flooding
HA01 - Path Traversal
AC03 - Subverting Environment Variable Values
DO02 - Excessive Allocation
DS02 - Try All Common Switches
INP08 - Format String Injection
INP09 - LDAP Injection
INP10 - Parameter Injection
INP11 - Relative Path Traversal
INP12 - Client-side Injection-induced Buffer Overflow
AC04 - XML Schema Poisoning
DO03 - XML Ping of the Death
AC05 - Content Spoofing
INP13 - Command Delimiters
INP14 - Input Data Manipulation
DE03 - Sniffing Attacks
CR03 - Dictionary-based Password Attack
API02 - Exploit Script-Based APIs
HA02 - White Box Reverse Engineering
DS03 - Footprinting
AC06 - Using Malicious Files
HA03 - Web Application Fingerprinting
SC02 - XSS Targeting Non-Script Elements
AC07 - Exploiting Incorrectly Configured Access Control Security Levels
INP15 - IMAP/SMTP Command Injection
HA04 - Reverse Engineering
SC03 - Embedding Scripts within Scripts
INP16 - PHP Remote File Inclusion
AA02 - Principal Spoof
CR04 - Session Credential Falsification through Forging
DO04 - XML Entity Expansion
DS04 - XSS Targeting Error Pages
SC04 - XSS Using Alternate Syntax
CR05 - Encryption Brute Forcing
AC08 - Manipulate Registry Information
DS05 - Lifting Sensitive Data Embedded in Cache
SC05 - Removing Important Client Functionality
INP17 - XSS Using MIME Type Mismatch
AA03 - Exploitation of Trusted Credentials
AC09 - Functionality Misuse
INP18 - Fuzzing and observing application log data/errors for application mapping
CR06 - Communication Channel Manipulation
AC10 - Exploiting Incorrectly Configured SSL
CR07 - XML Routing Detour Attacks
AA04 - Exploiting Trust in Client
CR08 - Client-Server Protocol Manipulation
INP19 - XML External Entities Blowup
INP20 - iFrame Overlay
AC11 - Session Credential Falsification through Manipulation
INP21 - DTD Injection
INP22 - XML Attribute Blowup
INP23 - File Content Injection
DO05 - XML Nested Payloads
AC12 - Privilege Escalation
AC13 - Hijacking a privileged process
AC14 - Catching exception throw/signal from privileged block
INP24 - Filter Failure through Buffer Overflow
INP25 - Resource Injection
INP26 - Code Injection
INP27 - XSS Targeting HTML Attributes
INP28 - XSS Targeting URI Placeholders
INP29 - XSS Using Doubled Characters
INP30 - XSS Using Invalid Characters
INP31 - Command Injection
INP32 - XML Injection
INP33 - Remote Code Inclusion
INP34 - SOAP Array Overflow
INP35 - Leverage Alternate Encoding
DE04 - Audit Log Manipulation
AC15 - Schema Poisoning
INP36 - HTTP Response Smuggling
INP37 - HTTP Request Smuggling
INP38 - DOM-Based XSS
AC16 - Session Credential Falsification through Prediction
INP39 - Reflected XSS
INP40 - Stored XSS
AC17 - Session Hijacking - ServerSide
AC18 - Session Hijacking - ClientSide
INP41 - Argument Injection
AC19 - Reusing Session IDs (aka Session Replay) - ServerSide
AC20 - Reusing Session IDs (aka Session Replay) - ClientSide
AC21 - Cross Site Request Forgery
DS06 - Data Leak
DR01 - Unprotected Sensitive Data
AC22 - Credentials Aging (deprecated)
AC23 - Credentials Disclosure
AC24 - Use of hardcoded credentials
LLM01 - Direct Prompt Injection
LLM02 - Indirect Prompt Injection via Retrieved Content
LLM03 - Sensitive Data Leakage to Third-Party Provider
LLM04 - Training Data Poisoning
LLM05 - Excessive Agency via Unauthorized Tool Use
LLM06 - Arbitrary Code Execution via LLM Agent
LLM07 - Jailbreaking and Safety Bypass
LLM08 - Sensitive Information Disclosure Through Output
LLM09 - Untrusted Tool Launch Configuration