WAKE
WAKE enriches, matches, and scores entities (IPs, users, hostnames,
sessions) inside the rsyslog pipeline, then propagates verdicts across
a tenant-scoped mesh of edges. The hot path is C, and so is gossip
(immesh, inside rsyslog); analytics are Python. It is meant for collectors that cannot ship every line, and
for sites where a central correlator is not available.
The C hot path
On each source ruleset the line is parsed, then enriched, then scored,
before it is written. mmsigma runs once after that, in the
shared logstore ruleset. None of these actions blocks the rsyslog queue.
mmenrich- CTI enrichment (C)- IOC lookup against a compiled
.thrtdatabase (IPs, domains, hashes, emails) plus MaxMind GeoIP City and ASN. The lookup path is bloom filter, then an accel table and binary search, with the CRC32C instruction from SSE 4.2 and ARMv8-CRC used for hashing; the vector code paths belong to the offline IOC miner rather than the lookup. Writes$!threat,$!labelsand$!tags, with the emit target configurable. Pure enrichment: no state, no scoring. mmwake- entity scoring & pheromone deposit (C)- Per-entity behavioral counters with thresholds fed from a
.score_baselinesidecar, consuming$!threatand$!labelsand folding a composite score into a shared pheromone mmap. Requires the SIMD TurboVM parser.immeshis not the next stage of this line: it is the C input module, in the same rsyslog process, that gossips and runs quorum on that table. mmsigma- Sigma detection & correlation (C)- Multi-pattern Sigma rule matching with a Teddy/SIMD matcher, carrying each rule’s MITRE ATT&CK technique into the verdict. The same action runs the correlation engine (
event_count,value_count,temporal, sum/avg/percentile, beaconing,temporal_ordered). Commutative partials hash onto one owner in a configured ring as$!sigma_contribution; the module does not open sockets. Percentile, median, ordered and beaconing types stay local. This plane does not merge with the pheromone table. See the mmsigma mesh pattern.
Mesh, engine, and console
libwakeandimmesh- pheromone gossip (C)- Edges broadcast signals about scored entities to their tenant peers over SWIM and PlumTree, run by the
immeshrsyslog module and enabled per node. Receivers add the confidence into a shared per-entity counter, and an alert requires at least two distinct sources, so local observations become fleet-wide awareness without a central correlator. waked- behavioral engine (Python)- Sixteen behavioral detectors in three groups: twelve per-entity (profile, first-seen, temporal, velocity, lateral-movement, data-staging, geo-travel, DNS and ICMP tunneling, cross-category, credential-pivot, slow-scan), three correlating over the signals those produce (role-incongruence, attack-chain, cross-window sequence), and one keyed on destinations rather than sources. Most carry a MITRE ATT&CK mapping; a few emit without one. Beaconing sits outside this layer: the C mmsigma correlation detects it at line rate and projects it into a
beaconingsignal. See behavioral detectors for the full list, thresholds and gaps. An EMA volume model over hour-of-week slots (which also feeds mmwake's baseline sidecar), a LogStore (DuckDB) for hot data, and an EntityStore (SQLite) for metadata. Detector thresholds themselves are configured constants with per-profile overrides, not EMA-derived. Exposes/ocsffor OCSF 1.8.0 projection (Detection 2004, Network 4001, Auth 3002, HTTP 4002). Also profiles its own Sigma layer on a timer and reports noisy and silent rules: see detection health. wakeweb- SOC console (Python / NiceGUI)- Delegates authentication to fleet over the local
fleetdbroker socket, so operator accounts are managed in one place. Authorization is tenant scoping rather than a read/write split: a viewer role exists but is not yet enforced, so any authenticated session in scope can mutate. See the console.
Pipeline
log sources syslog, journald, file tail, MQTT, ...
|
v
[ rsyslog ] input modules accept raw events
|
+-- mmnormalize + TurboVM structured field extraction (SIMD)
+-- mmenrich CTI / IOC / GeoIP -> $!threat, $!labels
+-- mmwake entity scoring + pheromone deposit
+-- immesh C input, same process: gossip + quorum
| on the mmwake table, not on the log line
+-- mmsigma Sigma match + correlation -> $!sigma
| hashed contribs -> $!sigma_contribution
| other plane: do not merge with pheromone
|
v
[ enriched.jsonl ] LogStore ingest path
|
v
[ waked ] 16 behavioral detectors, Python
+-- /ocsf endpoint OCSF 1.8.0 projection to downstream SIEM
+-- wakeweb operator console
Two meshes, one engine
A central correlator assumes a reliable path back to one box. That does not hold for offshore racing, DMZ collectors, or air-gapped floors. WAKE uses two planes that must not be collapsed into one gossip topic.
- Sigma reduce (hashed owner)
- Commutative correlation windows (
event_count,value_count,temporal, sum/avg) merge among the peers named in the overlay's ring. Owner =djb2(corr_id TAB group) % peercount. Non-owners emit$!sigma_contributionJSON; rsyslogomfwdmoves it.temporal_orderedand raw beaconing stay on the node that saw the events. mmsigma never opens a socket. See the vector diagram. - Pheromone (SWIM / PlumTree)
- Each edge broadcasts signals about scored entities to tenant
peers. Receivers add the confidence into a shared counter, which
decays globally on a timer rather than being weighted per source;
over a quorum the entity’s composite score crosses a
detection threshold without any single edge having seen the whole
picture. Injected
wake_signalJSON has no TurboVM arena, so that ruleset skips mmsigma. This plane is liveness and scoring gossip, not Sigma partials.
| Entity | Score | Hits | Sources |
|---|---|---|---|
| 203.0.113.66 | 8.7 | 142 | 5 |
| 198.51.100.23 | 6.4 | 88 | 3 |
| user:svc-backup | 4.9 | 51 | 2 |
| 192.0.2.140 | 3.2 | 27 | 2 |
| host:edge-04 | 1.8 | 12 | 1 |
Campaign, then TAC shadow
The campaign matcher that runs is attack-chain: fixed patterns over signals already emitted, on one entity. Sequence adds order, absence, and a handoff to another entity. Neither is a learned graph, and neither is the pheromone plane.
TAC (Transient Associative Coupling) is a local memory of which techniques co-fire on the same entity. The table decays. It is off by default. Nothing in the verdict, the alert, or the score reads it, and a coupling is not a reason to isolate a host. It sits beside attack-chain. It does not replace it.
Integration
WAKE doesn’t talk to fleetserver directly. It uses
the local fleetd as a broker (Unix socket
/var/run/fleet/app.sock, peer-UID gated). That removes
per-app service tokens, makes auth delegation consistent, and survives
fleetserver being unreachable.
- Edge-portable
- The WAKE collector runs on FreeBSD (jails), Linux (host), and macOS (dev). Only the platform integration differs; detectors are the same.
- OCSF projection
- Declarative mapping from internal signal schema to OCSF 1.8.0.
GET /ocsfon waked exposes the projection for downstream SIEMs. - Storage
- LogStore is DuckDB over per-day Parquet parts, with retention as removal of expired parts and periodic consolidation of the small ones. EntityStore is SQLite.
- Parsing
- The fast path is TurboVM, a 64-byte bytecode VM with SSE 4.2 / NEON code paths integrated into
liblognorm.