https://github.com/karib0u/rustinel
Windows EDR agent in Rust. ETW telemetry → Sigma/YARA detection → ECS alerts. User-mode, open-source, high-performance.
https://github.com/karib0u/rustinel
blue-team detection-engineering edr endpoint-detection etw incident-response malware-detection rust security-tools siem sigma sysmon threat-detection windows-security yara
Last synced: 4 months ago
JSON representation
Windows EDR agent in Rust. ETW telemetry → Sigma/YARA detection → ECS alerts. User-mode, open-source, high-performance.
- Host: GitHub
- URL: https://github.com/karib0u/rustinel
- Owner: Karib0u
- License: apache-2.0
- Created: 2026-01-31T21:27:43.000Z (5 months ago)
- Default Branch: main
- Last Pushed: 2026-02-04T18:51:46.000Z (5 months ago)
- Last Synced: 2026-02-06T05:46:34.559Z (5 months ago)
- Topics: blue-team, detection-engineering, edr, endpoint-detection, etw, incident-response, malware-detection, rust, security-tools, siem, sigma, sysmon, threat-detection, windows-security, yara
- Language: Rust
- Homepage: https://karib0u.github.io/rustinel/
- Size: 1.02 MB
- Stars: 51
- Watchers: 1
- Forks: 9
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
- Roadmap: docs/roadmap.md
Awesome Lists containing this project
README
# Rustinel
**High-performance, user-mode Windows EDR in Rust**
Rustinel is a **high-throughput Windows EDR agent** written in **Rust**. It collects **kernel telemetry via ETW**, normalizes events into a **Sysmon-compatible schema**, detects threats using **Sigma** + **YARA**, and outputs alerts as **ECS NDJSON** for straightforward SIEM ingestion.
> ✅ No kernel driver
> ✅ User-mode ETW pipeline
> ✅ Sigma behavioral detection, YARA scanning, IOCs detection
> ✅ Local hot reload for Sigma/YARA/IOC files
> ✅ ECS NDJSON alerts + operational logs
---
## Why Rustinel?
Rustinel is built for defenders who want:
- **Kernel-grade telemetry** without kernel risk (ETW, user-mode)
- **Performance under volume** (async pipeline + caching + noise reduction)
- **Detection compatibility** (Sysmon-style normalization for Sigma)
- **Operational simplicity** (NDJSON alerts on disk, easy to ship to a SIEM)
---
## What it does
Rustinel monitors Windows endpoints by:
- Collecting kernel events via **ETW** (process, network, file, registry, DNS, PowerShell, WMI, services, tasks)
- Normalizing ETW events into **Sysmon-compatible** fields
- Detecting threats using **Sigma rules** and **YARA scanning**
- Detecting **atomic IOCs** (hashes, IP/CIDR, domains, path regex)
- Hot-reloading local Sigma/YARA/IOC files without process restart
- Writing alerts in **ECS NDJSON** format
---
## Key features
- **User-mode only**: no kernel driver required
- **Dual detection engines**:
- **Sigma** for behavioral detection
- **YARA** for file scanning on process start
- **Atomic IOC detection**: hashes, IP/CIDR, domains, path regex
- **Local hot reload**: Sigma, YARA, and IOC files are reloaded in-place with atomic swaps
- **Noise reduction**:
- keyword filtering at the ETW session
- router-level filtering for high-volume network events
- optional network connection aggregation
- **Hot-path optimizations**:
- Sigma rules are filtered at load time (`category`/`product`/`service`)
- Sigma conditions are transpiled + precompiled at startup and on hot reload
- process-context enrichment is attached on alerts, not every event
- **Enrichment**:
- NT → DOS path normalization
- PE metadata extraction (OriginalFileName/Product/Description)
- parent process correlation
- SID → `DOMAIN\User` resolution
- DNS caching and reverse mapping
- **Windows service support** (install/start/stop/uninstall)
- **ECS NDJSON alerts** for SIEM ingestion
- **Optional active response** (dry-run or terminate on critical alerts)
---
## Requirements
- Windows 10/11 or Server 2016+
- Administrator privileges (ETW + service management)
- Rust 1.92+ (build from source)
---
## Quick start
> Run from an elevated PowerShell.
**Option 1: Download Release (Recommended)**
1. Download the latest release from [GitHub Releases](https://github.com/Karib0u/rustinel/releases).
2. Extract the archive.
3. Run from an elevated PowerShell:
```powershell
.\rustinel.exe run --console
```
**Option 2: Build from Source**
```powershell
# Build
cargo build --release
# Run (console output)
.\target\release\rustinel.exe run --console
````
Running without arguments is equivalent to `rustinel run`.
---
## 2-minute demo
### Sigma demo
This repo ships with an example rule: `rules/sigma/example_whoami.yml`
1. Start Rustinel (admin shell):
```powershell
cargo run -- run --console
```
2. Trigger the rule:
```powershell
whoami /all
```
3. Verify an alert was written:
* `logs/alerts.json.YYYY-MM-DD`
---
### YARA demo
This repo ships with an example rule: `rules/yara/example_test_string.yar`
1. Build the demo binary:
```powershell
rustc .\examples\yara_demo.rs -o .\examples\yara_demo.exe
```
2. Run it:
```powershell
.\examples\yara_demo.exe
```
3. Verify an alert includes the rule name:
* `ExampleMarkerString`
**Note:** The demo binary runs in a loop to demonstrate active response. With response enabled and `prevention_enabled = true`, the process will be automatically terminated when the YARA rule triggers (YARA matches are treated as `critical` severity).
---
## Service mode
```powershell
.\target\release\rustinel.exe service install
.\target\release\rustinel.exe service start
.\target\release\rustinel.exe service stop
.\target\release\rustinel.exe service uninstall
```
**Notes**
* `service install` registers the *current executable path* — run it from the final location.
* Config and rules paths resolve from the working directory; for services, prefer absolute paths or env overrides.
* Service runtime does not receive CLI flags; set log level via `config.toml` or `EDR__LOGGING__LEVEL`.
---
## Configuration
Configuration precedence:
1. CLI flags (highest, run mode only)
2. Environment variables
3. `config.toml`
4. Built-in defaults
Example `config.toml`:
```toml
[scanner]
sigma_enabled = true
sigma_rules_path = "rules/sigma"
yara_enabled = true
yara_rules_path = "rules/yara"
[reload]
enabled = true
debounce_ms = 2000
[allowlist]
paths = [
"C:\\Windows\\",
"C:\\Program Files\\",
"C:\\Program Files (x86)\\",
]
[logging]
level = "info"
directory = "logs"
filename = "rustinel.log"
console_output = true
[alerts]
directory = "logs"
filename = "alerts.json"
match_debug = "off" # off | summary | full
[response]
enabled = false
prevention_enabled = false
min_severity = "critical"
channel_capacity = 128
allowlist_images = []
[network]
aggregation_enabled = true
aggregation_max_entries = 20000
aggregation_interval_buffer_size = 50
[ioc]
enabled = true
hashes_path = "rules/ioc/hashes.txt"
ips_path = "rules/ioc/ips.txt"
domains_path = "rules/ioc/domains.txt"
paths_regex_path = "rules/ioc/paths_regex.txt"
default_severity = "high"
max_file_size_mb = 50
```
`allowlist.paths` is shared by default across:
- `response.allowlist_paths`
- `ioc.hash_allowlist_paths`
- `scanner.yara_allowlist_paths`
If a module-specific list is explicitly set, it overrides the shared list for that module only.
Match debug output:
1. `alerts.match_debug = "off"` disables match details in alerts (default).
2. `alerts.match_debug = "summary"` adds rule condition + matched fields/patterns.
3. `alerts.match_debug = "full"` adds matched values and YARA string snippets.
Environment overrides:
```powershell
set EDR__LOGGING__LEVEL=debug
set EDR__SCANNER__SIGMA_RULES_PATH=C:\rules\sigma
set EDR__RELOAD__DEBOUNCE_MS=2000
set EDR__ALLOWLIST__PATHS=["C:\\Windows\\","C:\\Program Files\\"]
# optional module-specific override:
set EDR__SCANNER__YARA_ALLOWLIST_PATHS=["C:\\Windows\\","D:\\Trusted\\"]
```
CLI override (highest precedence, run mode only):
```powershell
rustinel run --log-level debug
```
Note: rule logic evaluation errors are only logged at `warn`, `debug`, or `trace` levels (suppressed at `info`).
### Hot reload
| Option | Default | Description |
|--------|---------|-------------|
| `enabled` | `true` | Enable local file-based hot reload for Sigma, YARA, and IOC inputs |
| `debounce_ms` | `2000` | Debounce window for coalescing burst file changes before rebuild/swap |
Notes:
- Poll cadence is `max(reload.debounce_ms, 2000ms)`.
- Empty reload results are rejected for safety (previous compiled engines remain active).
### Active response
| Option | Default | Description |
|--------|---------|-------------|
| `enabled` | `false` | Enable active response engine |
| `prevention_enabled` | `false` | If `false`, logs dry-run actions only |
| `min_severity` | `critical` | Minimum severity to respond to (Sigma uses rule `level`, YARA is always treated as `critical`) |
| `channel_capacity` | `128` | Queue size for response tasks (drops on overflow) |
| `allowlist_images` | `[]` | Image basenames or full paths to skip |
| `allowlist_paths` | inherits `allowlist.paths` | Prefix paths to skip (case-insensitive). Optional module-specific override |
More details: `docs/active-response.md`.
### Atomic IOC detection
| Option | Default | Description |
|--------|---------|-------------|
| `enabled` | `true` | Enable atomic IOC detection |
| `hashes_path` | `rules/ioc/hashes.txt` | Hash IOC file (MD5/SHA1/SHA256) |
| `ips_path` | `rules/ioc/ips.txt` | IP and CIDR IOC file |
| `domains_path` | `rules/ioc/domains.txt` | Domain IOC file |
| `paths_regex_path` | `rules/ioc/paths_regex.txt` | Path/filename regex IOC file |
| `default_severity` | `high` | Severity assigned to IOC alerts |
| `max_file_size_mb` | `50` | Skip hashing files larger than this (MB) |
| `hash_allowlist_paths` | inherits `allowlist.paths` | Prefix paths to skip hashing (case-insensitive). Optional module-specific override |
---
## Rules
### Sigma
* Place `.yml` / `.yaml` files under `rules/sigma/`
* Rules are compiled at startup and hot-reloaded when files change
* Supported categories include:
`process_creation`, `network_connection`, `file_event`, `registry_event`,
`dns_query`, `image_load`, `ps_script`, `wmi_event`, `service_creation`, `task_creation`
### YARA
* Place `.yar` / `.yara` files under `rules/yara/`
* Rules compile at startup and are hot-reloaded when files change
* Scans trigger on **process creation** (runs in a background worker)
* Files under allowlisted path prefixes are skipped (`allowlist.paths` by default or `scanner.yara_allowlist_paths` override)
### Atomic IOCs
Place indicator files under `rules/ioc/`:
* `hashes.txt` — MD5, SHA1, SHA256 hashes (auto-detected by length)
* `ips.txt` — IP addresses and CIDR ranges
* `domains.txt` — exact domains or `*.`/`.` prefix for suffix matching
* `paths_regex.txt` — case-insensitive regexes matched against file paths
Hash checking runs in a dedicated background worker on process creation. Files under allowlisted paths (shared `allowlist.paths` by default, or `ioc.hash_allowlist_paths` override) and files exceeding `max_file_size_mb` are skipped automatically. Domain, IP, and path checks run inline with negligible overhead.
IOC files are also hot-reloaded when they change.
---
## Output
Rustinel produces:
* **Operational logs**: `logs/rustinel.log.YYYY-MM-DD`
* **Security alerts** (ECS NDJSON): `logs/alerts.json.YYYY-MM-DD`
Example alert (one JSON object per line):
```json
{
"@timestamp": "2025-01-15T14:32:10Z",
"event.kind": "alert",
"event.category": "process",
"event.action": "process_creation",
"rule.name": "Whoami Execution",
"rule.severity": "low",
"rule.engine": "Sigma",
"process.executable": "C:\\Windows\\System32\\whoami.exe",
"process.command_line": "whoami /all",
"user.name": "DOMAIN\\username"
}
```
---
## Development
```powershell
# Unit tests
cargo test
# Format + lint
cargo fmt
cargo clippy
# Validate Sigma + YARA rules
cargo run --bin validate_rules
```
Project layout (high level):
```text
src/
├── collector/ # ETW collection + routing
├── normalizer/ # Sysmon-style normalization + enrichment
├── engine/ # Sigma engine
├── scanner/ # YARA scanning worker
├── ioc/ # Atomic IOC detection (hashes, IPs, domains, paths)
├── state/ # caches (process/sid/dns/aggregation)
└── bin/validate_rules.rs
```
---
## Roadmap
Short roadmap:
- YARA expansion (memory scanning + periodic scans).
- Resource governor (Windows Job Objects CPU limits).
- Self-defense hardening (DACL/ACL restrictions + anti-injection).
- Watchdog sidecar to restart the service if the main process dies.
- ETW integrity checks to detect blinding/tampering.
- Deep inspection via stack tracing for "floating code".
---
## Status
Rustinel is **Alpha**. It’s usable for experimentation, lab deployments, and iterative hardening.
Expect breaking changes while the schema + engines mature.
---
## License
Apache 2.0 — see `LICENSE`.