Skip to content

Triage processes

The Process section of Triage has one segmented control with three views, Process tree, Suspicious activity and Graph, the first two with their counts. The suspicious count is coloured by the worst tier among the rows. The eBPF section sits beside it. This page describes Antinomie 0.8.0, which is in development; the current release is 0.7.1.

Triage Process › Process tree of a real run: Process tree 4, Suspicious activity 5 and Graph; a filter box; the rows pid 105 cookie 2 with a red 4 chip running /tmp/triage-sample, pid 106 cookie 3 with a blue 1 chip running /bin/sh, pid 107 cookie 4 running /bin/sleep, and pid 105 cookie 5 marked parent not in this trace with executable ?, each with TID and first-seen time.
The process tree of a real run; the chip beside a process counts its suspicious observations. Antinomie 0.8.0, a recorded run.

The tree shows the run’s processes, drawn with tree-style branches. Columns: Process, Executable, TID, Argv, First seen, Last seen, Task outcome and Exec history.

  • A process is a new child when a fork, vfork, clone or clone3 creates one. A clone with CLONE_THREAD is a thread and stays inside its parent. A clone3 whose flags were not captured creates no parent and child edge.
  • Executable is the latest successful captured exec path, and Exec history keeps earlier ones. When an exec’s path was not captured, the process is named by the image the guest says it loaded, never by its parent’s; with neither it reads ?. Task identity uses the task cookie, not the PID alone, so a reused PID does not merge two processes.
  • A task whose parent was not recorded says parent not in this trace.
  • Task outcome is how the task ended, separately from the run’s tree status.
  • A process with suspicious observations shows their count as a small chip in its Process cell, coloured by the worst tier among them (HIGH red, MEDIUM amber, LOW cyan). Click the process to open Suspicious activity filtered to it. Filter on it with process.suspicious > 0 or process.worst_tier == high.
  • A filter leaves a tree of the remaining rows. Sorting makes the list flat, and restoring recorded order brings back the indentation.
  • The task identity count on Summary includes threads; it is not a process count.

A run that lived through a transport reconnect is read whole: its recording segments are read oldest first into one tree.

Select a process to see in Details its Suspicious observations (up to 12, each with its tier, rule and summary; click a rule to open its syscall in Syscall Trace), or None recorded for this process., and three jumps:

Button Opens
Filter Trace to this process Syscall Trace filtered to this process (process.cookie == N, or process.pid == N without a cookie)
Files it touched Files → Opened files filtered to process.pid == N
Suspicious activity Suspicious activity filtered to process.pid == N; disabled when the process has none

Suspicious activity lists behaviour recognised in the run’s system calls, kernel records and packets. Each row is an observation to investigate, not a verdict that the sample is malicious.

Suspicious activity of a real run: the tier chips HIGH 2, MEDIUM 1, LOW 2 and Show INFO 3, the thirteen category chips with icons, Show hidden 0, and 1-5 of 5 matched; rows memory.rwx high Defense evasion / anti-analysis, privilege.setid_bit high Privilege escalation, process.interpreter low Execution in sh, bpf.program medium Rootkit, and bpf.seccomp_filter low Defense evasion / anti-analysis, each with its time and process.
Five observations of a real run, with their tiers and categories. Antinomie 0.8.0, a recorded run.

Antinomie 0.8.0 has 136 rules (0.7.1 has 134; 0.8.0 adds credential.canary_used and credential.cloud_credentials for the cloud VPS profiles). Each rule has:

  • a tier: HIGH, MEDIUM, LOW or INFO, how unusual the behaviour is for ordinary software;
  • a category, what the behaviour is for, one of thirteen;
  • the ATT&CK techniques (and detection strategies) it maps to, in the Source column, such as MITRE ATT&CK T1620 · DET0300.

See Tiers and categories and every rule in Suspicious activity rules.

Repeats fold into one row with a Count, a failed attempt or a program that does the thing as its job lowers the tier by one, and activity outside the run’s tree is hidden. Details says why a row has its tier. See Noise handling.

Column Shows
Time When the row was first seen (shown first)
Rule The rule id, such as memory.rwx
Tier The row’s tier after context
Category Such as Defense evasion / anti-analysis
Process The process name with its PID and TID
Summary What was observed
Count How many matches folded into the row
Source The ATT&CK reference, or Observed behaviour; no ATT&CK technique
Confidence high when the call’s entry and exit were completely recorded, limited otherwise
Evidence The call (or packet) to open
Version The rule’s version
Outcome Such as 3 succeeded or a failed result
Chip Does
HIGH, MEDIUM, LOW With none selected, all show. Click one to show only that tier; click others to add or remove them. Each shows its count.
Show INFO INFO matches are always counted; their rows are built only when this is on. The calls stay in the recording either way.
Category chips Execution, Persistence, Privilege, Evasion, Credentials, Discovery, Injection, C2, Rootkit, Impact, Collection, Lateral, Exfiltration, each with the icon its markers have in the graph. Selecting works as for tiers.
Show hidden (Show hidden / capped) Shows the rows hidden because the process is outside the run’s tree. Its tooltip also says how many frames of VM housekeeping the built-in suppression list skipped.

Evasion lists the anti-analysis checks the sample made through system calls (machine identity, CPU, MAC address, uptime, TracerPid, container markers, long sleeps) with the answer the guest gave, and a heuristic note on what the sample did in the next 30 seconds. CPUID and RDTSC checks run inside the program, leave no system call and are not visible.

A memory.rwx row selected; Details shows Rule memory.rwx, Tier high, Category Defense evasion / anti-analysis, Process Unknown (55 / 55), Summary mmap with prot 0x7, Count 3, Source MITRE ATT&CK T1620 · DET0300, Time, Confidence limited, Evidence syscall mmap call 0, Version 2 and Outcome 3 succeeded; below, Occurrences: calls 0, 1, 2 (3 in all), Why this tier: Rule tier high (memory.rwx), a folded Observed fields and Open original syscall.
Why this tier, the occurrences behind a folded row, and the way to its evidence. Antinomie 0.8.0, synthetic data.

Click a row to read it in Details: every column, the Occurrences behind a folded row, Why this tier (the rule’s tier and every change, with the reason), the observed fields and Open original syscall. Double-click a row to open its call in Syscall Trace, or its packet in Network for a row found in packets. Filter fields are in Triage table filters.

A matched indicator of compromise appears here too, as c2.ioc_match, so it shows in the graph and the Summary. See Network.

Tools → Settings… → Notifications → Toast for live HIGH findings (off by default in 0.8.0) raises a toast for the first HIGH finding of each rule while a run is still going. See The workspace.

Graph draws the same findings on process swimlanes against time. It shows exactly what the Suspicious activity table is filtered to: it shares the filter bar and the tier and category chips.

The Graph view of a real run: the chips, Open in window, Legend and 5 findings · 4 lanes; an escalation phase band, a severity curve and heat rows for Execution, Privilege, Evasion and Rootkit; lanes triage-sample 105 with evasion, privilege, rootkit and evasion markers, sh 106 with an execution marker, and sleep 107, with spawn lines from parent to child.
The activity graph of a real run. Antinomie 0.8.0, a recorded run.
  • Lanes follow the process tree; ▾ and ▸ fold a subtree, and many leaf siblings of one program fold into one name ×N lane. A lane for activity not tied to a process is labelled VM-wide / not tied to a process.
  • Markers take their colour from the tier (HIGH red, MEDIUM amber, LOW cyan, INFO grey) and carry the category’s icon, so colour is never the only cue. A hollow disc means only packets showed the finding. With many findings in view they become plain tier dots.
  • Above the lanes are the phases of the run (recon, download, persistence, escalation, hide/inject, C2, spread, impact; a stretch needs one HIGH, a MEDIUM with a LOW, two MEDIUMs or five LOWs), a severity curve (HIGH counts 10, MEDIUM 4, LOW 1, scaled to the tallest bar in view) and a heat strip with one row per category.
  • Thin lines join a parent to the processes it started, and a red arrow joins an injecting process to its target.
  • Legend explains every colour, icon, edge and band.
A dense activity graph of 24 process lanes, p0 1000 to p23 1023, with a VM-wide / not tied to a process lane on top, phases impact, persistence, recon, persistence, C2 and escalation, a busy severity curve and a heat strip with all thirteen categories, folded subtrees marked with triangles, and a 52.3 s break on the time axis.
Many processes and findings: subtrees fold, and quiet stretches are squeezed. Antinomie 0.8.0, synthetic data.

Hover a marker for a card with a tier chip, the rule, what it did and when, the process, count and outcome. Click it to select the row (Details follows, and the table scrolls to it), and double-click or press Enter for its first evidence. Click a lane name to keep only that process (Shift: and its descendants); click a phase to keep only its time range. Drag across the time axis to keep a time range, and press Escape to lift it.

Spacing: Events | Time (bottom right, or T) chooses how the time axis is laid out. Events, the default, gives every distinct moment a finding happened at one slot of equal width, so a burst of findings in a few milliseconds is as wide as the same number of findings spread over minutes; a slanted break mark and the length of the gap show where a long stretch with nothing in it was squeezed. Time is the true scale. Run (or R) shows the whole run and Fit (or F) goes back to the findings. Under the axis, the overview ruler shows every finding of the whole run with the stretch the graph shows as a window on it: drag the window to pan, drag its wide grips to zoom, drag across an empty part to show that stretch, and double-click the ruler to show the whole run.

A sparse activity graph: dropper 1201, sh 1202, curl 1203 and .x 1204, with execution, persistence, C2, evasion and injection markers, an injection arrow from .x to sh, a C2 phase band, and a 19.0 s break mark on the time axis between +5 s and +24 s.
Events spacing: a 19-second quiet stretch is squeezed into one slot and labelled. Antinomie 0.8.0, synthetic data.

Mouse: the wheel scrolls the lanes, Shift+wheel or a drag pans, Ctrl+wheel or a pinch zooms at the pointer, and a double-click on the axis zooms 2×. Keyboard (click the graph first): ← and → previous and next finding in time, ↑ and ↓ lane, Enter evidence, T spacing, F fit, + and - zoom at the selection, Space folds the lane, H M L I toggle the tier chips and Show INFO, and 1…9 and 0 the first ten category chips.

Open in window opens the graph in its own resizable window, one per run, with the same filter bar and chips and Details beside the graph.

The Graph view with the chips and three findings on three lanes, pid 60, pid 61 and pid 62, each one red evasion marker with a count of 4, the Equal spacing · guest time label and Spacing Events, Time, Run and Fit.
Repeats fold into one marker with a count. Antinomie 0.8.0, synthetic data.

At the right of the Triage tab bar, the Process, Files and Network sections show one refresh status, such as Refreshed 12 s ago · every 5 s. Its menu has Refresh now and the Every interval (1 to 300 s). A live run’s index is read again at that interval while Triage is on screen, and only if the recording grew. In a narrow pane the status moves under the tab bar.

The eBPF section lists captured BPF programs, classic socket filters and seccomp filters with columns Time, Observation, Outcome and Evidence. This section keeps its own Refresh and Every row.

Triage eBPF of a real run: Refresh, Every 5 s, Refreshed 42 s ago, and two rows: Loaded program fd 3 · bpf(BPF_PROG_LOAD) in tid 105, returned 3, call 84; and Seccomp installation successful · seccomp(SECCOMP_SET_MODE_FILTER) in tid 105, returned 0, call 93.
A BPF program load and a seccomp filter in a real run. Antinomie 0.8.0, a recorded run.

An observation says what happened: a program load, each way a program is attached (BPF_PROG_ATTACH, BPF_LINK_CREATE, BPF_RAW_TRACEPOINT_OPEN, or PERF_EVENT_IOC_SET_BPF on an earlier perf_event_open), a detach, a socket attachment, or a seccomp installation, in order, so the table reads load then attach for the same program. An attach row names the attach type, the target (the tracepoint name, kernel symbols, cgroup or interface, perf event), the program and the call that loaded it, and the result; a target the recording did not capture is shown as not captured, never guessed.

The eBPF section with four rows: Loaded program fd 3 · bpf(BPF_PROG_LOAD), a seccomp installation, Load failed (-13) · bpf(BPF_PROG_LOAD), and a prctl(SECCOMP_MODE_FILTER) installation; the first row selected and shown in Details as a BPF observation with Observed fields and Open original syscall.
A failed load stays distinct from a successful one. Antinomie 0.8.0, synthetic data.

In 0.8.0 the BPF view also lists the union bpf_attr members of each bpf call, decoded by the command that passed them, and takes a load’s instruction count and an attach’s program descriptor from them, so an attach of a program the run loaded says so (Program loaded in call N; this is its attach.).

New in 0.8.0

Select a row for Details: the decoded instructions with helper names and explanatory pseudocode, and Export binary and JSON for an exact raw export. Failed attempts and missing observations stay distinct from successful operations. When there were none, the section says No bpf syscall, classic socket filter, or seccomp install was recorded.