Home / Learning paths

Triage a reproducible benign artifact

Produce a structured observation record without extracting or executing the contents.

Audience: beginning malware-analysis and DFIR learners. Prerequisites: a terminal, JSON familiarity, and Python 3.9 or later; no third-party packages. Planning time: 15–20 minutes. Executed with Python 3.13.12 on Linux; fixture and validator version 1.0, reviewed 2026-09-09.

The artifact is an authored ZIP containing one plain-text note. The source fixes the entry name, timestamp, permissions, storage mode, and bytes so it can be regenerated. A URL and the word powershell are text observations; their presence does not demonstrate a network connection or interpreter execution.

Inputs and provenance

Download triage.py, the benign fixture.zip, and expected.json. No live sample or external upload is part of this exercise. The distributed ZIP is 245 bytes; its SHA-256 is:

77c380a3c4ab35efe50964b9c97db8bbbe27c49f96a65ee92b63c7c24f676cbb

A matching digest checks byte identity against this published fixture. It does not prove that an arbitrary file is safe or that a publisher is trustworthy.

Workflow and corroboration

  1. Inspect the script. It accepts only the expected stored entry, bounds file and entry sizes, and reads into memory. It never extracts entries or evaluates their text.
  2. Run the inspection and controls below.
  3. Regenerate into a new filename. Generation refuses to overwrite an existing file. Compare both observation records and hashes.
  4. On Linux, independently run sha256sum fixture.zip and unzip -l fixture.zip; the archive listing should show one notes.txt entry, 129 bytes, dated 2026-01-01. These commands inspect this supplied benign fixture.
python3 triage.py fixture.zip
python3 triage.py --self-test
python3 triage.py --generate regenerated.zip
python3 triage.py regenerated.zip

Expected structured observation

{"bytes": 245, "entries": ["notes.txt"], "execution_observed": false, "format": "ZIP (stored)", "sha256": "77c380a3c4ab35efe50964b9c97db8bbbe27c49f96a65ee92b63c7c24f676cbb", "strings": ["example.invalid", "powershell"], "text_bytes": 129}

The format, length, archive entry, and exact content are checked. execution_observed: false describes this static workflow's visibility, not proof of the absence of behavior in another environment.

Failure and negative cases

{"negative_controls_rejected": 3, "positive_fixture_passed": true}

The self-test rejects a traversal entry name, changed content with an invalid CRC, and non-ZIP bytes. It creates those controls in memory and extracts none. Unexpected compression, oversized entries, wrong content, missing files, and malformed archives stop validation with an error; an error is not a malware verdict. An identical hash with a different observation record indicates a tool or environment discrepancy that requires investigation.

Limitations and next step

This deliberately narrow validator recognizes one known fixture. It is not a general archive scanner, sandbox, malware classifier, or a safe parser for arbitrary hostile samples. Static strings suggest questions; they do not demonstrate execution, persistence, or attribution. Keep this provenance and observation record with a separate hypothesis and a safe corroboration step.

Continue the malware-triage path and the analysis guide. Adapt the observation schema to another approved benign artifact before considering any separately authorized dynamic analysis.

References

Follow My Work

Research RSS · About the author · GitHub.