One command. Every program execution on a machine, in order, in a CSV.
A disk image, a triage package or a folder of logs in. One UTC timeline of what ran, when, as whom and from where out. Windows and Linux, one binary, nothing to install.
caarea -f workstation.E01 -o workstation.csv --hunt
One run over two hosts of the lab: the triage of a Windows Server (event logs, scheduled tasks, Defender, Windows Error Reporting, PowerShell history) and an Ubuntu host (journal, syslog, cron, package logs). One timeline, 6,115 rows, and the hunt closes with the rows that deserve reading first, each with its reason in words: a beacon run from
Users\Public, a service whose binary is cmd.exe, a cron job running from /tmp, and two pointers it says are only pointers.
- Windows and Linux in the same timeline. A KAPE zip from the file server and a UAC tarball from the web server end up in one CSV, sorted together, each row stamped with its host. Images, triage packages, loose folders and single files mix freely. What it reads →
- Reads the sources others skip. Volume Shadow Copies inside E01 and virtual disks, dirty registry hives (their transaction logs replayed in memory), Prefetch including the compressed Windows 10/11 format, SRUM, Jump Lists, the Windows Timeline, the WMI repository, PowerShell history and ScriptBlock logs, Sysmon, AppLocker;
pacct,auditd, the binary systemd journal, package managers, containers, shell histories. Sixty-odd sources in all. - Recovers what was deleted. Freed registry cells and unused
$MFTrecords are read by default;--carvescans the raw bytes of images, live volumes and pagefiles for hives, event log chunks, MFT and journal records and Prefetch files that no file system points to any more. Carving → - Hunts when you ask.
--huntrebuilds the process tree of every host and marks what contradicts the documented boot and logon tree, the parents that never create shells, dead creators, look-alike and generated names, binaries in folders they do not belong to. Each mark carries its ATT&CK technique, its lineage, and a score that is the measured rarity of the pattern on clean hosts, not the author's confidence. Process hunting → - Gets the time right. Every timestamp is UTC. Linux logs that only carry wall-clock time are corrected with the host's own zone, found in the evidence. Time zones →
- Tells you where a row came from. Events that only exist in a shadow copy are tagged with the snapshot time; a freed cell says
deleted; a carved record sayscarvedand at which byte. A live event and its recovered twin are never shown twice. - Treats evidence as hostile. Archives are unpacked into an isolated, per-run folder; entries cannot escape it, symlinks are never followed, nothing is ever written into the evidence.
Download the binary for your platform from the Releases page, or build it:
git clone https://github.com/jupyterj0nes/caarea.git
cd caarea
cargo build --release # binary in target/release/caarea[.exe]| You have | Run |
|---|---|
| A disk image (E01, Ex01, raw, dd) or a virtual disk (VMDK, VHD, VHDX) | caarea -f disk.E01 -o out.csv |
| A running Windows host (triage in place, as administrator) | caarea -f \\.\C: -o out.csv --stage-dir D:\case\extracted |
| Triage packages (KAPE, Velociraptor, UAC, Cortex XDR, CyLR), zipped or not | caarea -d /path/to/packages -o out.csv |
A folder you collected by hand (winevt\Logs, /var/log, ...) |
caarea -d /path/to/folder -o out.csv |
Single files (an EVTX, a hive, an audit.log) |
caarea -f Security.evtx -f SYSTEM -f audit.log -o out.csv |
| The six hours around the moment of interest | caarea -d triage -o out.csv --toi 2026-09-24T12:00:00Z --toi-window 6 |
Add --hunt to any of them. Add -m evtx, -m registry, -m windows or -m linux to run one parser family only, --overwrite to replace an existing CSV. Every flag: command reference.
One RFC 4180 CSV with nineteen columns: fourteen that describe the event and the analysis tail that masstin, faramir and allymacb close their timelines with (hunt, hunt_score, hunt_why, verdict, notes). The fourteen sit in the verticals of masstin's timeline, each under the masstin column closest in meaning (time, host, event type, id, how the row was obtained, who it ran as, the image, its parent, who ran it, the process id, the command line, the file it was read from; two reserved_ columns where masstin's domains have no execution equivalent), so the four timelines of one case read side by side and a case tool maps each header once. Timestamps are UTC with a fixed width, so sorting the text sorts the time. Open it in Timeline Explorer or Excel.
timestamp,computer,artifact,event_id,state,target_username,reserved_1,processname,parentprocessname,subject_username,reserved_2,pid,commandline,source_file,hunt,hunt_score,hunt_why,verdict,notes
"2016-09-21T03:41:02.560546Z","IE10Win7","evtx:4688",4688,"live","","","C:\Windows\duKhLYUX.exe","","WORKGROUP\IE10WIN7$","",3744,"C:\Windows\duKhLYUX.exe","metasploit-psexec-native-target-security.evtx",,,,,
"2026-10-28T22:01:03.000000Z","rf-1a182f1b960-leo-lnx01","linux:syslog:sudo",0,"live","root","","/usr/bin/tee","sudo","c00pr","",0,"/usr/bin/tee /etc/cron.d/caarea","lnx01-logs:var/log/auth.log",,,,,artifact names the source, state says how the row was obtained (live, vss, deleted, txlog, carved), source_file the file it was read from inside its container (disk:partition_0_vss_0/Windows/System32/winevt/Logs/Security.evtx). Every column, with the rules of the tail: the CSV →
| Sources | |
|---|---|
| Windows event logs | Security (4688/4689, boot marker 4608, services, tasks, log cleared), System (7045, 7034, 7036, Kernel-General 12, MsiInstaller), Application (WER), Sysmon 1/5/6/7/11, PowerShell 400/800/4103/4104, TaskScheduler, WMI-Activity, AppLocker, Defender, Shell-Core, BITS |
| Windows file artifacts | Prefetch, SRUM, Amcache, Jump Lists and Recent\*.lnk, Windows Timeline, PowerShell console history, task XML, WER reports, Defender and PCA logs, the WMI repository, RecentFileCache.bcf, Syscache.hve |
| Registry | BAM/DAM, ShimCache, services, Run keys, TaskCache, IFEO / Winlogon / AppInit, UserAssist, RunMRU, RecentDocs, MUICache, FeatureUsage, CapabilityAccessManager, Office TrustRecords; dirty hives repaired from their logs, freed cells included |
| NTFS | $MFT (binaries and scripts written outside the system folders, resident script content quoted, freed records) and $UsnJrnl:$J (every Prefetch rewrite, drops, renames, deletions, log truncation) |
| Linux | pacct, audit.log, the binary systemd journal, auth.log / secure / syslog / cron, shell and REPL histories, dpkg / apt / dnf / pacman / zypper, cron and systemd units and timers, wtmp / btmp, Docker / containerd / podman, cloud-init, web server access logs, UAC process listings |
| Containers of all that | E01 / Ex01, raw, VMDK, VHD / VHDX, live volumes, every Volume Shadow Copy, ext2/3/4 and XFS partitions, plain or inside LVM2, KAPE / Velociraptor / UAC / Cortex XDR / CyLR packages, zips and tarballs nested five deep |
Event ids, keys and the notes on each source: What it reads →
--hunt runs the rules over the finished timeline and fills the tail of each row it judges: hunt is significant or candidate (or habitual when a clean reference host executes the same thing), hunt_score is how rare the row is on masstin's scale, 0 to 100, and hunt_why names every rule that fired, strongest first, then the lineage. The fourteen event columns do not change a byte. The detailed findings, with the catalogue score and the ATT&CK technique of every hit, go to a second CSV next to the timeline, and the console closes with the rows that deserve reading first: state, score, when and what ran, who created it, every rule that fired and, in words, why that matters. Rows that say the same thing (the same process, the same rules) are one entry with a count.
The rules only state what a documented source states: the expected-parent and allowed-children tables come from the SANS Hunt Evil poster and Elastic's parent-child rule. A rule's points are not chosen either: they are how often its pattern fires on stock, clean hosts, measured by a script and recorded with the corpus, and a row a clean host also produces is vouched for whatever its rules say. The rule catalogue, the process tree behind it, the measurement and its limits: Process hunting →
| Topic | Where |
|---|---|
| Every source, with event ids, keys and the notes on each | docs/sources.md |
| The nineteen columns in masstin's verticals, the analysis tail, how to read the CSV | docs/csv-format.md |
Process hunting: rules, process tree, how hunt_score is measured, the clean reference |
docs/hunting.md |
| Carving: what is looked for in raw bytes and how a structure proves itself | docs/carving.md |
| Time zones of Linux logs | docs/time-zones.md |
| Every command-line option | docs/cli.md |
| What is done and what is next | ROADMAP.md · CHANGELOG.md |
caarea --help lists every flag.
cargo test runs 161 tests: real-layout records for every binary format, real auditd lines, the public TZif files of two zones, safety tests that try to break out of the staging folder, and the identities the clean reference is matched by. Beyond them, the parsers were checked against:
- 524 public EVTX samples (EVTX-ATTACK-SAMPLES, EVTX-to-MITRE-Attack, DeepBlueCLI): the count per file matches
Get-WinEventexactly for every supported event id. - The registry test corpus of yarp: the transaction log replay (in the shared blockcarve crate) gives the same hive bins as Windows 10 and Windows 7 when they recovered those dirty hives themselves.
- Real
pacctfiles, Ubuntu 24.04 logs, an NTFS volume image produced on a Linux box and a 50 GB Windows workstation VMDK (dirty SYSTEM, SOFTWARE, DEFAULT and Amcache hives replayed from their logs). - The hunt, against two clean lab hosts collected live (nothing flagged once the clean reference is in) and a third one with eight executions and a WMI consumer planted by
scripts/lab/plant.ps1: five of the nine found, no unplanted row flagged, the four misses named as rule gaps.
The TaskScheduler operational channel is off by default on Windows clients and no public corpus has it; scripts\gen_taskscheduler_sample.ps1 turns it on, creates and runs a harmless task, exports the channel and runs CAAREA on it.
- BitLocker volumes are detected and skipped; decrypt first.
- btrfs partitions are not read yet;
hiberfil.sysis scanned raw, its compressed pages are not decoded. - Classic syslog has no year; it is inferred from the file's modification time, so logs spanning more than a year lose precision.
- On a Windows host with the default audit policy there is no 4688 at all, and without command-line auditing the command line is empty; the hunt's genealogy rules need one of Security 4688, Sysmon 1, auditd or
pacct.
CAAREA is one of four Rust tools that write the same kind of timeline and close it with the same analysis tail, so one case tool reads them all: masstin answers who logged in where, faramir what persists, allymacb what the file system did, and CAAREA what ran. They share the blockcarve scanner for raw bytes and vshadow-rs for shadow copies.
CAAREA stands for Chronological Artifacts & Activity Reconstruction Engine for Analysis, and is named after the carea leonés, the herding dog of León, the way masstin is named after the mastín. It builds on stable Rust with a plain cargo build --release and ships as one static binary for Windows, Linux and macOS. Internal DFIR research tool by jupyterj0nes; issues and pull requests are welcome.