
파이썬스러운 위협 모델링 프레임워크
전통적인 위협 모델링은 너무 늦게 도입되거나 때로는 전혀 이루어지지 않는 경우가 많습니다. 또한 수동으로 데이터 흐름과 보고서를 작성하는 것은 매우 시간이 많이 소요됩니다. 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/)가 설치되어 있다면 (리눅스 배포판에서는 기본 제공되지만 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 컨테이너 방식보다 오버헤드가 낮고 더 편리한 대안입니다.
- Linux/MacOS에 Devbox 설치: `curl -fsSL https://get.jetify.com/devbox | bash`
- [Windows/WSL](https://www.jetify.com/docs/devbox/installing-devbox/index#installing-wsl2)에 Devbox 설치
- devbox 최신 버전으로 업데이트: `devbox version update`
- `~/.config/nix/nix.conf` 파일에 GitHub 액세스 토큰 설정: `access-tokens = github.com=YOUR_TOKEN_HERE`
- 프로젝트의 `devbox.json` 파일에 지정된 모든 도구와 패키지를 포함하는 새로운 격리된 셸 환경 생성: `devbox shell`
- 터미널에서 `python`을 입력할 때 사용될 Python 실행 파일의 전체 경로를 `which python` 명령으로 표시합니다. 출력은 다음 경로여야 합니다: `.devbox/nix/profile/default/bin/python`
- 다음 명령을 실행하여 DFD(데이터 흐름 다이어그램)를 `sample.png`라는 PNG 파일로 생성하는지 테스트합니다: `./tm.py --dfd | dot -Tpng -o sample.png`
- Devbox 셸 환경 종료: `exit`
## 사용법
사용 가능한 모든 인수:```text
usage: tm.py [-h] [--debug] [--dfd] [--report REPORT]
[--exclude EXCLUDE] [--seq] [--list] [--describe DESCRIBE]
[--list-elements] [--json JSON] [--levels LEVELS [LEVELS ...]]
[--stale_days STALE_DAYS]
optional arguments:
-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
(pytm) ➜ pytm git:(master) ✗ ./tm.py --describe Element Element class attributes: OS definesConnectionTimeout default: False description handlesResources default: False implementsAuthenticationScheme default: False implementsNonce default: False inBoundary inScope Is the element in scope of the threat model, default: True isAdmin default: False isHardened default: False name required onAWS default: False
*colormap* 인수는 *dfd*와 함께 사용되며, 규칙 실행을 통해 식별된 위험 수준에 따라 요소를 빨간색, 노란색 또는 녹색으로 칠한 색상 코드 DFD를 출력합니다.
## 사용법 - Devbox 변형
- `devbox shell`
- `pytm` 사용은 평소와 동일
- `exit`
## 위협 모델 생성
다음은 사용자가 애플리케이션에 로그인하여 댓글을 게시하는 간단한 애플리케이션을 설명하는 샘플 `tm.py` 파일입니다. 앱 서버는 해당 댓글을 데이터베이스에 저장합니다. 주기적으로 데이터베이스를 정리하는 AWS Lambda가 있습니다.```python
#!/usr/bin/env python3
from pytm import TM, Server, Datastore, Dataflow, Boundary, Actor, Lambda, LLM, Data, Classification
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.isHardened = True
web.sourceCode = "server/web.cc"
db = Datastore("SQL Database (*)")
db.OS = "CentOS"
db.isHardened = False
db.inBoundary = Web_DB
db.isSql = True
db.inScope = False
db.sourceCode = "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.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 형식으로 출력됩니다.
위의 tm.py 파일에 --dfd 인수를 전달하면 표준 출력으로 출력이 생성되며, 이 출력은 Graphviz의 dot으로 전달되어 데이터 흐름 다이어그램을 생성합니다:```bash
tm.py --dfd | dot -Tpng -o sample.png
이 다이어그램을 생성합니다:
dfd.png
".levels = [1,2]" 속성을 요소에 추가하면 명령 인자 "--levels 1 2"에 따라 (두 플로우 끝이 동일한 DFD 레벨에 있는 경우 해당 요소와 관련된 데이터 흐름도 함께) 렌더링되거나 표시되지 않습니다.
다음 명령은 Sequence 다이어그램을 생성합니다.```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}}}}
}}}}}
All items inside a loop must be escaped, doubling the braces, so `{item.name}` becomes `{{item.name}}`.
The example above uses two nested loops, so items in the inner loop must be escaped twice, that's why they're using four braces.
### Overrides
You can override attributes of findings (threats matching the model assets and/or dataflows), for example to set a custom CVSS score and/or response text:```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를 반환하면 규칙이 결과를 생성하고, 그렇지 않으면 결과가 아닙니다. Condition은 `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` 속성을 검사하여 모든 수신 및 발신 Dataflow를 분석할 수 있습니다. 예를 들어, 들어오는 트래픽이 있는 서버에만 위협을 일치시키려면 `any(target.inputs)`를 사용하세요. SQL 데이터스토어에 연결되는 요소를 일치시키는 고급 예제는 `any(f.sink.oneOf(Datastore) and f.sink.isSQL 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