Skip to content

Lab 05 — Dynamic Analysis — Behavioural

Hands-on lab · ← Back to the module concept

Setup

git clone https://github.com/plaintext-security/plaintext-labs
cd plaintext-labs/malware/05-dynamic-behavioural
make up
make fetch-sample      # pulls a real XorDdos ELF from MalwareBazaar into the isolated container
make demo

⚠ This lab DETONATES a live Linux malware sample. Handle it accordingly. - Authorization & isolation. Only run malware in an environment you own and have isolated. This lab executes the sample under strace — that detonation must stay inside the network-denied lab container (docker-compose.yml sets internal: true, so there is no route off the host). Never run the sample on your host, on a shared machine, or in any container with internet access. - The failed C2 is the point. Because the network is denied, XorDdos's connect() to its C2 on port 3306 fails in the trace — that failure is the teachable artifact, and it is what keeps the detonation safe. Do not "fix" networking to make it succeed. - Hygiene. The sample is fetched at lab time (password-protected zip, password infected) and is never committed.gitignore covers samples/. make fetch-sample needs a free abuse.ch Auth-Key (set MB_AUTH_KEY). - Offline fallback. No key / MalwareBazaar unreachable? Skip make fetch-sample; make demo falls back to the bundled synthetic target (compiled from data/target.c), which emits the same high-signal syscalls — a credential read, init.d/cron persistence writes, an argv spoof, and a failed connect() to :3306 — without being malicious.

Scenario

A compromised Linux server is throwing outbound traffic and won't stay clean after a reboot. IR pulled an unpacked ELF off it; static analysis was thin. You suspect XorDdos — a real Linux DDoS trojan that Microsoft Threat Intelligence dissects in "Rise in XorDdos". The team lead wants a behavioural trace: what files does it touch, how does it survive a reboot, and does it phone home? Detonate it under strace inside the isolated container, then map the observed syscalls back to the behaviours Microsoft documents: persistence drops under /etc/init.d plus a cron entry that re-runs every three minutes, an argv/process-name spoof (it overwrites its command line with something like cat resolv.conf), and an encrypted C2 connection on port 3306.

Throughout, the sample = the real XorDdos ELF that make fetch-sample drops in samples/ (path printed by the fetcher). In offline mode it is the bundled synthetic target (source in data/target.c, readable after the exercise), which approximates the same syscalls. Approach the trace as if you don't know what the binary does.

Do

Throughout, SAMPLE is the real ELF at /lab/samples/<sha256> (from make fetch-sample) or, in offline mode, the bundled ./target.

  1. [ ] Run strace against the sample and save the full trace.

    strace -o /lab/samples/trace.log -f -e trace=all "$SAMPLE"
    
    The -f flag follows child processes. Review the output size — how many syscalls were generated? (For the real XorDdos ELF, the trace is large; for the synthetic fallback it is small but covers the same high-signal calls.)

  2. [ ] Filter the trace for high-signal syscalls. Search the trace for: openat, connect, execve, clone, mmap, mprotect. For each one you find, record the syscall name, its arguments, and the return value. Specifically look for the XorDdos fingerprints Microsoft documents: openat/write to /etc/init.d and a cron path (persistence), the argv overwrite to a benign-looking command, and a connect() to port 3306 (C2).

  3. [ ] Run ltrace and compare with strace.

    ltrace -o /tmp/ltrace.txt "$SAMPLE"
    
    What library calls appear that were not obvious from the syscall trace? Do any libc functions correspond to the high-signal syscalls you found in step 2? (ltrace may be unavailable on arm64 — note that and rely on strace if so.)

  4. [ ] Map syscalls to the documented XorDdos behaviours and to ATT&CK. For each high-signal event, name the MITRE ATT&CK technique it represents and tie it to the matching behaviour from the Microsoft writeup: init.d/cron writes → persistence (T1037.004 / T1053.003), argv spoof → masquerading (T1036.004), connect() :3306 → C2 (T1071), /etc/passwd read → T1003.008, child execve → T1059.004. One sentence per event. Note whether the C2 connect() succeeded or failed, and why a failed connect in an isolated sandbox is still strong evidence.

  5. [ ] Read the Procmon CSV sample. Open data/procmon-sample.csv and answer: (a) which process was being traced? (b) what operations appear most frequently? (c) are there any registry or network events? Practice applying a mental filter: if this were a malware trace, which events would you investigate first?

  6. [ ] Write the behavioural report. In behavioural-report.md: timeline of key events from the strace (in time order), ATT&CK mapping for each, and a verdict — does this binary warrant escalation?

  7. [ ] Author a host detection from the timeline and prove it (the build half). The syscall timeline is detection-shaped — turn it into a rule. Pick the single highest-signal event (or short sequence) from step 2 — e.g. an execve of a shell, a connect to a non-loopback address, or an openat on a sensitive path — and author a detection for it: either a Sigma rule against the linux/process_creation (auditd) log source, or an auditd rule (auditctl -a ... -S execve -F ...). Then prove the two-sided result. Generate a positive: run the target under auditd (or feed your saved /tmp/trace.txt through your parser as the "malicious" log) and confirm your rule fires. Then generate a negative: run a benign command that touches none of your matched conditions (/bin/ls, cat /etc/hostname) and confirm the rule stays quiet. A rule that also fires on ls is keyed on a syscall every process makes — tighten the field match (the path, the argv, the destination) until only the malicious behaviour trips it. Reading the timeline and authoring a verified detection from it are equal halves. (Hint: Sigma's process_creation fields are CommandLine, Image, ParentImage; map your strace execve/connect arguments onto those. Validate the Sigma YAML parses with sigma check or by converting it with sigma convert.)

Success criteria — you're done when

  • [ ] Full strace output is saved and reviewed.
  • [ ] All high-signal syscalls are found, documented, and mapped to ATT&CK.
  • [ ] ltrace output is compared to strace output.
  • [ ] Procmon CSV is read and three events are annotated.
  • [ ] behavioural-report.md exists with a timeline and verdict.
  • [ ] You authored a host detection (Sigma or auditd rule) from the syscall timeline that fires on the malicious trace and stays quiet on a benign command — the build half, proven two-sided.

Deliverables

behavioural-report.md, parse_trace.py (see Automate & own it), the authored rule (behavioural.yml Sigma or behavioural.rules auditd) with the fires-on-malicious / quiet-on-benign proof recorded in the report. Commit all three.

Automate & own it

Required. Write parse_trace.py: a script that reads a strace output file (plain text, one line per syscall) and outputs a Markdown table of high-signal events (syscall name, arguments, return value, ATT&CK mapping). High-signal syscalls to flag: openat, connect, execve, clone, mmap with PROT_EXEC, mprotect. AI can draft the line parser and the regex extraction; you write the ATT&CK mapping dictionary manually (this is the learning — don't let the AI fill it in without you reading each technique).

AI acceleration

Pipe the strace output to an AI and ask for a behavioural summary. Then manually grep for connect and execve in the raw trace and check whether the AI mentioned them. If it missed any, add them to the report and note what the AI summary would have caused you to miss.

Connects forward

Module 06 extends dynamic analysis to the network layer — you will see the network-facing version of what the strace connect calls indicate here. The strace timeline and ATT&CK mapping you produce here are the inputs to a detection rule in Track 02 (Defensive Operations).

Marketable proof

"I run strace/ltrace against unknown Linux binaries, map syscall behaviour to MITRE ATT&CK, and produce a behavioural report that connects dynamic observation to a threat model."

Stretch

  • Add -tt (timestamps) and -T (syscall duration) to your strace command. Identify any syscalls with unusually long duration — what might a long sleep or read call indicate?
  • Convert your Sigma rule with sigma-cli to a concrete backend query (e.g. an Elastic or Splunk query) and note how the abstract process_creation fields translate into a real SIEM search — the hand-off your detection makes to Track 02 (Defensive Operations).

Comments

Sign in with GitHub to comment. Choose the type: Feedback (errors or suggestions on this page) · Hints (help for fellow learners — no spoilers) · General (anything else).