fb52b1432e
Fibratus EDR profile (kind: fibratus). Pull-from-event-log model, same
shape DetonatorAgent's FibratusEdrPlugin.cs uses: operator configures
Fibratus on the EDR VM with alertsenders.eventlog: {enabled: true,
format: json}; rule matches land in the Application log. Whiskers gains
GET /api/alerts/fibratus/since which wevtutil-queries the log,
extracts <TimeCreated SystemTime> + <EventID> + <Data>, ships the raw
JSON blobs back. The new FibratusEdrAnalyzer mirrors Elastic's
two-phase shape — Phase 1 exec, Phase 2 polls Whiskers — and normalizes
Fibratus's actual schema (events[].proc.{name,exe,cmdline,parent_name,
parent_cmdline,ancestors} + bare tactic.id/technique.id/subtechnique.id
labels) into the saved-view renderer's dict.
Whiskers /api/info now reports telemetry_sources: ['fibratus'] when
fibratus.exe is at C:\Program Files\Fibratus\Bin\, so the
orchestrator can preflight before dispatching. wevtutil's single-quoted
attribute output is parsed correctly.
Dashboard reachability cache (services.edr_health). 30s TTL +
background poller every 15s. Per-probe timeouts dropped 4s/5s -> 2s.
First load post-boot waits at most one probe cycle; every subsequent
load <5ms (cache hit).
GrumpyCats package split: 1085-line monolith into:
grumpycat.py — orchestrator (14 lines)
cli/ — parser, handlers, runner
litterbox_client/ — base + per-domain mixins (files, analysis,
doppelganger, results, edr, reports, system)
composed into LitterBoxClient.
LitterBoxMCP.py rewires its one import. New CLI subcommand
fibratus-alerts and matching MCP tool fibratus_alerts_since pull
Fibratus alerts via a LitterBox passthrough endpoint
(/api/edr/fibratus/<profile>/alerts/since) for wire-checking the agent
without dispatching a payload.
CHANGELOG updated.
53 lines
1.7 KiB
Rust
53 lines
1.7 KiB
Rust
//! `GET /api/info` — agent self-reports its identity so LitterBox can
|
|
//! filter Elastic alerts by the host's actual hostname without the operator
|
|
//! configuring it manually. `telemetry_sources` lets the orchestrator
|
|
//! preflight which alert pipelines this VM can serve (currently: Fibratus
|
|
//! installed-or-not).
|
|
|
|
use std::path::Path;
|
|
|
|
use axum::Json;
|
|
use serde::Serialize;
|
|
|
|
const AGENT_VERSION: &str = env!("CARGO_PKG_VERSION");
|
|
|
|
/// Default Fibratus install path. LitterBox treats the presence of this
|
|
/// binary as the cheap probe for "this VM can serve Fibratus alerts."
|
|
const FIBRATUS_EXE: &str = r"C:\Program Files\Fibratus\Bin\fibratus.exe";
|
|
|
|
#[derive(Serialize)]
|
|
pub struct AgentInfo {
|
|
pub hostname: String,
|
|
pub os_version: String,
|
|
pub agent_version: &'static str,
|
|
/// Names of additional telemetry pipelines this VM can serve. The
|
|
/// orchestrator dispatches a profile of `kind: fibratus` only when
|
|
/// `"fibratus"` appears in this list.
|
|
pub telemetry_sources: Vec<&'static str>,
|
|
}
|
|
|
|
pub async fn get_info() -> Json<AgentInfo> {
|
|
let hostname = gethostname::gethostname()
|
|
.into_string()
|
|
.unwrap_or_else(|_| "unknown".to_string());
|
|
let os_version = os_info::get().to_string();
|
|
|
|
let mut telemetry_sources: Vec<&'static str> = Vec::new();
|
|
if has_fibratus() {
|
|
telemetry_sources.push("fibratus");
|
|
}
|
|
|
|
Json(AgentInfo {
|
|
hostname,
|
|
os_version,
|
|
agent_version: AGENT_VERSION,
|
|
telemetry_sources,
|
|
})
|
|
}
|
|
|
|
/// Cheap "is Fibratus installed here?" check. Just a stat — we do not
|
|
/// run the binary or query the event log on every /api/info hit.
|
|
pub fn has_fibratus() -> bool {
|
|
Path::new(FIBRATUS_EXE).exists()
|
|
}
|