vex-ioc 1.1.0__tar.gz
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.
- vex_ioc-1.1.0/LICENSE.md +21 -0
- vex_ioc-1.1.0/PKG-INFO +336 -0
- vex_ioc-1.1.0/README.md +307 -0
- vex_ioc-1.1.0/pyproject.toml +48 -0
- vex_ioc-1.1.0/setup.cfg +4 -0
- vex_ioc-1.1.0/vex/__init__.py +5 -0
- vex_ioc-1.1.0/vex/__main__.py +5 -0
- vex_ioc-1.1.0/vex/async_client.py +79 -0
- vex_ioc-1.1.0/vex/banner.py +64 -0
- vex_ioc-1.1.0/vex/batch.py +196 -0
- vex_ioc-1.1.0/vex/cache.py +82 -0
- vex_ioc-1.1.0/vex/client.py +136 -0
- vex_ioc-1.1.0/vex/config.py +125 -0
- vex_ioc-1.1.0/vex/defang.py +81 -0
- vex_ioc-1.1.0/vex/enrichers/__init__.py +1 -0
- vex_ioc-1.1.0/vex/enrichers/base.py +86 -0
- vex_ioc-1.1.0/vex/enrichers/domain.py +130 -0
- vex_ioc-1.1.0/vex/enrichers/hash.py +171 -0
- vex_ioc-1.1.0/vex/enrichers/ip.py +101 -0
- vex_ioc-1.1.0/vex/enrichers/protocol.py +35 -0
- vex_ioc-1.1.0/vex/enrichers/url.py +96 -0
- vex_ioc-1.1.0/vex/ioc_detector.py +75 -0
- vex_ioc-1.1.0/vex/knowledge/__init__.py +1 -0
- vex_ioc-1.1.0/vex/knowledge/api.py +27 -0
- vex_ioc-1.1.0/vex/knowledge/db.py +132 -0
- vex_ioc-1.1.0/vex/main.py +592 -0
- vex_ioc-1.1.0/vex/mitre/__init__.py +1 -0
- vex_ioc-1.1.0/vex/mitre/mapper.py +78 -0
- vex_ioc-1.1.0/vex/mitre/mapping.py +133 -0
- vex_ioc-1.1.0/vex/models.py +202 -0
- vex_ioc-1.1.0/vex/output/__init__.py +1 -0
- vex_ioc-1.1.0/vex/output/export.py +62 -0
- vex_ioc-1.1.0/vex/output/formatter.py +431 -0
- vex_ioc-1.1.0/vex/output/stix.py +172 -0
- vex_ioc-1.1.0/vex/plugins/__init__.py +1 -0
- vex_ioc-1.1.0/vex/plugins/loader.py +42 -0
- vex_ioc-1.1.0/vex/plugins/registry.py +47 -0
- vex_ioc-1.1.0/vex/plugins/virustotal.py +59 -0
- vex_ioc-1.1.0/vex/timeline.py +131 -0
- vex_ioc-1.1.0/vex/version_check.py +93 -0
- vex_ioc-1.1.0/vex_ioc.egg-info/PKG-INFO +336 -0
- vex_ioc-1.1.0/vex_ioc.egg-info/SOURCES.txt +44 -0
- vex_ioc-1.1.0/vex_ioc.egg-info/dependency_links.txt +1 -0
- vex_ioc-1.1.0/vex_ioc.egg-info/entry_points.txt +2 -0
- vex_ioc-1.1.0/vex_ioc.egg-info/requires.txt +6 -0
- vex_ioc-1.1.0/vex_ioc.egg-info/top_level.txt +1 -0
vex_ioc-1.1.0/LICENSE.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Christian Huhn
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
vex_ioc-1.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: vex-ioc
|
|
3
|
+
Version: 1.1.0
|
|
4
|
+
Summary: VirusTotal IOC Enrichment Tool for SOC/DFIR workflows
|
|
5
|
+
Author-email: Christian Huhn <duathron@gmail.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/duathron/vex
|
|
8
|
+
Project-URL: Repository, https://github.com/duathron/vex
|
|
9
|
+
Project-URL: Bug Tracker, https://github.com/duathron/vex/issues
|
|
10
|
+
Keywords: virustotal,ioc,threat-intelligence,dfir,soc,mitre-attack,stix
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Classifier: Intended Audience :: Information Technology
|
|
14
|
+
Classifier: Topic :: Security
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
19
|
+
Requires-Python: >=3.11
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
License-File: LICENSE.md
|
|
22
|
+
Requires-Dist: httpx>=0.27.0
|
|
23
|
+
Requires-Dist: typer>=0.12.0
|
|
24
|
+
Requires-Dist: rich>=13.7.0
|
|
25
|
+
Requires-Dist: pydantic>=2.7.0
|
|
26
|
+
Requires-Dist: pyyaml>=6.0.1
|
|
27
|
+
Requires-Dist: python-dotenv>=1.0.0
|
|
28
|
+
Dynamic: license-file
|
|
29
|
+
|
|
30
|
+
<p align="center">
|
|
31
|
+
<img src="vex/vex.png" alt="vex logo" width="200"/>
|
|
32
|
+
</p>
|
|
33
|
+
|
|
34
|
+
<h1 align="center">vex</h1>
|
|
35
|
+
|
|
36
|
+
<p align="center">
|
|
37
|
+
<b>VirusTotal IOC enrichment for SOC triage and DFIR investigations, straight from your terminal.</b>
|
|
38
|
+
</p>
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
██╗ ██╗███████╗██╗ ██╗
|
|
42
|
+
██║ ██║██╔════╝╚██╗██╔╝
|
|
43
|
+
██║ ██║█████╗ ╚███╔╝
|
|
44
|
+
╚██╗ ██╔╝██╔══╝ ██╔██╗
|
|
45
|
+
╚████╔╝ ███████╗██╔╝ ██╗
|
|
46
|
+
╚═══╝ ╚══════╝╚═╝ ╚═╝
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## Features
|
|
52
|
+
|
|
53
|
+
- **Auto-detection** of IOC types: MD5, SHA1, SHA256, IPv4, IPv6, Domain, URL
|
|
54
|
+
- **Two modes**: `triage` (fast, 1 API call) and `investigate` (deep, multiple calls)
|
|
55
|
+
- **Output formats**: JSON (default), Rich tables, plain console, CSV, STIX 2.1
|
|
56
|
+
- **MITRE ATT&CK mapping** from sandbox behaviors and VT tags
|
|
57
|
+
- **IOC defanging/refanging** for safe sharing (`hxxps[://]evil[.]com`)
|
|
58
|
+
- **Automation-ready**: exit codes, `--alert` filtering, `--summary` on stderr
|
|
59
|
+
- **Timeline enrichment**: chronological event reconstruction for DFIR
|
|
60
|
+
- **Local knowledge base**: tag, annotate, and watchlist IOCs in SQLite
|
|
61
|
+
- **Plugin architecture**: extensible enrichment sources via Protocol interface
|
|
62
|
+
- **Parallel batch processing** with progress bar for large IOC lists
|
|
63
|
+
- **STIX 2.1 export** for threat intelligence sharing
|
|
64
|
+
- **SQLite cache** with configurable TTL (default 24h)
|
|
65
|
+
- **Rate limiting**: token-bucket, free tier (4 req/min) and premium configurable
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## Setup
|
|
70
|
+
|
|
71
|
+
### Prerequisites
|
|
72
|
+
|
|
73
|
+
- Python 3.11+
|
|
74
|
+
- A [VirusTotal API key](https://www.virustotal.com/gui/my-apikey) (free tier works)
|
|
75
|
+
|
|
76
|
+
### Installation
|
|
77
|
+
|
|
78
|
+
**From PyPI (recommended):**
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
pip install vex-ioc
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
**From source:**
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
git clone https://github.com/duathron/vex.git
|
|
88
|
+
cd vex
|
|
89
|
+
|
|
90
|
+
python -m venv .venv
|
|
91
|
+
source .venv/bin/activate # Windows: .venv\Scripts\activate
|
|
92
|
+
|
|
93
|
+
pip install -r requirements.txt
|
|
94
|
+
pip install -e .
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Upgrade
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
# If installed from PyPI
|
|
101
|
+
pip install --upgrade vex-ioc
|
|
102
|
+
|
|
103
|
+
# If installed from git clone (editable)
|
|
104
|
+
cd vex
|
|
105
|
+
git pull
|
|
106
|
+
pip install -r requirements.txt
|
|
107
|
+
pip install -e .
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### API Key
|
|
111
|
+
|
|
112
|
+
Set your API key using **one** of these methods (priority order):
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
# Option 1: Per-command flag (highest priority)
|
|
116
|
+
vex triage 8.8.8.8 --api-key YOUR_KEY
|
|
117
|
+
vex investigate evil.com -k YOUR_KEY
|
|
118
|
+
|
|
119
|
+
# Option 2: Environment variable
|
|
120
|
+
export VT_API_KEY="your-virustotal-api-key"
|
|
121
|
+
|
|
122
|
+
# Option 3: Save permanently to ~/.vex/config.yaml
|
|
123
|
+
vex config --set-api-key YOUR_KEY
|
|
124
|
+
|
|
125
|
+
# Option 4: Manual config.yaml or .env
|
|
126
|
+
# api:
|
|
127
|
+
# key: "your-key"
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## Quickstart
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
# Fast triage
|
|
136
|
+
vex triage 44d88612fea8a8f36de82e1278abb02f
|
|
137
|
+
|
|
138
|
+
# Rich terminal output
|
|
139
|
+
vex investigate evil-domain.com -o rich
|
|
140
|
+
|
|
141
|
+
# Batch from file, CSV export
|
|
142
|
+
vex triage -f iocs.txt --csv
|
|
143
|
+
|
|
144
|
+
# Pipe from another tool
|
|
145
|
+
echo "8.8.8.8" | vex triage -o rich
|
|
146
|
+
|
|
147
|
+
# Defanged IOC support
|
|
148
|
+
vex triage "hxxps[://]evil[.]com"
|
|
149
|
+
|
|
150
|
+
# STIX 2.1 export
|
|
151
|
+
vex investigate evil.com --stix > bundle.json
|
|
152
|
+
|
|
153
|
+
# Timeline reconstruction
|
|
154
|
+
vex investigate evil.com -o rich --timeline
|
|
155
|
+
|
|
156
|
+
# Automation: exit code + alert filter + summary
|
|
157
|
+
vex triage -f iocs.txt --alert SUSPICIOUS --summary
|
|
158
|
+
echo $? # 0=clean, 1=suspicious, 2=malicious
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## Documentation
|
|
164
|
+
|
|
165
|
+
### Subcommands
|
|
166
|
+
|
|
167
|
+
| Command | Description |
|
|
168
|
+
|---------|-------------|
|
|
169
|
+
| `vex triage <ioc>` | Fast SOC triage (1 API call) |
|
|
170
|
+
| `vex investigate <ioc>` | Deep DFIR investigation (multiple calls) |
|
|
171
|
+
| `vex config` | Manage configuration (save API key, etc.) |
|
|
172
|
+
| `vex cache-clear` | Clear the SQLite result cache |
|
|
173
|
+
| `vex version` | Show version |
|
|
174
|
+
| `vex tag <ioc>` | Manage IOC tags in local knowledge base |
|
|
175
|
+
| `vex note <ioc>` | Manage IOC notes in local knowledge base |
|
|
176
|
+
| `vex watchlist <name>` | Manage IOC watchlists |
|
|
177
|
+
|
|
178
|
+
### Triage / Investigate Options
|
|
179
|
+
|
|
180
|
+
| Flag | Description |
|
|
181
|
+
|------|-------------|
|
|
182
|
+
| `-k` / `--api-key` | VirusTotal API key (overrides env var & config) |
|
|
183
|
+
| `-q` / `--quiet` | Suppress the ASCII banner |
|
|
184
|
+
| `-o` / `--output` | Output format: `json` \| `rich` \| `console` (default: `console`) |
|
|
185
|
+
| `-f` / `--file` | File with one IOC per line |
|
|
186
|
+
| `-c` / `--config` | Custom config.yaml path |
|
|
187
|
+
| `--no-cache` | Bypass cache, force fresh lookup |
|
|
188
|
+
| `--csv` | CSV output (triage only) |
|
|
189
|
+
| `--defang` | Defang IOCs in output |
|
|
190
|
+
| `--stix` | Export as STIX 2.1 JSON bundle |
|
|
191
|
+
| `--alert <LEVEL>` | Only show results >= verdict level |
|
|
192
|
+
| `--summary` | Print verdict summary to stderr |
|
|
193
|
+
| `--timeline` | Show chronological timeline (investigate only) |
|
|
194
|
+
|
|
195
|
+
### Configuration Command
|
|
196
|
+
|
|
197
|
+
Manage vex configuration:
|
|
198
|
+
|
|
199
|
+
```bash
|
|
200
|
+
# Save API key permanently
|
|
201
|
+
vex config --set-api-key YOUR_KEY
|
|
202
|
+
|
|
203
|
+
# Show usage
|
|
204
|
+
vex config
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
Saved config is stored at `~/.vex/config.yaml` with restricted permissions (0o600).
|
|
208
|
+
|
|
209
|
+
### IOC Types
|
|
210
|
+
|
|
211
|
+
| Type | Example |
|
|
212
|
+
|------|---------|
|
|
213
|
+
| MD5 | `44d88612fea8a8f36de82e1278abb02f` |
|
|
214
|
+
| SHA1 | `3395856ce81f2b7382dee72602f798b642f14140` |
|
|
215
|
+
| SHA256 | `275a021bbfb6489e54d471899f7db9d1663fc695...` |
|
|
216
|
+
| IPv4 | `8.8.8.8` |
|
|
217
|
+
| IPv6 | `2001:4860:4860::8888` |
|
|
218
|
+
| Domain | `example.com` |
|
|
219
|
+
| URL | `https://example.com/malware.exe` |
|
|
220
|
+
|
|
221
|
+
Defanged IOCs are automatically refanged before lookup:
|
|
222
|
+
`hxxps[://]evil[.]com` becomes `https://evil.com`.
|
|
223
|
+
|
|
224
|
+
### Verdict System
|
|
225
|
+
|
|
226
|
+
| Verdict | Condition | Exit Code |
|
|
227
|
+
|---------|-----------|-----------|
|
|
228
|
+
| **MALICIOUS** | >= 3 malicious detections | 2 |
|
|
229
|
+
| **SUSPICIOUS** | >= 1 malicious detection | 1 |
|
|
230
|
+
| **UNKNOWN** | Zero detections OR too few engines | 0 |
|
|
231
|
+
| **CLEAN** | Zero detections AND enough engines | 0 |
|
|
232
|
+
|
|
233
|
+
**Zero detections does not mean CLEAN.** If too few engines reported, the verdict is UNKNOWN.
|
|
234
|
+
|
|
235
|
+
### MITRE ATT&CK Mapping
|
|
236
|
+
|
|
237
|
+
In `investigate` mode, vex maps sandbox behaviors and VT tags to MITRE ATT&CK techniques. Mappings cover 80+ keywords across all major tactics (Execution, Persistence, Defense Evasion, etc.) and appear in Rich output and STIX exports.
|
|
238
|
+
|
|
239
|
+
### Knowledge Base
|
|
240
|
+
|
|
241
|
+
Manage local IOC metadata that persists across sessions:
|
|
242
|
+
|
|
243
|
+
```bash
|
|
244
|
+
# Tag IOCs
|
|
245
|
+
vex tag 8.8.8.8 --add dns --add google
|
|
246
|
+
vex tag 8.8.8.8 # list tags
|
|
247
|
+
|
|
248
|
+
# Add notes
|
|
249
|
+
vex note evil.com --add "Seen in phishing campaign Q4"
|
|
250
|
+
vex note evil.com # list notes
|
|
251
|
+
|
|
252
|
+
# Watchlists
|
|
253
|
+
vex watchlist priority --add 8.8.8.8 --add evil.com
|
|
254
|
+
vex watchlist priority --list
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
### Plugin Architecture
|
|
258
|
+
|
|
259
|
+
vex uses a Protocol-based plugin system. The built-in VirusTotal plugin implements `EnricherProtocol`. Third-party sources (OTX, AbuseIPDB, etc.) can be added by implementing the same protocol.
|
|
260
|
+
|
|
261
|
+
---
|
|
262
|
+
|
|
263
|
+
## Config Reference
|
|
264
|
+
|
|
265
|
+
```yaml
|
|
266
|
+
api:
|
|
267
|
+
# key: "your-key" # or set VT_API_KEY env var
|
|
268
|
+
tier: free # free | premium
|
|
269
|
+
rate_limit:
|
|
270
|
+
free:
|
|
271
|
+
requests_per_minute: 4
|
|
272
|
+
requests_per_day: 500
|
|
273
|
+
premium:
|
|
274
|
+
requests_per_minute: 1000
|
|
275
|
+
requests_per_day: 50000
|
|
276
|
+
|
|
277
|
+
thresholds:
|
|
278
|
+
malicious_min_detections: 3
|
|
279
|
+
suspicious_min_detections: 1
|
|
280
|
+
min_engines_for_clean: 10
|
|
281
|
+
|
|
282
|
+
cache:
|
|
283
|
+
enabled: true
|
|
284
|
+
ttl_hours: 24
|
|
285
|
+
# db_path: "/custom/path/cache.db" # default: ~/.vex/cache.db
|
|
286
|
+
|
|
287
|
+
output:
|
|
288
|
+
default_format: json
|
|
289
|
+
quiet: false # suppress banner (-q)
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
---
|
|
293
|
+
|
|
294
|
+
## Project Structure
|
|
295
|
+
|
|
296
|
+
```
|
|
297
|
+
vex/
|
|
298
|
+
├── __init__.py # Package version (1.1.0)
|
|
299
|
+
├── main.py # Typer CLI app with all subcommands
|
|
300
|
+
├── banner.py # ASCII art banner (ffuf-style)
|
|
301
|
+
├── client.py # Sync VT API v3 client + rate limiter
|
|
302
|
+
├── async_client.py # Async VT API client for parallel ops
|
|
303
|
+
├── config.py # Pydantic config from config.yaml
|
|
304
|
+
├── cache.py # SQLite result cache with TTL
|
|
305
|
+
├── ioc_detector.py # Regex auto-detection of IOC types
|
|
306
|
+
├── defang.py # IOC defanging/refanging
|
|
307
|
+
├── models.py # Pydantic v2 models + Verdict enum
|
|
308
|
+
├── batch.py # Parallel batch processing
|
|
309
|
+
├── timeline.py # Timeline event reconstruction
|
|
310
|
+
├── vex.png # Logo
|
|
311
|
+
├── enrichers/
|
|
312
|
+
│ ├── base.py # Shared enricher utilities
|
|
313
|
+
│ ├── protocol.py # EnricherProtocol interface
|
|
314
|
+
│ ├── hash.py # MD5/SHA1/SHA256 enrichment
|
|
315
|
+
│ ├── ip.py # IPv4/IPv6 enrichment
|
|
316
|
+
│ ├── domain.py # Domain enrichment
|
|
317
|
+
│ └── url.py # URL enrichment
|
|
318
|
+
├── plugins/
|
|
319
|
+
│ ├── registry.py # Plugin discovery & registration
|
|
320
|
+
│ ├── loader.py # Plugin loading
|
|
321
|
+
│ └── virustotal.py # Built-in VT plugin
|
|
322
|
+
├── mitre/
|
|
323
|
+
│ ├── mapping.py # VT behavior → ATT&CK technique dict
|
|
324
|
+
│ └── mapper.py # Result → ATT&CK mapping engine
|
|
325
|
+
├── knowledge/
|
|
326
|
+
│ ├── db.py # SQLite knowledge base (tags/notes/watchlists)
|
|
327
|
+
│ └── api.py # High-level knowledge base API
|
|
328
|
+
└── output/
|
|
329
|
+
├── formatter.py # Rich + console + timeline formatters
|
|
330
|
+
├── export.py # JSON + CSV export
|
|
331
|
+
└── stix.py # STIX 2.1 bundle generation
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
---
|
|
335
|
+
|
|
336
|
+
*Built by [Christian Huhn](https://github.com/duathron) — [github.com/duathron/vex](https://github.com/duathron/vex)*
|
vex_ioc-1.1.0/README.md
ADDED
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="vex/vex.png" alt="vex logo" width="200"/>
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
<h1 align="center">vex</h1>
|
|
6
|
+
|
|
7
|
+
<p align="center">
|
|
8
|
+
<b>VirusTotal IOC enrichment for SOC triage and DFIR investigations, straight from your terminal.</b>
|
|
9
|
+
</p>
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
██╗ ██╗███████╗██╗ ██╗
|
|
13
|
+
██║ ██║██╔════╝╚██╗██╔╝
|
|
14
|
+
██║ ██║█████╗ ╚███╔╝
|
|
15
|
+
╚██╗ ██╔╝██╔══╝ ██╔██╗
|
|
16
|
+
╚████╔╝ ███████╗██╔╝ ██╗
|
|
17
|
+
╚═══╝ ╚══════╝╚═╝ ╚═╝
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Features
|
|
23
|
+
|
|
24
|
+
- **Auto-detection** of IOC types: MD5, SHA1, SHA256, IPv4, IPv6, Domain, URL
|
|
25
|
+
- **Two modes**: `triage` (fast, 1 API call) and `investigate` (deep, multiple calls)
|
|
26
|
+
- **Output formats**: JSON (default), Rich tables, plain console, CSV, STIX 2.1
|
|
27
|
+
- **MITRE ATT&CK mapping** from sandbox behaviors and VT tags
|
|
28
|
+
- **IOC defanging/refanging** for safe sharing (`hxxps[://]evil[.]com`)
|
|
29
|
+
- **Automation-ready**: exit codes, `--alert` filtering, `--summary` on stderr
|
|
30
|
+
- **Timeline enrichment**: chronological event reconstruction for DFIR
|
|
31
|
+
- **Local knowledge base**: tag, annotate, and watchlist IOCs in SQLite
|
|
32
|
+
- **Plugin architecture**: extensible enrichment sources via Protocol interface
|
|
33
|
+
- **Parallel batch processing** with progress bar for large IOC lists
|
|
34
|
+
- **STIX 2.1 export** for threat intelligence sharing
|
|
35
|
+
- **SQLite cache** with configurable TTL (default 24h)
|
|
36
|
+
- **Rate limiting**: token-bucket, free tier (4 req/min) and premium configurable
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## Setup
|
|
41
|
+
|
|
42
|
+
### Prerequisites
|
|
43
|
+
|
|
44
|
+
- Python 3.11+
|
|
45
|
+
- A [VirusTotal API key](https://www.virustotal.com/gui/my-apikey) (free tier works)
|
|
46
|
+
|
|
47
|
+
### Installation
|
|
48
|
+
|
|
49
|
+
**From PyPI (recommended):**
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
pip install vex-ioc
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
**From source:**
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
git clone https://github.com/duathron/vex.git
|
|
59
|
+
cd vex
|
|
60
|
+
|
|
61
|
+
python -m venv .venv
|
|
62
|
+
source .venv/bin/activate # Windows: .venv\Scripts\activate
|
|
63
|
+
|
|
64
|
+
pip install -r requirements.txt
|
|
65
|
+
pip install -e .
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Upgrade
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
# If installed from PyPI
|
|
72
|
+
pip install --upgrade vex-ioc
|
|
73
|
+
|
|
74
|
+
# If installed from git clone (editable)
|
|
75
|
+
cd vex
|
|
76
|
+
git pull
|
|
77
|
+
pip install -r requirements.txt
|
|
78
|
+
pip install -e .
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### API Key
|
|
82
|
+
|
|
83
|
+
Set your API key using **one** of these methods (priority order):
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
# Option 1: Per-command flag (highest priority)
|
|
87
|
+
vex triage 8.8.8.8 --api-key YOUR_KEY
|
|
88
|
+
vex investigate evil.com -k YOUR_KEY
|
|
89
|
+
|
|
90
|
+
# Option 2: Environment variable
|
|
91
|
+
export VT_API_KEY="your-virustotal-api-key"
|
|
92
|
+
|
|
93
|
+
# Option 3: Save permanently to ~/.vex/config.yaml
|
|
94
|
+
vex config --set-api-key YOUR_KEY
|
|
95
|
+
|
|
96
|
+
# Option 4: Manual config.yaml or .env
|
|
97
|
+
# api:
|
|
98
|
+
# key: "your-key"
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## Quickstart
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
# Fast triage
|
|
107
|
+
vex triage 44d88612fea8a8f36de82e1278abb02f
|
|
108
|
+
|
|
109
|
+
# Rich terminal output
|
|
110
|
+
vex investigate evil-domain.com -o rich
|
|
111
|
+
|
|
112
|
+
# Batch from file, CSV export
|
|
113
|
+
vex triage -f iocs.txt --csv
|
|
114
|
+
|
|
115
|
+
# Pipe from another tool
|
|
116
|
+
echo "8.8.8.8" | vex triage -o rich
|
|
117
|
+
|
|
118
|
+
# Defanged IOC support
|
|
119
|
+
vex triage "hxxps[://]evil[.]com"
|
|
120
|
+
|
|
121
|
+
# STIX 2.1 export
|
|
122
|
+
vex investigate evil.com --stix > bundle.json
|
|
123
|
+
|
|
124
|
+
# Timeline reconstruction
|
|
125
|
+
vex investigate evil.com -o rich --timeline
|
|
126
|
+
|
|
127
|
+
# Automation: exit code + alert filter + summary
|
|
128
|
+
vex triage -f iocs.txt --alert SUSPICIOUS --summary
|
|
129
|
+
echo $? # 0=clean, 1=suspicious, 2=malicious
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
## Documentation
|
|
135
|
+
|
|
136
|
+
### Subcommands
|
|
137
|
+
|
|
138
|
+
| Command | Description |
|
|
139
|
+
|---------|-------------|
|
|
140
|
+
| `vex triage <ioc>` | Fast SOC triage (1 API call) |
|
|
141
|
+
| `vex investigate <ioc>` | Deep DFIR investigation (multiple calls) |
|
|
142
|
+
| `vex config` | Manage configuration (save API key, etc.) |
|
|
143
|
+
| `vex cache-clear` | Clear the SQLite result cache |
|
|
144
|
+
| `vex version` | Show version |
|
|
145
|
+
| `vex tag <ioc>` | Manage IOC tags in local knowledge base |
|
|
146
|
+
| `vex note <ioc>` | Manage IOC notes in local knowledge base |
|
|
147
|
+
| `vex watchlist <name>` | Manage IOC watchlists |
|
|
148
|
+
|
|
149
|
+
### Triage / Investigate Options
|
|
150
|
+
|
|
151
|
+
| Flag | Description |
|
|
152
|
+
|------|-------------|
|
|
153
|
+
| `-k` / `--api-key` | VirusTotal API key (overrides env var & config) |
|
|
154
|
+
| `-q` / `--quiet` | Suppress the ASCII banner |
|
|
155
|
+
| `-o` / `--output` | Output format: `json` \| `rich` \| `console` (default: `console`) |
|
|
156
|
+
| `-f` / `--file` | File with one IOC per line |
|
|
157
|
+
| `-c` / `--config` | Custom config.yaml path |
|
|
158
|
+
| `--no-cache` | Bypass cache, force fresh lookup |
|
|
159
|
+
| `--csv` | CSV output (triage only) |
|
|
160
|
+
| `--defang` | Defang IOCs in output |
|
|
161
|
+
| `--stix` | Export as STIX 2.1 JSON bundle |
|
|
162
|
+
| `--alert <LEVEL>` | Only show results >= verdict level |
|
|
163
|
+
| `--summary` | Print verdict summary to stderr |
|
|
164
|
+
| `--timeline` | Show chronological timeline (investigate only) |
|
|
165
|
+
|
|
166
|
+
### Configuration Command
|
|
167
|
+
|
|
168
|
+
Manage vex configuration:
|
|
169
|
+
|
|
170
|
+
```bash
|
|
171
|
+
# Save API key permanently
|
|
172
|
+
vex config --set-api-key YOUR_KEY
|
|
173
|
+
|
|
174
|
+
# Show usage
|
|
175
|
+
vex config
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
Saved config is stored at `~/.vex/config.yaml` with restricted permissions (0o600).
|
|
179
|
+
|
|
180
|
+
### IOC Types
|
|
181
|
+
|
|
182
|
+
| Type | Example |
|
|
183
|
+
|------|---------|
|
|
184
|
+
| MD5 | `44d88612fea8a8f36de82e1278abb02f` |
|
|
185
|
+
| SHA1 | `3395856ce81f2b7382dee72602f798b642f14140` |
|
|
186
|
+
| SHA256 | `275a021bbfb6489e54d471899f7db9d1663fc695...` |
|
|
187
|
+
| IPv4 | `8.8.8.8` |
|
|
188
|
+
| IPv6 | `2001:4860:4860::8888` |
|
|
189
|
+
| Domain | `example.com` |
|
|
190
|
+
| URL | `https://example.com/malware.exe` |
|
|
191
|
+
|
|
192
|
+
Defanged IOCs are automatically refanged before lookup:
|
|
193
|
+
`hxxps[://]evil[.]com` becomes `https://evil.com`.
|
|
194
|
+
|
|
195
|
+
### Verdict System
|
|
196
|
+
|
|
197
|
+
| Verdict | Condition | Exit Code |
|
|
198
|
+
|---------|-----------|-----------|
|
|
199
|
+
| **MALICIOUS** | >= 3 malicious detections | 2 |
|
|
200
|
+
| **SUSPICIOUS** | >= 1 malicious detection | 1 |
|
|
201
|
+
| **UNKNOWN** | Zero detections OR too few engines | 0 |
|
|
202
|
+
| **CLEAN** | Zero detections AND enough engines | 0 |
|
|
203
|
+
|
|
204
|
+
**Zero detections does not mean CLEAN.** If too few engines reported, the verdict is UNKNOWN.
|
|
205
|
+
|
|
206
|
+
### MITRE ATT&CK Mapping
|
|
207
|
+
|
|
208
|
+
In `investigate` mode, vex maps sandbox behaviors and VT tags to MITRE ATT&CK techniques. Mappings cover 80+ keywords across all major tactics (Execution, Persistence, Defense Evasion, etc.) and appear in Rich output and STIX exports.
|
|
209
|
+
|
|
210
|
+
### Knowledge Base
|
|
211
|
+
|
|
212
|
+
Manage local IOC metadata that persists across sessions:
|
|
213
|
+
|
|
214
|
+
```bash
|
|
215
|
+
# Tag IOCs
|
|
216
|
+
vex tag 8.8.8.8 --add dns --add google
|
|
217
|
+
vex tag 8.8.8.8 # list tags
|
|
218
|
+
|
|
219
|
+
# Add notes
|
|
220
|
+
vex note evil.com --add "Seen in phishing campaign Q4"
|
|
221
|
+
vex note evil.com # list notes
|
|
222
|
+
|
|
223
|
+
# Watchlists
|
|
224
|
+
vex watchlist priority --add 8.8.8.8 --add evil.com
|
|
225
|
+
vex watchlist priority --list
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
### Plugin Architecture
|
|
229
|
+
|
|
230
|
+
vex uses a Protocol-based plugin system. The built-in VirusTotal plugin implements `EnricherProtocol`. Third-party sources (OTX, AbuseIPDB, etc.) can be added by implementing the same protocol.
|
|
231
|
+
|
|
232
|
+
---
|
|
233
|
+
|
|
234
|
+
## Config Reference
|
|
235
|
+
|
|
236
|
+
```yaml
|
|
237
|
+
api:
|
|
238
|
+
# key: "your-key" # or set VT_API_KEY env var
|
|
239
|
+
tier: free # free | premium
|
|
240
|
+
rate_limit:
|
|
241
|
+
free:
|
|
242
|
+
requests_per_minute: 4
|
|
243
|
+
requests_per_day: 500
|
|
244
|
+
premium:
|
|
245
|
+
requests_per_minute: 1000
|
|
246
|
+
requests_per_day: 50000
|
|
247
|
+
|
|
248
|
+
thresholds:
|
|
249
|
+
malicious_min_detections: 3
|
|
250
|
+
suspicious_min_detections: 1
|
|
251
|
+
min_engines_for_clean: 10
|
|
252
|
+
|
|
253
|
+
cache:
|
|
254
|
+
enabled: true
|
|
255
|
+
ttl_hours: 24
|
|
256
|
+
# db_path: "/custom/path/cache.db" # default: ~/.vex/cache.db
|
|
257
|
+
|
|
258
|
+
output:
|
|
259
|
+
default_format: json
|
|
260
|
+
quiet: false # suppress banner (-q)
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
---
|
|
264
|
+
|
|
265
|
+
## Project Structure
|
|
266
|
+
|
|
267
|
+
```
|
|
268
|
+
vex/
|
|
269
|
+
├── __init__.py # Package version (1.1.0)
|
|
270
|
+
├── main.py # Typer CLI app with all subcommands
|
|
271
|
+
├── banner.py # ASCII art banner (ffuf-style)
|
|
272
|
+
├── client.py # Sync VT API v3 client + rate limiter
|
|
273
|
+
├── async_client.py # Async VT API client for parallel ops
|
|
274
|
+
├── config.py # Pydantic config from config.yaml
|
|
275
|
+
├── cache.py # SQLite result cache with TTL
|
|
276
|
+
├── ioc_detector.py # Regex auto-detection of IOC types
|
|
277
|
+
├── defang.py # IOC defanging/refanging
|
|
278
|
+
├── models.py # Pydantic v2 models + Verdict enum
|
|
279
|
+
├── batch.py # Parallel batch processing
|
|
280
|
+
├── timeline.py # Timeline event reconstruction
|
|
281
|
+
├── vex.png # Logo
|
|
282
|
+
├── enrichers/
|
|
283
|
+
│ ├── base.py # Shared enricher utilities
|
|
284
|
+
│ ├── protocol.py # EnricherProtocol interface
|
|
285
|
+
│ ├── hash.py # MD5/SHA1/SHA256 enrichment
|
|
286
|
+
│ ├── ip.py # IPv4/IPv6 enrichment
|
|
287
|
+
│ ├── domain.py # Domain enrichment
|
|
288
|
+
│ └── url.py # URL enrichment
|
|
289
|
+
├── plugins/
|
|
290
|
+
│ ├── registry.py # Plugin discovery & registration
|
|
291
|
+
│ ├── loader.py # Plugin loading
|
|
292
|
+
│ └── virustotal.py # Built-in VT plugin
|
|
293
|
+
├── mitre/
|
|
294
|
+
│ ├── mapping.py # VT behavior → ATT&CK technique dict
|
|
295
|
+
│ └── mapper.py # Result → ATT&CK mapping engine
|
|
296
|
+
├── knowledge/
|
|
297
|
+
│ ├── db.py # SQLite knowledge base (tags/notes/watchlists)
|
|
298
|
+
│ └── api.py # High-level knowledge base API
|
|
299
|
+
└── output/
|
|
300
|
+
├── formatter.py # Rich + console + timeline formatters
|
|
301
|
+
├── export.py # JSON + CSV export
|
|
302
|
+
└── stix.py # STIX 2.1 bundle generation
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
---
|
|
306
|
+
|
|
307
|
+
*Built by [Christian Huhn](https://github.com/duathron) — [github.com/duathron/vex](https://github.com/duathron/vex)*
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68.0", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "vex-ioc"
|
|
7
|
+
version = "1.1.0"
|
|
8
|
+
description = "VirusTotal IOC Enrichment Tool for SOC/DFIR workflows"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
requires-python = ">=3.11"
|
|
12
|
+
authors = [
|
|
13
|
+
{ name = "Christian Huhn", email = "duathron@gmail.com" },
|
|
14
|
+
]
|
|
15
|
+
keywords = ["virustotal", "ioc", "threat-intelligence", "dfir", "soc", "mitre-attack", "stix"]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Development Status :: 4 - Beta",
|
|
18
|
+
"Environment :: Console",
|
|
19
|
+
"Intended Audience :: Information Technology",
|
|
20
|
+
"Topic :: Security",
|
|
21
|
+
"Programming Language :: Python :: 3.11",
|
|
22
|
+
"Programming Language :: Python :: 3.12",
|
|
23
|
+
"Programming Language :: Python :: 3.13",
|
|
24
|
+
"Programming Language :: Python :: 3.14",
|
|
25
|
+
]
|
|
26
|
+
dependencies = [
|
|
27
|
+
"httpx>=0.27.0",
|
|
28
|
+
"typer>=0.12.0",
|
|
29
|
+
"rich>=13.7.0",
|
|
30
|
+
"pydantic>=2.7.0",
|
|
31
|
+
"pyyaml>=6.0.1",
|
|
32
|
+
"python-dotenv>=1.0.0",
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
[project.scripts]
|
|
36
|
+
vex = "vex.main:main"
|
|
37
|
+
|
|
38
|
+
[project.entry-points."vex.plugins"]
|
|
39
|
+
# Third-party plugins register here. Example:
|
|
40
|
+
# my-plugin = "my_package.plugin:MyPlugin"
|
|
41
|
+
|
|
42
|
+
[project.urls]
|
|
43
|
+
Homepage = "https://github.com/duathron/vex"
|
|
44
|
+
Repository = "https://github.com/duathron/vex"
|
|
45
|
+
"Bug Tracker" = "https://github.com/duathron/vex/issues"
|
|
46
|
+
|
|
47
|
+
[tool.setuptools.packages.find]
|
|
48
|
+
include = ["vex*"]
|