-
Notifications
You must be signed in to change notification settings - Fork 166
Application Architecture
LitterBox is a Flask app with server-rendered Jinja templates and vanilla-JS ES6 modules on the frontend (no build step). Analysis is performed by a registry of pluggable analyzer classes; the EDR pipeline is a separate orchestrator that talks to a remote agent over HTTP.
graph LR
Upload[Operator uploads sample] --> Hash[Hash + metadata + entropy]
Hash --> Type{Type}
Type -->|.exe / .dll / .lnk / .docx / .xlsx / .bin| FileFlow[File analysis]
Type -->|.sys| DriverFlow[Driver analysis]
PID[Operator picks a PID] --> ProcessFlow[Process analysis]
FileFlow --> StaticGroup[Static analyzers]
FileFlow --> DynamicGroup[Dynamic analyzers]
FileFlow --> EdrGroup[EDR profiles]
DriverFlow --> Holygrail[HolyGrail BYOVD]
ProcessFlow --> DynamicGroup
StaticGroup --> Persist[(Saved JSON)]
DynamicGroup --> Persist
EdrGroup --> Persist
Holygrail --> Persist
Persist --> Risk[Risk scoring]
Risk --> Render[Results pages]
Each rounded box is a separate JSON file under Results/<hash>_<original-name>/:
| File | Source |
|---|---|
file_info.json |
written at upload β hashes, entropy, PE info, etc. |
static_analysis_results.json |
YARA + CheckPlz + Stringnalyzer findings |
dynamic_analysis_results.json |
YARA-mem + PE-Sieve + Moneta + Patriot + HSB + RedEdr |
byovd_results.json |
HolyGrail driver analysis |
edr_<profile>_results.json |
one per dispatched EDR profile (kind: elastic or kind: fibratus) |
_summary_cache.json |
mtime-validated dashboard payload (auto-generated) |
LitterBox host EDR-instrumented Windows VM
βββββββββββββββββββββββββββββββββββ βββββββββββββββββββββββββββββββ
β ElasticEdrAnalyzer / β β Whiskers.exe (Rust HTTP) β
β FibratusEdrAnalyzer β ββHTTPββΊβ /api/info β
β ββ Phase 1 (sync) ββ β ββββββββ€ /api/lock/{acquire,...} β
β β get_info β β β /api/execute/exec (XOR) β
β β lock_acquire β β β /api/logs/execution β
β β exec (XOR'd) β β β /api/alerts/fibratus/... β
β β wait_for_exit β β β β
β β kill (idempotent)β β β β same VM β β
β β get_logs β β β β
β β lock_release β β β ββββββββββββββββββββββββ β
β ββββββββββββββββββββ β β β Elastic Defend agent β β
β β returns Phase 1 dict β β β OR β β
β β status=polling_alerts β β β Fibratus (ETW) β β
β ββ Phase 2 (daemon thread)βββ β β ββββββββββββββββββββββββ β
β β poll alerts every 2s β β β β β
β β early-return on first hit β β β Application event log β
β β settle window for bursts β β β (Provider=Fibratus) β
β β save final findings JSON β β β β β
β βββββββββββββββββββββββββββββ β ββββ Whiskers wevtutil-queriesβ
β β β β
β Frontend polls saved JSON β OR Elastic stack β
β every 2-15s (adaptive) β β HTTP to β
βββββββββββββββββββββββββββββββββββ ElasticClient.fetch_alerts
Two-phase split keeps the agent lock window tight: Phase 1 holds the lock through exec β log fetch β release (~1-7s typical); Phase 2 runs unlocked so back-to-back dispatches don't queue. Time-bounded queries keep concurrent runs from polluting each other.
See EDR Integration for the full discussion.
litterbox.py # admin-check + Flask app.run(); entry point
config/config.yaml # all paths, tool configs, timeouts, enable flags
app/
βββ __init__.py # create_app() β wires AnalysisManager + RouteHelpers
βββ helpers.py # RouteHelpers β load_analysis_data, calculate risk
βββ blueprints/ # one Flask blueprint per concern
β βββ upload.py # GET / (dashboard) + GET /upload + POST /upload
β βββ analysis.py # /validate, /analyze/*, /analyze/all, /analyze/edr,
β β # /holygrail, /whiskers
β βββ results.py # /results/<type>/<target>, /results/edr/<profile>/<target>,
β β # /summary, /files
β βββ doppelganger.py # /doppelganger
β βββ management.py # /cleanup, /health, DELETE /file/<target>
β βββ api.py # /api/results/..., /api/edr/..., /api/report/<target>
βββ services/
β βββ rendering.py # render_pid_results, render_file_results
β βββ summary.py # process_pid_summary, process_file_summary
β βββ summary_cache.py # mtime-validated per-sample cache
β βββ tool_check.py # check_analysis_tool, check_holygrail_tool
β βββ edr_health.py # TTL-cached agent reachability + background poller
β βββ error_handling.py # @error_handler decorator
βββ utils/
β βββ file_io.py # FileTypeDetector, save_uploaded_file, get_pe_info
β βββ validators.py
β βββ path_manager.py # find_file_by_hash (mtime-cached)
β βββ risk_analyzer.py # RiskCalculator + calculate_risk
β βββ forensics.py # SecurityAnalyzer (MalAPI), entropy
β βββ json_helpers.py
β βββ reporting.py # generate_html_report
βββ analyzers/
β βββ base.py # BaseAnalyzer + BaseSubprocessAnalyzer
β βββ manager.py # AnalysisManager β parallel static, parallel dynamic + serial hsb
β βββ blender.py # system-process baseline comparison
β βββ fuzzy.py # ssdeep-style fuzzy matching DB
β βββ holygrail.py # BYOVD driver analysis
β βββ static/ # yara, checkplz, stringnalyzer
β βββ dynamic/ # yara, pe_sieve, moneta, patriot, hsb, hollows_hunter, rededr
β βββ edr/ # NOT a subprocess β talks to remote Whiskers + alert source
β βββ profile.py # EdrProfile dataclass + load_profiles
β βββ agent_client.py # AgentClient β Whiskers HTTP API
β βββ elastic_client.py # ElasticClient β security alerts indices
β βββ elastic_edr_analyzer.py # kind=elastic orchestrator
β βββ fibratus_edr_analyzer.py # kind=fibratus orchestrator
β βββ registry.py # init() + dispatch_split() β kind dispatch
βββ templates/
βββ base.html, dashboard.html, upload.html, agents.html,
βββ analyze_all.html, edr_info.html, results.html, file_info.html,
βββ β¦
Vanilla JS, ES6 modules, no bundler. Loaded via <script type="module">.
app/static/js/
βββ base.js # universal β sidebar, modals, status, cleanup
βββ summary.js # /summary page
βββ blender.js, fuzzy.js # /doppelganger tabs
βββ results/
β βββ core.js # AnalysisCore + DOMContentLoaded entry
β βββ managers.js # TabManager, PayloadManager, ModalHandler
β βββ tools.js # registry of per-tool modules
β βββ renderers.js
β βββ edr-saved.js # /results/edr/<profile>/<target> bootstrap
β βββ tools/ # one module per scanner β all consume `_shared.js` helpers
β βββ _shared.js
β βββ yara.js, checkplz.js, stringnalyzer.js
β βββ pe_sieve.js, moneta.js, patriot.js, hsb.js, rededr.js
β βββ edr.js # diff-aware re-render, lazy detail, adaptive poll
β βββ summary.js
βββ dashboard/core.js # / dashboard
βββ agents/core.js # /whiskers
βββ analyze-all/core.js # /analyze/all/<target>
βββ utils/ # escape, formatters, severity, fetch, modals, dom
All polling JS pauses on document.visibilityState === 'hidden' and resumes (with one immediate refresh) on visible.
Whiskers/ # separate Rust crate, single binary
βββ Cargo.toml, Cargo.lock
βββ README.md # install, CLI flags, endpoints, build-from-source
βββ src/
βββ main.rs # CLI: --port / --bind / --samples-dir / --install / --uninstall
βββ api/
β βββ info.rs # /api/info β hostname + telemetry_sources detection
β βββ lock.rs # single-occupancy gate
β βββ execute.rs # multipart exec, chunked-XOR write, rundll32 for DLLs
β βββ logs.rs # execution + agent log buffers
β βββ alerts.rs # /api/alerts/fibratus/since β wevtutil queries Application log
βββ state.rs # AppState + RunState
βββ file_writer.rs # chunked-XOR (64 KiB working buffer)
βββ agent_log.rs
Built with cargo build --release β target/release/Whiskers.exe (~1.6 MB, no runtime deps). See Whiskers Agent.
- π Home
- π§ Application Architecture
- π Dashboard
- π All in One Pipeline
- π― Detection Score Explained
- 𧬠Blender Scanner
- π FuzzyHash Scanner
- π‘οΈ HolyGrail BYOVD Scanner
- π YARA Rules Management