Malware Triage — 15 minute first verdict
You have a suspicious binary. Goal: in 15 minutes, decide CLEAN / SUSPICIOUS / MALICIOUS / NEEDS-DEEPER.
Phase 1: Static (5 min)
# 1. File format
file sample.bin
exiftool sample.bin # author / compile timestamp / version
# 2. Hash + reputation
sha256sum sample.bin
# Submit to: VirusTotal, MalwareBazaar, IntelX, Joe Sandbox, ANY.RUN
# Often the verdict already exists — saves you 14 minutes.
# 3. Strings — fast triage signal
strings -n 8 sample.bin | sort -u | head -100
strings -e l -n 8 sample.bin | sort -u | head -50 # wide (UTF-16) strings on Windows
# Suspicious strings to grep for:
strings sample.bin | grep -iE 'http|https|wmic|powershell|cmd.exe|temp|appdata|amsi|defender|reflectiveloader'
# 4. Format-specific: PE
peresearcher sample.exe # OR python pefile
python3 -c '
import pefile
p = pefile.PE("sample.exe")
print("Compile time:", p.FILE_HEADER.TimeDateStamp)
print("Sections:", [(s.Name.decode().rstrip("\x00"), s.SizeOfRawData, s.get_entropy()) for s in p.sections])
print("Imports:", [(e.dll.decode(), [i.name.decode() if i.name else hex(i.ordinal) for i in e.imports]) for e in p.DIRECTORY_ENTRY_IMPORT])
'
# 5. Entropy → packed?
python3 -c '
import math
data = open("sample.bin","rb").read()
counts = [data.count(bytes([b])) for b in range(256)]
total = len(data)
ent = -sum((c/total)*math.log2(c/total) for c in counts if c)
print(f"Entropy: {ent:.3f} / 8 — {'packed' if ent > 7.5 else 'normal'}")
'
# 6. YARA against canonical rulesets
yara -r /opt/yara-rules/ sample.bin
yara -r /opt/Neo23x0-signature-base/ sample.bin
Phase 2: Dynamic (5 min — in an isolated VM)
# Pre-flight (do this once, save snapshot)
# - Disconnected network OR use INetSim/FakeNet-NG to fake services
# - Procmon recording (Process / File / Network / Registry filters)
# - Wireshark capturing on the snapshot's network adapter
# - Fakedns / inetsim listening for DNS / HTTP / SMTP / FTP
# Detonate
cp sample.bin C:\tmp\sample.exe
# Right-click → Run as admin OR sample.exe in cmd
# Observe for 60-180 seconds, then take snapshot
# Then revert VM for next run
Things to look for
| Signal |
Verdict |
Writes to \AppData\Local\Temp then executes |
Likely dropper |
| Creates Run/RunOnce registry key |
Persistence |
| Schedules a task |
Persistence |
| Modifies firewall via netsh |
Defense evasion |
| Spawns powershell + LongStringEncoded |
Stage 2 |
| Network: HTTPS to a no-SNI IP |
C2 callback |
| DNS to a DGA-looking domain |
C2 callback |
| Reads process memory of lsass.exe / winlogon.exe |
Credential theft |
| Writes to userinit / shells / image-file-exec-options |
Persistence |
Touches \Microsoft\Cryptography\Defaults\Provider |
Cert injection |
Phase 3: Unpack (if entropy was high, optional 5 min)
# In dynamic VM, after detonation, dump memory:
# Scylla (UI) → attach to process, dump PE image
# OR PE-sieve (command-line):
pe-sieve.exe /pid 1234 /dir dumped
# OR DnSpy + DotNetReactorUnpacker for .NET
# OR de4dot for obfuscated .NET
# Then static-re the unpacked binary (Phase 1 strings/imports against the dump)
Phase 4: Verdict + handoff
| Verdict |
Indicators |
Next step |
| CLEAN |
Known-good hash, signed, expected strings/imports, no suspicious behavior |
Mark + move on |
| SUSPICIOUS |
Unsigned, low rep, mildly unusual imports/strings, no clear malicious behavior |
Sandbox 30 min longer, YARA against custom rules |
| MALICIOUS |
C2 callback, drops files, persistence, credential theft, packed + evades VMs |
IOC extraction, then deep RE (load reverser/ghidra/SKILL.md) |
| NEEDS-DEEPER |
High entropy, anti-analysis, custom-packed, no obvious signal |
Unpack first (Phase 3), then re-triage |
IOC extraction template
If MALICIOUS:
- Hashes (md5, sha1, sha256)
- C2 domains / IPs (from PCAP)
- Mutex names (Procmon: CreateMutex events)
- File paths created
- Registry keys modified
- YARA signature (generate from unique strings/code)
Tooling cheatsheet
| Stage |
Tool |
Use |
| Static (PE) |
pefile, capa, exiftool, Detect It Easy (DIE) |
Format + capability scan |
| Static (ELF) |
readelf, objdump, radare2 |
Format + symbols |
| Static (Mach-O) |
jtool2, otool, MachOView |
Format + symbols |
| Dynamic |
Cuckoo, CAPE, ANY.RUN, Joe Sandbox, Hatching Triage |
Automated sandbox |
| Network |
Wireshark, mitmproxy, FakeNet-NG, INetSim |
Traffic capture + fake services |
| Memory |
Volatility 3, PE-sieve, Scylla |
Memory forensics + unpacking |
| Disassembly |
Ghidra, IDA, Binary Ninja |
Full RE — see reverser/ghidra/SKILL.md |
| YARA |
yara, capa rules |
Signature matching |
References
- "Practical Malware Analysis" — Sikorski & Honig (still the canonical book)
- MITRE ATT&CK — for behavior → technique mapping
- Lenny Zeltser's "REMnux" — pre-built malware analysis distro
- DEFCON "Malware Forensics" track recordings
1---2name: reverser-malware-triage3description: Fast malware triage workflow — static (PE/Mach-O/ELF format, strings, imports, signatures, entropy/packed indicators), dynamic (sandbox with INetSim, Wireshark, Process Monitor, Procmon, time-shift), unpack (Scylla/PE-sieve), then full RE with Ghidra/IDA. Designed for ≤15 min initial verdict.4---56# Malware Triage — 15 minute first verdict78You have a suspicious binary. Goal: in 15 minutes, decide CLEAN / SUSPICIOUS / MALICIOUS / NEEDS-DEEPER.910## Phase 1: Static (5 min)1112```bash13# 1. File format14file sample.bin15exiftool sample.bin # author / compile timestamp / version1617# 2. Hash + reputation18sha256sum sample.bin19# Submit to: VirusTotal, MalwareBazaar, IntelX, Joe Sandbox, ANY.RUN20# Often the verdict already exists — saves you 14 minutes.2122# 3. Strings — fast triage signal23strings -n 8 sample.bin | sort -u | head -10024strings -e l -n 8 sample.bin | sort -u | head -50 # wide (UTF-16) strings on Windows2526# Suspicious strings to grep for:27strings sample.bin | grep -iE 'http|https|wmic|powershell|cmd.exe|temp|appdata|amsi|defender|reflectiveloader'2829# 4. Format-specific: PE30peresearcher sample.exe # OR python pefile31python3 -c '32import pefile33p = pefile.PE("sample.exe")34print("Compile time:", p.FILE_HEADER.TimeDateStamp)35print("Sections:", [(s.Name.decode().rstrip("\x00"), s.SizeOfRawData, s.get_entropy()) for s in p.sections])36print("Imports:", [(e.dll.decode(), [i.name.decode() if i.name else hex(i.ordinal) for i in e.imports]) for e in p.DIRECTORY_ENTRY_IMPORT])37'3839# 5. Entropy → packed?40python3 -c '41import math42data = open("sample.bin","rb").read()43counts = [data.count(bytes([b])) for b in range(256)]44total = len(data)45ent = -sum((c/total)*math.log2(c/total) for c in counts if c)46print(f"Entropy: {ent:.3f} / 8 — {'packed' if ent > 7.5 else 'normal'}")47'4849# 6. YARA against canonical rulesets50yara -r /opt/yara-rules/ sample.bin51yara -r /opt/Neo23x0-signature-base/ sample.bin52```5354## Phase 2: Dynamic (5 min — in an isolated VM)5556```bash57# Pre-flight (do this once, save snapshot)58# - Disconnected network OR use INetSim/FakeNet-NG to fake services59# - Procmon recording (Process / File / Network / Registry filters)60# - Wireshark capturing on the snapshot's network adapter61# - Fakedns / inetsim listening for DNS / HTTP / SMTP / FTP6263# Detonate64cp sample.bin C:\tmp\sample.exe65# Right-click → Run as admin OR sample.exe in cmd6667# Observe for 60-180 seconds, then take snapshot68# Then revert VM for next run69```7071### Things to look for7273| Signal | Verdict |74|---|---|75| Writes to `\AppData\Local\Temp` then executes | Likely dropper |76| Creates Run/RunOnce registry key | Persistence |77| Schedules a task | Persistence |78| Modifies firewall via netsh | Defense evasion |79| Spawns powershell + LongStringEncoded | Stage 2 |80| Network: HTTPS to a no-SNI IP | C2 callback |81| DNS to a DGA-looking domain | C2 callback |82| Reads process memory of lsass.exe / winlogon.exe | Credential theft |83| Writes to userinit / shells / image-file-exec-options | Persistence |84| Touches `\Microsoft\Cryptography\Defaults\Provider` | Cert injection |8586## Phase 3: Unpack (if entropy was high, optional 5 min)8788```bash89# In dynamic VM, after detonation, dump memory:90# Scylla (UI) → attach to process, dump PE image91# OR PE-sieve (command-line):92pe-sieve.exe /pid 1234 /dir dumped93# OR DnSpy + DotNetReactorUnpacker for .NET94# OR de4dot for obfuscated .NET9596# Then static-re the unpacked binary (Phase 1 strings/imports against the dump)97```9899## Phase 4: Verdict + handoff100101| Verdict | Indicators | Next step |102|---|---|---|103| **CLEAN** | Known-good hash, signed, expected strings/imports, no suspicious behavior | Mark + move on |104| **SUSPICIOUS** | Unsigned, low rep, mildly unusual imports/strings, no clear malicious behavior | Sandbox 30 min longer, YARA against custom rules |105| **MALICIOUS** | C2 callback, drops files, persistence, credential theft, packed + evades VMs | IOC extraction, then deep RE (load `reverser/ghidra/SKILL.md`) |106| **NEEDS-DEEPER** | High entropy, anti-analysis, custom-packed, no obvious signal | Unpack first (Phase 3), then re-triage |107108## IOC extraction template109110If MALICIOUS:111- Hashes (md5, sha1, sha256)112- C2 domains / IPs (from PCAP)113- Mutex names (Procmon: CreateMutex events)114- File paths created115- Registry keys modified116- YARA signature (generate from unique strings/code)117118## Tooling cheatsheet119120| Stage | Tool | Use |121|---|---|---|122| Static (PE) | pefile, capa, exiftool, Detect It Easy (DIE) | Format + capability scan |123| Static (ELF) | readelf, objdump, radare2 | Format + symbols |124| Static (Mach-O) | jtool2, otool, MachOView | Format + symbols |125| Dynamic | Cuckoo, CAPE, ANY.RUN, Joe Sandbox, Hatching Triage | Automated sandbox |126| Network | Wireshark, mitmproxy, FakeNet-NG, INetSim | Traffic capture + fake services |127| Memory | Volatility 3, PE-sieve, Scylla | Memory forensics + unpacking |128| Disassembly | Ghidra, IDA, Binary Ninja | Full RE — see `reverser/ghidra/SKILL.md` |129| YARA | yara, capa rules | Signature matching |130131## References132133- "Practical Malware Analysis" — Sikorski & Honig (still the canonical book)134- MITRE ATT&CK — for behavior → technique mapping135- Lenny Zeltser's "REMnux" — pre-built malware analysis distro136- DEFCON "Malware Forensics" track recordings