AMFeedlyCustomerScripts/Feedly_Threat_Actor_IOC_Extractor

GitHub: AMFeedlyCustomerScripts/Feedly_Threat_Actor_IOC_Extractor

Stars: 0 | Forks: 0

# Feedly Threat Actor IOC Extractor Extract Indicators of Compromise (IPs, domains, file hashes, URLs) associated with any threat actor tracked by Feedly Threat Intelligence — directly from the command line. ## Overview This tool implements a repeatable two-step workflow from the Feedly Threat Actor Insights card to a full IOC list: 1. **Resolve** — search for a threat actor by name (e.g. `"Lazarus Group"`, `"APT28"`) to retrieve its Feedly NLP entity ID via the autocomplete endpoint. 2. **Extract** — call the threat actor relationships endpoint to pull all associated IOC entities and classify them by type. ### Use Cases - **SIEM / SOAR ingestion** — feed IOCs into Splunk, Sentinel, or XSOAR in JSON or CSV - **Firewall / EDR blocklists** — export IP and domain lists for policy updates - **Threat hunt preparation** — pull hashes before a hunt to pre-populate detection tools - **Incident response** — quickly enumerate all known IOCs for an actor during an active incident - **Scheduled automation** — run on a cron/schedule against a fixed actor ID for continuous refresh ## Requirements - Python 3.8+ - Feedly Enterprise API token - `requests` library (`pip install requests`) - `PyYAML` library for config file support (`pip install pyyaml`) — optional ## Installation # 1. Clone the repository git clone https://github.com/AMFeedlyCustomerScripts/Feedly_Threat_Actor_IOC_Extractor.git cd Feedly_Threat_Actor_IOC_Extractor # 2. Install dependencies pip install -r requirements.txt # 3. Configure credentials (choose one method) ### Credential Options **Option A — Environment variable (recommended for automation)** export FEEDLY_API_KEY="your_feedly_api_token" **Option B — .env file** echo 'FEEDLY_API_KEY="your_feedly_api_token"' > .env **Option C — Config file** cp config.yaml.template config.yaml # Edit config.yaml and set feedly.api_token ## Usage ### Basic — search by name python feedly_threat_actor_ioc.py --actor "Lazarus Group" The script resolves the name to an entity ID interactively if multiple actors match, then fetches all associated IOCs across all time. ### Skip name resolution — use entity ID directly python feedly_threat_actor_ioc.py \ --actor-id "nlp/f/entity/gz:ta:68391641-859f-4a9a-9a1e-3e5cf71ec376" Useful in automation where the entity ID is already known (e.g. stored from a prior `--dry-run`). ### Restrict the time window python feedly_threat_actor_ioc.py --actor "APT28" --interval LAST_30_DAYS ### Filter by IOC type # IPs and domains only python feedly_threat_actor_ioc.py --actor "Lazarus" --type ip,domain # Hashes only python feedly_threat_actor_ioc.py --actor "Lazarus" --type hash ### Save output to a file # Plain text — grouped by type, one value per line python feedly_threat_actor_ioc.py --actor "Lazarus" --output lazarus_iocs.txt --format txt # JSON — full metadata per IOC python feedly_threat_actor_ioc.py --actor "Lazarus" --output lazarus_iocs.json --format json # CSV — one row per IOC, ready for Excel or SIEM import python feedly_threat_actor_ioc.py --actor "Lazarus" --output lazarus_iocs.csv --format csv ### Dry run — resolve name only, skip IOC fetch python feedly_threat_actor_ioc.py --actor "Sandworm" --dry-run Prints the entity ID without making the relationships call. Useful for pre-validating actor names in scripts. ### Use a config file cp config.yaml.template config.yaml # Edit config.yaml python feedly_threat_actor_ioc.py --actor "Lazarus" --config config.yaml ### Debug the raw API response python feedly_threat_actor_ioc.py --actor "APT29" --dump-raw --verbose Prints the full JSON response from the relationships endpoint to stderr — helpful when first running against a new actor or API version. ## Command-Line Reference | Option | Short | Description | |--------|-------|-------------| | `--actor NAME` | `-a` | Threat actor name to search (mutually exclusive with `--actor-id`) | | `--actor-id ID` | `-i` | Skip name resolution; use this entity ID directly | | `--interval WINDOW` | | Time window: `LAST_7_DAYS`, `LAST_30_DAYS`, `LAST_3_MONTHS`, `LAST_6_MONTHS`, `LAST_1_YEAR`, `FOREVER` (default: `FOREVER`) | | `--type TYPES` | `-t` | Comma-separated filter: `ip`, `domain`, `hash`, `url`, `email`, `other`, `all` (default: `all`) | | `--format FORMAT` | `-f` | Output format: `txt`, `json`, `csv` (default: `txt`) | | `--output FILE` | `-o` | Write to file instead of stdout | | `--config FILE` | `-c` | Path to YAML config file (default: `config.yaml` in current/script dir) | | `--api-key KEY` | | Override API key from environment / config | | `--search-count N` | | Max actor candidates returned in the search step (default: `10`) | | `--dry-run` | | Resolve actor name and print entity ID only | | `--dump-raw` | | Print raw relationships JSON to stderr | | `--verbose` | `-v` | Enable debug output | ## Output Formats ### Text (`--format txt`) Plain-text, grouped by IOC type. One value per line — easy to paste into tickets or blocklist configs. # Feedly Threat Actor IOC Export # Actor : Lazarus Group # ID : nlp/f/entity/gz:ta:68391641-859f-4a9a-9a1e-3e5cf71ec376 # Window : FOREVER # Date : 2026-05-29T14:30:00Z # Total : 42 IOC(s) ## DOMAIN (18) cdn-apple.com download-node.com ... ## HASH (14) 3a4b5c6d7e8f... ... ## IP (10) 185.220.101.45 ... ### JSON (`--format json`) Full metadata including article mention count and Feedly entity ID per IOC. { "meta": { "actor_name": "Lazarus Group", "actor_id": "nlp/f/entity/gz:ta:68391641-859f-4a9a-9a1e-3e5cf71ec376", "interval": "FOREVER", "exported_at": "2026-05-29T14:30:00+00:00", "total_iocs": 42 }, "iocs": [ { "value": "185.220.101.45", "ioc_type": "ip", "ioc_group": "ip", "article_count": 7, "entity_id": "nlp/f/entity/ioc:..." }, { "value": "cdn-apple.com", "ioc_type": "domain", "ioc_group": "domain", "article_count": 3, "entity_id": "nlp/f/entity/ioc:..." } ] } ### CSV (`--format csv`) One row per IOC with actor context columns — ready for Excel, Splunk lookup tables, or SIEM ingestion. value,ioc_type,ioc_group,article_count,entity_id,actor_name,actor_id,interval 185.220.101.45,ip,ip,7,nlp/f/entity/ioc:...,Lazarus Group,nlp/f/entity/gz:ta:...,FOREVER cdn-apple.com,domain,domain,3,nlp/f/entity/ioc:...,Lazarus Group,nlp/f/entity/gz:ta:...,FOREVER ## IOC Type Classification The script classifies each IOC value automatically using regex: | Group | Fine-grained types | Examples | |-------|--------------------|---------| | `ip` | `ip` (IPv4/CIDR), `ipv6` | `185.220.101.45`, `2001:db8::1` | | `domain` | `domain` | `cdn-apple.com`, `update-service.net` | | `hash` | `hash_md5`, `hash_sha1`, `hash_sha256`, `hash_sha512` | 32/40/64/128 hex chars | | `url` | `url` | `https://malicious.example/payload` | | `email` | `email` | `attacker@protonmail.com` | | `other` | `unknown` | Anything that does not match above | Defanged IOCs (e.g. `hxxps://`, `[.]`) are normalised before classification. ## Configuration File Copy `config.yaml.template` to `config.yaml` and edit as needed: feedly: api_token: "YOUR_FEEDLY_API_TOKEN_HERE" defaults: interval: "FOREVER" # Default time window format: "json" # Default output format ioc_types: "all" # Default IOC type filter output_dir: "./output" # Auto-save timestamped files here (optional) CLI flags always override config file values. ## Automation Example #!/bin/bash # Daily IOC refresh for a known actor export FEEDLY_API_KEY="..." python feedly_threat_actor_ioc.py \ --actor-id "nlp/f/entity/gz:ta:68391641-859f-4a9a-9a1e-3e5cf71ec376" \ --interval LAST_7_DAYS \ --type ip,domain \ --format csv \ --output /var/threat-intel/lazarus_$(date +%Y%m%d).csv ## Troubleshooting **No IOCs returned** The relationships endpoint surfaces IOC entities that Feedly has explicitly linked to the actor. If the result is empty: - Try `--interval FOREVER` to widen the time window. - Use `--dump-raw --verbose` to inspect the raw response structure. - Verify the entity ID with `--dry-run` — a wrong ID returns 404. - Some actors may have relationships classified as malware/TTP only, with no linked IOC entities. **Authentication error** Verify your token is set: `echo $FEEDLY_API_KEY`. Tokens can be generated at `https://feedly.com/v3/auth/dev`. **Multiple actors matched** The search returns up to `--search-count` (default 10) candidates. Use the interactive menu to pick the correct one, or use `--actor-id` to bypass search entirely once you know the entity ID. ## API Endpoints Used | Step | Method | Endpoint | |------|--------|----------| | Name resolution | `GET` | `/v3/search/entities?query={name}&count={n}` | | IOC extraction | `GET` | `/v3/ml/relationships/actor/{id}?intervalType={window}` | ## License © 2025 Feedly, Inc. All rights reserved. See the script header for the full disclaimer.