| 1 | # CTI Detection Automation |
| 2 | |
| 3 | Pulls indicators from live threat-intel feeds, deduplicates them, extracts the |
| 4 | MITRE ATT&CK techniques behind them, turns the result into Wazuh detection rules |
| 5 | and CDB lists, and emails an analyst for sign-off before anything goes live. No |
| 6 | rule reaches the SIEM without a human approving it. |
| 7 | |
| 8 | This is the piece that feeds the watchlists used by the |
| 9 | [SOC automation lab](../soc-automation-lab) - the `cti-malicious-ip`, |
| 10 | `cti-malicious-domain`, and `cti-malware-hash` lists that the Wazuh rules look up |
| 11 | against are generated here. |
| 12 | |
| 13 |  |
| 14 | |
| 15 | ## What it does |
| 16 | |
| 17 | - **Collects** from ThreatFox, Feodo Tracker, URLhaus, AlienVault OTX, and OpenPhish, |
| 18 | covering IPs, domains, URLs, file hashes, phishing, exploit-kit and malware-download |
| 19 | URLs, C2 infrastructure, and (optionally) leaked credentials. |
| 20 | - **Normalizes** every source into one indicator model and **deduplicates** across |
| 21 | feeds - an IP seen in both ThreatFox and Feodo becomes one indicator carrying both |
| 22 | sources, the higher confidence, and the union of techniques. |
| 23 | - **Extracts and dedups TTPs**: ATT&CK technique IDs come straight from OTX pulses and |
| 24 | are inferred from malware family and threat type for the feeds that don't carry them, |
| 25 | then collapsed into a ranked coverage list. |
| 26 | - **Generates Wazuh rules**: CDB lists per indicator type plus an XML ruleset whose |
| 27 | list-lookup rules are tagged with the dominant ATT&CK techniques for that bucket. |
| 28 | - **Gates on approval**: every run produces a candidate bundle and emails the analyst a |
| 29 | signed, time-limited review link. Rules are written to Wazuh only when the analyst |
| 30 | approves. |
| 31 | |
| 32 | ```mermaid |
| 33 | flowchart LR |
| 34 | F[ThreatFox / Feodo / URLhaus<br/>OTX / OpenPhish] --> N[normalize] |
| 35 | N --> D[deduplicate] |
| 36 | D --> C{confidence<br/>>= threshold} |
| 37 | C --> T[extract + dedup TTPs] |
| 38 | T --> G[generate CDB lists<br/>+ Wazuh rules] |
| 39 | G --> M[email analyst<br/>signed review link] |
| 40 | M -->|approve| W[promote to Wazuh] |
| 41 | M -->|reject| X[discard] |
| 42 | ``` |
| 43 | |
| 44 | ## The approval gate |
| 45 | |
| 46 | The pipeline never deploys on its own. It writes the candidate to a staging |
| 47 | directory and emails a review link. The analyst sees the diff against the last |
| 48 | approved bundle, the indicator counts, and the ATT&CK coverage, then approves or |
| 49 | rejects. |
| 50 | |
| 51 | | Review page | Bundle history | |
| 52 | |---|---| |
| 53 | |  |  | |
| 54 | |
| 55 | Short walkthrough of the flow: [docs/media/cti-approval-walkthrough.mp4](docs/media/cti-approval-walkthrough.mp4) |
| 56 | |
| 57 | The review link is an `itsdangerous` signed token with a TTL, so it can't be |
| 58 | forged or replayed after it expires. |
| 59 | |
| 60 | ## Run the demo |
| 61 | |
| 62 | No API keys needed - the demo runs against the bundled fixtures: |
| 63 | |
| 64 | ```bash |
| 65 | make install |
| 66 | make demo # generates a bundle and writes the approval email to output/emails/ |
| 67 | make serve # approval console on http://localhost:8080 |
| 68 | ``` |
| 69 | |
| 70 | Open the email under `output/emails/`, click through to the review page, and |
| 71 | approve. The promoted lists and rules land in `output/active/`. |
| 72 | |
| 73 | ## Run it for real |
| 74 | |
| 75 | ```bash |
| 76 | cp .env.example .env # set CTI_APPROVAL_SECRET and feed API keys |
| 77 | cp config.example.yaml config.yaml |
| 78 | python -m cti.cli run -c config.yaml |
| 79 | ``` |
| 80 | |
| 81 | ThreatFox and OTX need free API keys (`THREATFOX_AUTH_KEY`, `OTX_API_KEY`); Feodo, |
| 82 | URLhaus, and OpenPhish are keyless. Set `email.backend: smtp` and the SMTP settings |
| 83 | in `config.yaml` to send the approval mail to a real inbox. Point `wazuh_etc_dir` at |
| 84 | the manager's `/var/ossec/etc` and approval will write the lists and rules straight |
| 85 | into place. |
| 86 | |
| 87 | Schedule it with the systemd timer in `deploy/` (hourly by default) or any cron. |
| 88 | |
| 89 | ## Layout |
| 90 | |
| 91 | ``` |
| 92 | src/cti/feeds/ one connector per source, each with a pure parse() |
| 93 | src/cti/dedup.py cross-feed merge |
| 94 | src/cti/ttp.py ATT&CK extraction + coverage report |
| 95 | src/cti/rules.py CDB list + Wazuh XML generation |
| 96 | src/cti/approval.py signed tokens + email rendering + SMTP |
| 97 | src/cti/pipeline.py orchestration, candidate staging, promotion |
| 98 | src/cti/web.py Flask approval console |
| 99 | fixtures/ sample feed payloads for the demo and tests |
| 100 | tests/ pytest suite (feeds, dedup, ttp, rules, approval, web) |
| 101 | ``` |
| 102 | |
| 103 | ## Tests |
| 104 | |
| 105 | ```bash |
| 106 | make test |
| 107 | ``` |
| 108 | |
| 109 | Connectors are split into `fetch` and `parse`, so the suite runs the real parsing |
| 110 | logic against fixtures with no network. Coverage includes cross-feed dedup, TTP |
| 111 | extraction, rule generation well-formedness, token signing/expiry, and the full |
| 112 | approve/reject path through the web app. |
| 113 | |
| 114 | See [docs/architecture.md](docs/architecture.md) for the data model and |
| 115 | [docs/approval-flow.md](docs/approval-flow.md) for the gate in detail. |