Threat intelligence feeds¶
Threat intelligence feeds keep lookups filled with current indicators of compromise (IOC): IP addresses, domains, URLs, hashes, and similar values. As an analyst you usually choose which feed fills which lookup, then use that lookup in detections (and optionally in risk scoring) so rules stay current without hard coding indicator lists in YAML.
Typical uses:
- Watchlists: alert when traffic or DNS hits a known bad IP or domain.
- Risk boost: raise
event.risk_scorewhen a window dimension matches an IOC row. - Shared intel: keep one maintained list for many correlation rules.
For membership tests and whitelist / blacklist patterns in predicates, see Lookups in detections. For how IOC rows change numeric risk, see Risk scoring. Lookup types and declarations are in the Lookups reference.
How feeds connect to detections¶
The path is always the same:
- A feed declaration in the Library (
/Feeds/…) pulls data on a schedule (HTTP JSON, CSV, and similar sources). - The feed writes items into a named lookup (
output.lookup). - A detection (or risk scoring) reads that lookup with
!LOOKUP/!LOOKUP.CONTAINS, or via theioclookup group.
External TI source → Feed (lmio-feeds) → Lookup items → Correlator / risk score
You can also attach a feed from the Lookups UI (feedPath). The runtime effect is the same: the lookup content is refreshed from the feed.
Who owns what
Analysts maintain which indicators matter (lookup content and feed targets). Detection engineers keep predicate wiring stable. Prefer changing feed / lookup content over editing rule YAML when the indicator set grows.
Prerequisites¶
- LogMan.io Feeds is deployed (service that runs feed declarations).
- A lookup declaration exists under
/Lookups(many IOC lookups ship in the common library withdefault: true). - The feed’s
output.lookupname matches the lookupdefine.name(tenant suffix is handled for you). - Key types align: IP feeds →
lookup/ipaddress(or IP range); domains → string keys; and so on.
Shipped IOC oriented lookups include:
| Lookup | Typical key | Group | Used for |
|---|---|---|---|
maliciousipaddresses |
IP | ioc |
Bad source / destination IPs |
maliciousdomains |
domain string | ioc |
DNS and HTTP hostnames |
maliciousurls |
URL string | (varies) | Full URL matches |
malicioushashes |
file hash | (varies) | File / malware hashes |
torexitnodes / vpnexitnodes |
IP | (none) | Anonymizer exit nodes |
Put a lookup in the ioc group when you want Correlator risk scoring to add score automatically for matching window dimensions. See IOC and threat intelligence.
Example: feed that fills a malicious IP lookup¶
Minimal feed that reads a JSON list of IP objects and updates maliciousipaddresses.
Example response from GET /api/v1/ips (fictional TI API, shortened). The feed iterates results:
{
"count": 2,
"results": [
{
"ip": "203.0.113.66",
"risk.score": 25.0,
"tags": ["botnet", "scanner"]
},
{
"ip": "198.51.100.14",
"risk.score": 40.0,
"tags": ["c2"]
}
]
}
How this maps in the feed below:
iterate: results→ one lookup item per objectkey: !ITEM EVENT ip→203.0.113.66and198.51.100.14become keys inmaliciousipaddressesrisk.scoreis stored on the item for risk scoring; if missing, the feed defaults to25.0- extra fields such as
tagsare ignored unless you add them toschema/apply
---
define:
name: Malicious IP Feed
type: lmio/feed
schema:
ip: str
risk.score: fp64
input:
source: https://ti.example.com/api/v1/ips
type: json
iterate: results
period: 1h
headers: '{"Authorization": "Bearer YOUR_TOKEN"}'
verify: none
apply:
key: !ITEM EVENT ip
risk.score:
!TRY
- !ITEM EVENT risk.score
- 25.0
output:
lookup: maliciousipaddresses
Notes:
periodcontrols how often the feed refreshes (for example1h,1d).keybecomes the lookup key; extra fields (such asrisk.score) become lookup attributes used by risk scoring.- Replace the URL, headers, and
iteratepath to match your TI provider’s JSON shape. - For APIs that return a
nextURL per page, use pagination (subtype: pagination,pagination_mode: url). Ask your administrator if you need that wiring.
After the feed runs, open Lookups → maliciousipaddresses and confirm new IPs appear.
Example: alert when traffic hits an IOC IP¶
Same pattern as other watchlists in Lookups in detections: membership of source.ip in the lookup.
predicate:
!AND
- !IN
what: source.ip
where: !EVENT
- !IN
what: !ITEM EVENT source.ip
where:
!LOOKUP
what: maliciousipaddresses
trigger:
- event:
source.ip: !ITEM EVENT source.ip
destination.ip: !ITEM EVENT destination.ip
threat.indicator.confidence: high
threat.indicator.ip: !ITEM EVENT source.ip
threat.indicator.type: malicious_ip
Library rules such as Traffic from Tor Exit Nodes use the same idea with torexitnodes instead of maliciousipaddresses. Point your feed at torexitnodes (or keep a dedicated Tor list) and the shipped rule starts matching as soon as items land in the lookup.
Shorthand¶
- !LOOKUP.CONTAINS
what: !ITEM EVENT source.ip
in: maliciousipaddresses
Example: malicious domains and DNS¶
- Feed writes hostnames into
maliciousdomains(string keys). - Rule tests
dns.question.name(orurl.domain, depending on your parsers).
predicate:
!AND
- !IN
what: dns.question.name
where: !EVENT
- !IN
what: !ITEM EVENT dns.question.name
where:
!LOOKUP
what: maliciousdomains
Align the feed’s key with the event field (FQDN vs bare domain). Normalize in the feed apply section if the TI source and your DNS logs use different formats.
Example: raise risk without a dedicated rule¶
If the lookup is in the ioc group, Correlator can add risk.score from matching rows whenever a detection’s window dimensions include that value (for example source.ip or dns.question.name). You do not need a separate “IOC hit” rule for that boost.
key risk.score
203.0.113.66 25.0
evil.example.com 20.0
A VPN failure rule with base score 45 whose source.ip matches the first row becomes 70 before any asset weight. Details: Risk scoring.
You can still write an explicit watchlist rule (previous sections) when you want a dedicated alert for every IOC sighting, not only a score bump on other detections.
Wiring checklist¶
- Lookup exists and has the right type (
ip, string, and so on). - Optional: set
group: iocon the lookup declaration for automatic risk adds. - Feed
output.lookupequals the lookup name. - Feed
key/ schema matches lookup keys; cast types inapplywhen needed. - Detection uses
!LOOKUP/!LOOKUP.CONTAINSon the same name, or you rely oniocrisk only. - After deploy, wait for one feed
period, then verify items in the UI and a test event in Discover.
Practical tips¶
- Prefer one feed per lookup (or a clear merge strategy) so ownership stays obvious.
- Keep base severity on the rule honest; use IOC
risk.scoreand rule tuning to prioritize without rewriting predicates. - Use global lookups / feeds for shared intel across tenants; use tenant scoped ones for local or customer specific lists.
- Do not paste large static IOC lists into correlation YAML; that is what feeds and lookups are for.
- When testing, insert a single known test IP or domain into the lookup (UI or feed), fire a synthetic event, then remove the test row.
Advanced example: Netbox prefixes as enrichment¶
Not every feed is a classic IOC watchlist. The same feed → lookup path can keep inventory data current and reuse it in parsing enrichment and in detections. A common case is Netbox IPAM prefixes: each prefix is a CIDR with optional VLAN and description; the feed stores them in an IP range lookup; Parsec then tags events by source.ip.
1. IP range lookup¶
Declare a lookup with two IP keys (start, end) and the attributes you want on the event:
---
define:
type: lookup/ipaddressrange
name: netbox
label: Netbox prefixes
description_title: Prefixes and VLANs from Netbox IPAM
keys:
- name: start
type: ip
- name: end
type: ip
fields:
prefix:
type: str
description:
type: str
vlan.id:
type: str
vlan.name:
type: str
status:
type: str
2. Feed that pages Netbox and expands CIDR keys¶
Netbox (and similar Django REST APIs) return an absolute next URL. Use pagination_mode: url. The feed key is the CIDR string (prefix); LogMan.io Feeds expands it to start / end for the IP range lookup.
Example response from GET /api/ipam/prefixes/?limit=100 (shortened). The feed iterates results and follows next until it is null:
{
"count": 2,
"next": "https://netbox.example.com/api/ipam/prefixes/?limit=100&offset=100",
"previous": null,
"results": [
{
"id": 42,
"prefix": "10.0.112.0/22",
"description": "Office LAN Prague",
"status": {
"value": "active",
"label": "Active"
},
"vlan": {
"id": 7,
"vid": 112,
"name": "OFFICE-PRG"
}
},
{
"id": 43,
"prefix": "10.0.200.0/24",
"description": "Guest WiFi",
"status": {
"value": "active",
"label": "Active"
},
"vlan": null
}
]
}
How this maps in the feed below:
iterate: results→ one lookup item per prefix objectpagination_path: next→ second page URL above; last page has"next": nullkey: !ITEM EVENT prefix→ for example10.0.112.0/22becomes range10.0.112.0…10.0.115.255- nested
vlan.vid/vlan.nameandstatus.labelvia nested!GET; whenvlanisnull,!TRYstores an empty string
---
define:
name: Netbox Prefixes Feed
type: lmio/feed
schema:
prefix: str
description: str
vlan: "(id: si64, vid: si64, name: str)"
status: "(value: str, label: str)"
input:
source: https://netbox.example.com/api/ipam/prefixes/?limit=100
type: json
subtype: pagination
pagination_path: next
pagination_mode: url
iterate: results
period: 1d
headers: '{"Authorization": "Bearer NETBOX_TOKEN"}'
verify: none
apply:
key: !ITEM EVENT prefix
prefix:
!CAST
what: !ITEM EVENT prefix
type: str
description:
!TRY
- !CAST
what: !ITEM EVENT description
type: str
- ""
vlan.id:
!TRY
- !CAST
what:
!GET
from:
!GET
from: !EVENT
what: vlan
what: vid
type: str
- ""
vlan.name:
!TRY
- !CAST
what:
!GET
from:
!GET
from: !EVENT
what: vlan
what: name
type: str
- ""
status:
!TRY
- !CAST
what:
!GET
from:
!GET
from: !EVENT
what: status
what: label
type: str
- ""
output:
lookup: netbox
Nested Netbox objects (vlan, status) need nested !GET (not a flat !ITEM EVENT vlan.vid). Missing VLAN is handled with !TRY and an empty string. A template for this feed ships under /Templates/Feeds/ in the common library.
3. Enricher: map source.ip to ECS fields¶
Once the lookup is populated, a Parsec enricher can resolve the range that contains source.ip and write ECS fields such as source.vlan.id, source.vlan.name, source.subnet.id, and network.name. Place the enricher in the parser chain after mapping so source.ip already exists.
---
define:
type: parsec/enricher
schema: /Schemas/ECS.yaml
enrich:
source.vlan.id:
!OR
- !GET
what: vlan.id
from:
!GET
from:
!LOOKUP
what: netbox
what: !ITEM EVENT source.ip
- !ITEM EVENT source.vlan.id
source.vlan.name:
!OR
- !GET
what: vlan.name
from:
!GET
from:
!LOOKUP
what: netbox
what: !ITEM EVENT source.ip
- !ITEM EVENT source.vlan.name
source.subnet.id:
!OR
- !GET
what: prefix
from:
!GET
from:
!LOOKUP
what: netbox
what: !ITEM EVENT source.ip
- !ITEM EVENT source.subnet.id
network.name:
!OR
- !GET
what: description
from:
!GET
from:
!LOOKUP
what: netbox
what: !ITEM EVENT source.ip
- !ITEM EVENT network.name
!OR keeps an existing value when the lookup misses (unknown or public IP). The same pattern works for destination.ip or client.ip if you add parallel blocks.
Schema auto enrich
ECS also documents automatic enrich from lookup subnets into source.vlan.id / source.subnet.id. If you name the lookup subnets and align field names, Parsec can fill those two fields without a custom enricher. The enricher above is for a lookup named netbox and for extra fields such as source.vlan.name and network.name.
4. Optional: detections on enriched or raw lookup data¶
After enrichment, rules can filter on source.vlan.id or network.name like any other ECS field. You can also test membership in the range lookup directly (same style as zones):
- !IN
what: !ITEM EVENT source.ip
where:
!LOOKUP
what: netbox
That is useful for “traffic from a Netbox managed prefix” style rules, while the enricher keeps Discover and dashboards readable without repeating the lookup in every query.
Related reading¶
- Lookups in detections: whitelist and blacklist predicates
- Risk scoring: IOC group and score layers
- Predicates: SP Lang filters
- Enricher declarations: adding fields during parsing
- Lookups reference: types, declarations, deployment
- IP address lookups: IP and IP range lookups
- Advanced correlation rules: multi stage rules that may consume threat intel signals