rtexit-method 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/RTEXIT.md +127 -0
- package/_rtexit/config.toml +103 -0
- package/_rtexit/config.user.toml +28 -0
- package/_rtexit/custom/config.toml +12 -0
- package/_rtexit/scripts/autodoc_engine.py +203 -0
- package/_rtexit/scripts/finding_tracker.py +251 -0
- package/_rtexit/scripts/resolve_config.py +127 -0
- package/_rtexit/scripts/resolve_customization.py +154 -0
- package/package.json +53 -0
- package/resources/certifications.md +21 -0
- package/resources/payloads.md +21 -0
- package/resources/tools.md +53 -0
- package/resources/wordlists.md +15 -0
- package/templates/attack-chain-template.md +33 -0
- package/templates/executive-report-template.md +64 -0
- package/templates/executive-report.md +27 -0
- package/templates/finding-template.md +74 -0
- package/templates/remediation-roadmap.md +31 -0
- package/templates/sead-template.md +73 -0
- package/templates/technical-report.md +63 -0
- package/tools/installer/commands/install.js +40 -0
- package/tools/installer/lib/asset-manifest.js +11 -0
- package/tools/installer/lib/banner.js +12 -0
- package/tools/installer/lib/config-template.js +29 -0
- package/tools/installer/lib/copy-assets.js +39 -0
- package/tools/installer/lib/paths.js +11 -0
- package/tools/installer/lib/prompts.js +43 -0
- package/tools/installer/lib/write-config.js +32 -0
- package/tools/installer/rt-cli.js +20 -0
package/RTEXIT.md
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# RTExit — Red Team Exit Framework
|
|
2
|
+
|
|
3
|
+
> AI-Assisted Red Team Methodology — From Beginner to Expert
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## What is RTExit?
|
|
8
|
+
|
|
9
|
+
RTExit is a complete, AI-assisted Red Team methodology framework built on the same architecture as BMAD-METHOD. It provides structured **Agents**, **Skills**, and **Attack Scenarios** for every phase of a Red Team engagement — from pre-engagement planning to final report delivery.
|
|
10
|
+
|
|
11
|
+
**Covers:**
|
|
12
|
+
- 🌐 Web Applications (OWASP WSTG full)
|
|
13
|
+
- 📱 Mobile — Android & iOS (OWASP MASVS full)
|
|
14
|
+
- 💻 Desktop — Electron, Windows (.NET/Win32), macOS
|
|
15
|
+
- 🔌 Network & Infrastructure
|
|
16
|
+
- 🏢 Active Directory / Windows AD
|
|
17
|
+
- ☁️ Cloud — AWS, Azure, GCP
|
|
18
|
+
- 🎭 Social Engineering & Phishing
|
|
19
|
+
- 🔒 Physical Security
|
|
20
|
+
- 📡 IoT / Firmware / SCADA
|
|
21
|
+
- 🗄️ Databases — MySQL, PostgreSQL, MSSQL, MongoDB, Redis, Firebase
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Quick Start
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
npx rtexit-method install
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Website: `https://www.exitcode.me/`
|
|
32
|
+
Repository: `https://github.com/exit-code-eg/RTExit`
|
|
33
|
+
|
|
34
|
+
The installer will:
|
|
35
|
+
|
|
36
|
+
- show the RTExit banner
|
|
37
|
+
- ask for language and skill-level choices
|
|
38
|
+
- install RTExit assets only
|
|
39
|
+
- create or update `_rtexit/config.user.toml`
|
|
40
|
+
|
|
41
|
+
Then:
|
|
42
|
+
|
|
43
|
+
1. Open `_rtexit/config.user.toml`
|
|
44
|
+
2. Complete your operator and engagement details
|
|
45
|
+
3. Open your AI IDE in the project
|
|
46
|
+
4. Start with `rt-help`
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## The 7 Agents
|
|
51
|
+
|
|
52
|
+
| Agent | Name | Icon | Domain |
|
|
53
|
+
|-------|------|------|--------|
|
|
54
|
+
| Commander | Ahmed | 🎯 | Strategy, Scope, Planning |
|
|
55
|
+
| Scout | Nour | 🔭 | Reconnaissance & OSINT |
|
|
56
|
+
| Breaker | Karim | 💀 | Web, API, Languages, Databases |
|
|
57
|
+
| Navigator | Rami | 📱 | Mobile, Desktop, IoT |
|
|
58
|
+
| Ghost | Sara | 👻 | Post-Exploitation, AD, Cloud |
|
|
59
|
+
| Phantom | Omar | 🎭 | Social Engineering, Physical |
|
|
60
|
+
| Scribe | Layla | 📝 | Reporting, Evidence, Auto-Docs |
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## The 4 Phases
|
|
65
|
+
|
|
66
|
+
```
|
|
67
|
+
Phase 1: PLANNING → Scope, SEAD, Threat Model, Methodology
|
|
68
|
+
Phase 2: RECONNAISSANCE → OSINT, Subdomains, Attack Surface
|
|
69
|
+
Phase 3: EXPLOITATION → Web, Mobile, Network, Cloud, Social, Post-Exploitation
|
|
70
|
+
Phase 4: REPORTING → Findings, CVSS, MITRE, Reports, Remediation
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## Skill Levels
|
|
76
|
+
|
|
77
|
+
Every skill supports 4 levels:
|
|
78
|
+
- **BEGINNER** — Step-by-step with explanations, safe tools
|
|
79
|
+
- **INTERMEDIATE** — Methodology focus, standard tools
|
|
80
|
+
- **ADVANCED** — OPSEC-aware, stealth techniques
|
|
81
|
+
- **EXPERT** — Custom exploitation, vulnerability research
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## Engagement Output Structure
|
|
86
|
+
|
|
87
|
+
All documentation is auto-generated in `_rtexit-output/docs/`:
|
|
88
|
+
|
|
89
|
+
```
|
|
90
|
+
docs/
|
|
91
|
+
├── engagement/ → SEAD, scope, timeline, contacts
|
|
92
|
+
├── reconnaissance/→ subdomains, attack-surface, employees
|
|
93
|
+
├── findings/ → findings-master.csv + individual F-XXX.md files
|
|
94
|
+
├── evidence/ → screenshots, terminal-logs, chain-of-custody
|
|
95
|
+
├── attack-chains/ → multi-step paths, MITRE map
|
|
96
|
+
└── reports/ → executive + technical + remediation
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## Frameworks Supported
|
|
102
|
+
|
|
103
|
+
| Framework | Domain |
|
|
104
|
+
|-----------|--------|
|
|
105
|
+
| PTES | General purpose (7 phases) |
|
|
106
|
+
| NIST SP 800-115 | Compliance-driven |
|
|
107
|
+
| OWASP WSTG | Web applications |
|
|
108
|
+
| OWASP MASVS | Mobile applications |
|
|
109
|
+
| TIBER-EU | Financial institutions |
|
|
110
|
+
| CBEST | UK financial sector |
|
|
111
|
+
| MITRE ATT&CK | Adversary behavior mapping |
|
|
112
|
+
| Cyber Kill Chain | Attack phase mapping |
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## Resources
|
|
117
|
+
|
|
118
|
+
- PayloadsAllTheThings: github.com/swisskyrepo/PayloadsAllTheThings
|
|
119
|
+
- HackTricks: hacktricks.wiki
|
|
120
|
+
- SecLists: github.com/danielmiessler/SecLists
|
|
121
|
+
- OWASP WSTG: owasp.org/www-project-web-security-testing-guide
|
|
122
|
+
- MITRE ATT&CK: attack.mitre.org
|
|
123
|
+
- CVSS 4.0: first.org/cvss/v4-0
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
*RTExit — Red Team Methodology Framework | 2026*
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# RTExit Base Configuration
|
|
2
|
+
# This file is the base config. Override in config.user.toml or custom/config.toml
|
|
3
|
+
# DO NOT edit this file directly — use the override files
|
|
4
|
+
|
|
5
|
+
[core]
|
|
6
|
+
operator_name = ""
|
|
7
|
+
operator_email = ""
|
|
8
|
+
company = ""
|
|
9
|
+
project_name = "{dir-name}"
|
|
10
|
+
output_folder = "{project-root}/_rtexit-output"
|
|
11
|
+
language = "en" # en / ar — interface language
|
|
12
|
+
document_output_language = "en" # en / ar — report language
|
|
13
|
+
skill_level = "intermediate" # beginner / intermediate / advanced / expert
|
|
14
|
+
|
|
15
|
+
[engagement]
|
|
16
|
+
ref = "" # e.g. CLIENT-RT-WEB-2026-001
|
|
17
|
+
client_name = ""
|
|
18
|
+
start_date = ""
|
|
19
|
+
end_date = ""
|
|
20
|
+
scope_type = "blackbox" # blackbox / greybox / whitebox
|
|
21
|
+
methodology = "ptes" # ptes / nist / owasp / tiber / cbest
|
|
22
|
+
primary_domain = "web" # web / mobile / network / cloud / ad / all
|
|
23
|
+
|
|
24
|
+
[tools]
|
|
25
|
+
nmap = "nmap"
|
|
26
|
+
sqlmap = "sqlmap"
|
|
27
|
+
nuclei = "nuclei"
|
|
28
|
+
ffuf = "ffuf"
|
|
29
|
+
amass = "amass"
|
|
30
|
+
subfinder = "subfinder"
|
|
31
|
+
gobuster = "gobuster"
|
|
32
|
+
nikto = "nikto"
|
|
33
|
+
masscan = "masscan"
|
|
34
|
+
hydra = "hydra"
|
|
35
|
+
hashcat = "hashcat"
|
|
36
|
+
metasploit = "msfconsole"
|
|
37
|
+
python = "python3"
|
|
38
|
+
burp = "burpsuite"
|
|
39
|
+
adb = "adb"
|
|
40
|
+
apktool = "apktool"
|
|
41
|
+
frida = "frida"
|
|
42
|
+
|
|
43
|
+
[wordlists]
|
|
44
|
+
subdomains = "/opt/SecLists/Discovery/DNS/subdomains-top1million-5000.txt"
|
|
45
|
+
web_dirs = "/opt/SecLists/Discovery/Web-Content/directory-list-2.3-medium.txt"
|
|
46
|
+
passwords = "/opt/SecLists/Passwords/Leaked-Databases/rockyou.txt"
|
|
47
|
+
usernames = "/opt/SecLists/Usernames/Names/names.txt"
|
|
48
|
+
api_endpoints = "/opt/SecLists/Discovery/Web-Content/api/api-endpoints.txt"
|
|
49
|
+
xss_payloads = "/opt/SecLists/Fuzzing/XSS/XSS-Jhaddix.txt"
|
|
50
|
+
|
|
51
|
+
# Agent roster
|
|
52
|
+
[agents]
|
|
53
|
+
|
|
54
|
+
[agents.commander]
|
|
55
|
+
name = "Ahmed"
|
|
56
|
+
title = "Red Team Commander"
|
|
57
|
+
icon = "🎯"
|
|
58
|
+
module = "1-planning"
|
|
59
|
+
|
|
60
|
+
[agents.scout]
|
|
61
|
+
name = "Nour"
|
|
62
|
+
title = "Reconnaissance Specialist"
|
|
63
|
+
icon = "🔭"
|
|
64
|
+
module = "2-reconnaissance"
|
|
65
|
+
|
|
66
|
+
[agents.breaker]
|
|
67
|
+
name = "Karim"
|
|
68
|
+
title = "Vulnerability Analyst"
|
|
69
|
+
icon = "💀"
|
|
70
|
+
module = "3-exploitation/web"
|
|
71
|
+
|
|
72
|
+
[agents.navigator]
|
|
73
|
+
name = "Rami"
|
|
74
|
+
title = "Mobile & Desktop Specialist"
|
|
75
|
+
icon = "📱"
|
|
76
|
+
module = "3-exploitation/mobile"
|
|
77
|
+
|
|
78
|
+
[agents.ghost]
|
|
79
|
+
name = "Sara"
|
|
80
|
+
title = "Post-Exploitation Specialist"
|
|
81
|
+
icon = "👻"
|
|
82
|
+
module = "3-exploitation/post"
|
|
83
|
+
|
|
84
|
+
[agents.phantom]
|
|
85
|
+
name = "Omar"
|
|
86
|
+
title = "Social Engineering Specialist"
|
|
87
|
+
icon = "🎭"
|
|
88
|
+
module = "3-exploitation/social"
|
|
89
|
+
|
|
90
|
+
[agents.scribe]
|
|
91
|
+
name = "Layla"
|
|
92
|
+
title = "Report Writer & Evidence Specialist"
|
|
93
|
+
icon = "📝"
|
|
94
|
+
module = "4-reporting"
|
|
95
|
+
|
|
96
|
+
# Compliance mapping targets
|
|
97
|
+
[compliance]
|
|
98
|
+
pci_dss = true
|
|
99
|
+
gdpr = true
|
|
100
|
+
iso27001 = true
|
|
101
|
+
hipaa = false
|
|
102
|
+
soc2 = false
|
|
103
|
+
nist_csf = true
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# RTExit User Configuration — Override base config here
|
|
2
|
+
# This file is gitignored — personal settings only
|
|
3
|
+
|
|
4
|
+
[core]
|
|
5
|
+
operator_name = "" # Your name
|
|
6
|
+
operator_email = "" # Your email
|
|
7
|
+
company = "" # Your company name
|
|
8
|
+
skill_level = "" # beginner / intermediate / advanced / expert
|
|
9
|
+
|
|
10
|
+
[engagement]
|
|
11
|
+
ref = "" # Current engagement reference number
|
|
12
|
+
client_name = "" # Current client name
|
|
13
|
+
start_date = "" # YYYY-MM-DD
|
|
14
|
+
end_date = "" # YYYY-MM-DD
|
|
15
|
+
scope_type = "" # blackbox / greybox / whitebox
|
|
16
|
+
methodology = "" # ptes / nist / owasp / tiber / cbest
|
|
17
|
+
primary_domain = "" # web / mobile / network / cloud / ad / all
|
|
18
|
+
|
|
19
|
+
[tools]
|
|
20
|
+
# Override tool paths if not in system PATH
|
|
21
|
+
# nmap = "/usr/bin/nmap"
|
|
22
|
+
# sqlmap = "/opt/sqlmap/sqlmap.py"
|
|
23
|
+
# burp = "/opt/BurpSuitePro/burpsuite_pro.jar"
|
|
24
|
+
|
|
25
|
+
[wordlists]
|
|
26
|
+
# Override wordlist paths for your system
|
|
27
|
+
# subdomains = "/home/user/wordlists/subdomains.txt"
|
|
28
|
+
# passwords = "/home/user/wordlists/rockyou.txt"
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# RTExit team-level overrides.
|
|
2
|
+
# Commit shared engagement defaults here; keep personal values in config.user.toml.
|
|
3
|
+
|
|
4
|
+
[core]
|
|
5
|
+
language = ""
|
|
6
|
+
document_output_language = ""
|
|
7
|
+
skill_level = ""
|
|
8
|
+
|
|
9
|
+
[engagement]
|
|
10
|
+
methodology = ""
|
|
11
|
+
primary_domain = ""
|
|
12
|
+
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
RTExit Auto-Documentation Engine
|
|
4
|
+
Automatically logs all activities, commands, and findings.
|
|
5
|
+
Usage:
|
|
6
|
+
python3 autodoc_engine.py log --skill rt-osint --cmd "amass enum -d target.com" --output "..."
|
|
7
|
+
python3 autodoc_engine.py timeline
|
|
8
|
+
python3 autodoc_engine.py custody --finding F-001 --evidence "screenshot.png"
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
import argparse
|
|
12
|
+
import datetime
|
|
13
|
+
import hashlib
|
|
14
|
+
import json
|
|
15
|
+
import os
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
OUTPUT_DIR = os.environ.get('RTEXIT_OUTPUT', '_rtexit-output')
|
|
19
|
+
DOCS_DIR = os.path.join(OUTPUT_DIR, 'docs')
|
|
20
|
+
TIMELINE_FILE = os.path.join(DOCS_DIR, 'engagement', 'timeline.md')
|
|
21
|
+
CUSTODY_FILE = os.path.join(DOCS_DIR, 'evidence', 'chain-of-custody.md')
|
|
22
|
+
TERMINAL_LOG_DIR = os.path.join(DOCS_DIR, 'evidence', 'terminal-logs')
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def ensure_dirs():
|
|
26
|
+
for d in [
|
|
27
|
+
os.path.join(DOCS_DIR, 'engagement'),
|
|
28
|
+
os.path.join(DOCS_DIR, 'reconnaissance'),
|
|
29
|
+
os.path.join(DOCS_DIR, 'findings'),
|
|
30
|
+
os.path.join(DOCS_DIR, 'evidence', 'screenshots'),
|
|
31
|
+
os.path.join(DOCS_DIR, 'evidence', 'terminal-logs'),
|
|
32
|
+
os.path.join(DOCS_DIR, 'evidence', 'http-logs'),
|
|
33
|
+
os.path.join(DOCS_DIR, 'attack-chains'),
|
|
34
|
+
os.path.join(DOCS_DIR, 'reports'),
|
|
35
|
+
]:
|
|
36
|
+
os.makedirs(d, exist_ok=True)
|
|
37
|
+
|
|
38
|
+
# Initialize timeline if not exists
|
|
39
|
+
if not os.path.exists(TIMELINE_FILE):
|
|
40
|
+
with open(TIMELINE_FILE, 'w', encoding='utf-8') as f:
|
|
41
|
+
f.write("# Engagement Timeline\n\n")
|
|
42
|
+
f.write("| Timestamp | Phase | Skill | Activity | Finding |\n")
|
|
43
|
+
f.write("|-----------|-------|-------|----------|---------|\n")
|
|
44
|
+
|
|
45
|
+
# Initialize custody log if not exists
|
|
46
|
+
if not os.path.exists(CUSTODY_FILE):
|
|
47
|
+
with open(CUSTODY_FILE, 'w', encoding='utf-8') as f:
|
|
48
|
+
f.write("# Chain of Custody Log\n\n")
|
|
49
|
+
f.write("| Timestamp | Finding | Evidence | SHA-256 Hash | Operator |\n")
|
|
50
|
+
f.write("|-----------|---------|----------|--------------|----------|\n")
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def sha256_file(path: str) -> str:
|
|
54
|
+
if not os.path.exists(path):
|
|
55
|
+
return "file-not-found"
|
|
56
|
+
h = hashlib.sha256()
|
|
57
|
+
with open(path, 'rb') as f:
|
|
58
|
+
for chunk in iter(lambda: f.read(8192), b''):
|
|
59
|
+
h.update(chunk)
|
|
60
|
+
return h.hexdigest()
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def sha256_str(s: str) -> str:
|
|
64
|
+
return hashlib.sha256(s.encode()).hexdigest()
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def cmd_log(args):
|
|
68
|
+
ensure_dirs()
|
|
69
|
+
ts = datetime.datetime.now().isoformat(timespec='seconds')
|
|
70
|
+
date_str = datetime.date.today().strftime('%Y%m%d')
|
|
71
|
+
|
|
72
|
+
# Log to timeline
|
|
73
|
+
finding_ref = args.finding or '-'
|
|
74
|
+
activity = args.cmd[:80] if args.cmd else args.note or 'activity'
|
|
75
|
+
with open(TIMELINE_FILE, 'a', encoding='utf-8') as f:
|
|
76
|
+
f.write(f"| {ts} | {args.phase or '-'} | {args.skill or '-'} | `{activity}` | {finding_ref} |\n")
|
|
77
|
+
|
|
78
|
+
# Save terminal log
|
|
79
|
+
if args.cmd:
|
|
80
|
+
log_filename = f"{date_str}_{args.skill or 'unknown'}_{ts.replace(':', '-')}.txt"
|
|
81
|
+
log_path = os.path.join(TERMINAL_LOG_DIR, log_filename)
|
|
82
|
+
with open(log_path, 'w', encoding='utf-8') as f:
|
|
83
|
+
f.write(f"# Terminal Log\n")
|
|
84
|
+
f.write(f"Timestamp : {ts}\n")
|
|
85
|
+
f.write(f"Skill : {args.skill or 'unknown'}\n")
|
|
86
|
+
f.write(f"Phase : {args.phase or 'unknown'}\n")
|
|
87
|
+
f.write(f"Command : {args.cmd}\n")
|
|
88
|
+
f.write(f"Finding : {finding_ref}\n\n")
|
|
89
|
+
f.write("## Output\n```\n")
|
|
90
|
+
f.write(args.output or '(no output captured)')
|
|
91
|
+
f.write("\n```\n")
|
|
92
|
+
|
|
93
|
+
# Chain of custody
|
|
94
|
+
evidence_hash = sha256_str(args.output or '')
|
|
95
|
+
with open(CUSTODY_FILE, 'a', encoding='utf-8') as f:
|
|
96
|
+
f.write(f"| {ts} | {finding_ref} | {log_filename} | `{evidence_hash[:16]}...` | {args.operator or '-'} |\n")
|
|
97
|
+
|
|
98
|
+
print(f"✅ Logged: {log_filename}")
|
|
99
|
+
else:
|
|
100
|
+
print(f"✅ Timeline entry added: {ts}")
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def cmd_timeline(args):
|
|
104
|
+
ensure_dirs()
|
|
105
|
+
if os.path.exists(TIMELINE_FILE):
|
|
106
|
+
print(open(TIMELINE_FILE).read())
|
|
107
|
+
else:
|
|
108
|
+
print("No timeline yet.")
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def cmd_custody(args):
|
|
112
|
+
ensure_dirs()
|
|
113
|
+
|
|
114
|
+
if args.evidence and os.path.exists(args.evidence):
|
|
115
|
+
evidence_hash = sha256_file(args.evidence)
|
|
116
|
+
evidence_name = os.path.basename(args.evidence)
|
|
117
|
+
else:
|
|
118
|
+
evidence_hash = sha256_str(args.evidence or '')
|
|
119
|
+
evidence_name = args.evidence or 'unknown'
|
|
120
|
+
|
|
121
|
+
ts = datetime.datetime.now().isoformat(timespec='seconds')
|
|
122
|
+
with open(CUSTODY_FILE, 'a', encoding='utf-8') as f:
|
|
123
|
+
f.write(f"| {ts} | {args.finding or '-'} | {evidence_name} | `{evidence_hash[:32]}` | {args.operator or '-'} |\n")
|
|
124
|
+
|
|
125
|
+
print(f"✅ Evidence logged: {evidence_name}")
|
|
126
|
+
print(f" SHA-256: {evidence_hash}")
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def cmd_init(args):
|
|
130
|
+
"""Initialize output directory for a new engagement."""
|
|
131
|
+
ensure_dirs()
|
|
132
|
+
|
|
133
|
+
# Create engagement files
|
|
134
|
+
engagement_info = {
|
|
135
|
+
'ref': args.ref or '',
|
|
136
|
+
'client': args.client or '',
|
|
137
|
+
'start': datetime.date.today().isoformat(),
|
|
138
|
+
'methodology': args.methodology or 'ptes',
|
|
139
|
+
'scope': args.scope or 'blackbox',
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
info_path = os.path.join(DOCS_DIR, 'engagement', 'engagement-info.json')
|
|
143
|
+
with open(info_path, 'w') as f:
|
|
144
|
+
json.dump(engagement_info, f, indent=2)
|
|
145
|
+
|
|
146
|
+
scope_path = os.path.join(DOCS_DIR, 'engagement', 'scope.md')
|
|
147
|
+
if not os.path.exists(scope_path):
|
|
148
|
+
with open(scope_path, 'w') as f:
|
|
149
|
+
f.write(f"# Scope — {args.ref or 'ENGAGEMENT'}\n\n")
|
|
150
|
+
f.write("## In-Scope Targets\n\n| Target | Type | Priority |\n|--------|------|----------|\n| | | |\n\n")
|
|
151
|
+
f.write("## Out-of-Scope\n\n-\n\n")
|
|
152
|
+
f.write("## Notes\n\n")
|
|
153
|
+
|
|
154
|
+
print(f"✅ Engagement initialized: {args.ref}")
|
|
155
|
+
print(f" Output directory: {os.path.abspath(OUTPUT_DIR)}")
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def main():
|
|
159
|
+
parser = argparse.ArgumentParser(description='RTExit Auto-Documentation Engine')
|
|
160
|
+
sub = parser.add_subparsers(dest='command')
|
|
161
|
+
|
|
162
|
+
# log
|
|
163
|
+
p_log = sub.add_parser('log', help='Log an activity')
|
|
164
|
+
p_log.add_argument('--skill', help='Skill name')
|
|
165
|
+
p_log.add_argument('--phase', help='Current phase')
|
|
166
|
+
p_log.add_argument('--cmd', help='Command executed')
|
|
167
|
+
p_log.add_argument('--output', help='Command output')
|
|
168
|
+
p_log.add_argument('--finding', help='Related finding ID')
|
|
169
|
+
p_log.add_argument('--operator', help='Operator name')
|
|
170
|
+
p_log.add_argument('--note', help='Free text note')
|
|
171
|
+
|
|
172
|
+
# timeline
|
|
173
|
+
sub.add_parser('timeline', help='Show engagement timeline')
|
|
174
|
+
|
|
175
|
+
# custody
|
|
176
|
+
p_cust = sub.add_parser('custody', help='Log evidence chain of custody')
|
|
177
|
+
p_cust.add_argument('--finding', required=True, help='Finding ID')
|
|
178
|
+
p_cust.add_argument('--evidence', required=True, help='Evidence file path or description')
|
|
179
|
+
p_cust.add_argument('--operator', help='Operator name')
|
|
180
|
+
|
|
181
|
+
# init
|
|
182
|
+
p_init = sub.add_parser('init', help='Initialize new engagement')
|
|
183
|
+
p_init.add_argument('--ref', help='Engagement reference')
|
|
184
|
+
p_init.add_argument('--client', help='Client name')
|
|
185
|
+
p_init.add_argument('--methodology', default='ptes')
|
|
186
|
+
p_init.add_argument('--scope', default='blackbox')
|
|
187
|
+
|
|
188
|
+
args = parser.parse_args()
|
|
189
|
+
|
|
190
|
+
if args.command == 'log':
|
|
191
|
+
cmd_log(args)
|
|
192
|
+
elif args.command == 'timeline':
|
|
193
|
+
cmd_timeline(args)
|
|
194
|
+
elif args.command == 'custody':
|
|
195
|
+
cmd_custody(args)
|
|
196
|
+
elif args.command == 'init':
|
|
197
|
+
cmd_init(args)
|
|
198
|
+
else:
|
|
199
|
+
parser.print_help()
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
if __name__ == '__main__':
|
|
203
|
+
main()
|