DFIR^:DFIR

strings & File Triage

Triage an unknown file or a blob of unallocated space: strings in depth (-n, -t x, -e l for UTF-16, piping into IOC regexes), file/magic bytes, xxd and hexdump, exiftool metadata, binwalk, carving with foremost/scalpel/photorec, bulk_extractor, hashing and ssdeep, PDF and Office maldoc checks, YARA — with the Windows equivalents (Sysinternals strings, Get-FileHash, certutil, Format-Hex) alongside.

intermediateupdated 2026-09-26strings / bstrings / Sysinternals strings.exe · file / libmagic · xxd / hexdump / Format-Hex · exiftool

strings & File Triage

Before a disassembler, before a sandbox, there is the ten-minute pass every unknown file gets: what is it really (file, magic bytes), what is written inside it (strings, in the right encoding), what does it carry (exiftool, binwalk, embedded objects), what does it match (hashes, ssdeep, YARA). The same tools, pointed at a memory image, a swap file or the unallocated blocks of a disk, become carving — pulling files and indicators out of space no filesystem points to. This card is those tools, Linux/macOS first with the Windows equivalent next to each, and the patterns that make strings output readable instead of a 40,000-line wall.

[!warning] Handle malware like malware Work on a copy, in a VM with no shared clipboard or network, with the file renamed to sample.bin so nothing double-clicks it. strings, file and exiftool do not execute anything — but binwalk -e, 7z x and PDF tools that render can trigger parser bugs. Snapshot first.

Identify: what is it really?

file sample.bin                          # libmagic: type, arch, linker, packer hints
file -b --mime-type sample.bin           # bare MIME
file -z archive.gz                       # look inside compressed
file -k sample.bin                       # keep going, report all matches (polyglots)
file *                                   # a whole directory, quickly
xxd sample.bin | head -4                 # eyeball the magic yourself
# Windows: no `file`, so read the magic
Format-Hex .\sample.bin -Count 32
certutil -dump .\sample.bin | Select -First 5          # for certs/PKCS
# or install: winget install GnuWin32.File / use TrID (trid.exe sample.bin)
Magic (hex)ASCIIType
4D 5AMZWindows PE (exe/dll/sys) — PE\0\0 follows at offset in 0x3C
7F 45 4C 46.ELFLinux/Unix executable
CF FA ED FE / CA FE BA BEMach-O 64-bit / universal (fat)
50 4B 03 04PK..ZIP — also docx/xlsx/pptx, jar, apk, ipa, odt
D0 CF 11 E0 A1 B1 1A E1OLE2 / CFB — legacy doc/xls/ppt, msi, msg
25 50 44 46%PDFPDF
7B 5C 72 74 66{\rtfRTF (CVE-2017-11882 territory)
1F 8Bgzip
42 5A 68BZhbzip2
FD 37 7A 58 5A 00.7zXZ.xz
37 7A BC AF 27 1C7z..'.7-Zip
52 61 72 21 1A 07Rar!..RAR
75 73 74 61 72 @257ustartar
FF D8 FFJPEG
89 50 4E 47 0D 0A 1A 0A.PNGPNG
47 49 46 38GIF8GIF
52 49 46 46RIFFWAV/AVI/WebP
53 51 4C 69 74 65SQLiteSQLite DB (browser history, Windows Timeline, mobile apps)
72 65 67 66regfWindows registry hive
45 6C 66 46 69 6C 65ElfFileWindows EVTX
4C 00 00 00 01 14 02 00L...Windows LNK
4D 41 4D 04 / 53 43 43 41 @4MAM. / SCCAPrefetch (compressed Win10 / raw)
EF BB BF / FF FE / FE FFUTF-8 BOM / UTF-16 LE / BE text
23 21#!script with shebang
4D 53 43 46MSCFCAB
43 57 53 / 46 57 53CWS/FWSFlash
00 00 00 xx 66 74 79 70ftyp @4MP4/MOV/HEIC
4B 44 4DKDMVMware VMDK
63 6F 6E 65 63 74 69 78conectixVHD
45 56 46 09 0D 0A FF 00EVFEnCase E01
4C 69 4D 45LiMELiME memory dump

[!tip] Extension lies, magic mostly doesn’t invoice.pdf.exe, report.docm renamed to .doc, a JPEG with a PHP webshell appended (file says JPEG, strings says <?php), a ZIP that is also a valid PDF. file -k and looking at both ends of the file (xxd | head, xxd | tail) catch most polyglots and appended payloads. Trailing data after the PNG IEND chunk or after the ZIP central directory is never innocent.

strings in depth

GNU strings (binutils) prints runs of printable characters ≥ 4 bytes. The defaults hide half of what a Windows binary contains.

strings sample.bin                        # ASCII (and single-byte) runs ≥ 4 chars
strings -n 8 sample.bin                   # minimum length 8 — cuts the noise dramatically
strings -a sample.bin                     # -a: scan the WHOLE file, not just loaded sections (default on modern binutils, be explicit)
strings -e l sample.bin                   # 16-bit little-endian = UTF-16LE: Windows API strings, paths, registry keys, PowerShell in .NET binaries
strings -e b sample.bin                   # UTF-16 big-endian (rare: Java, some Mac formats)
strings -e S sample.bin                   # single 8-bit incl. high-ASCII (Latin-1 lures, some packers)
strings -t x sample.bin                   # prefix each string with its hex offset (-t d decimal, -t o octal) → jump there in a hex editor
strings -t x -e l sample.bin | grep -i 'cmd\|powershell\|http'
strings -a -n 6 sample.bin; strings -a -n 6 -e l sample.bin    # ALWAYS run both — ASCII and UTF-16 — on Windows samples
strings -f *.bin                          # -f: print filename before each string (many files)
strings sample.bin | sort | uniq -c | sort -rn | head    # repeated strings = table entries, decoy padding
strings sample.bin | awk 'length > 60'    # long strings: base64 blobs, embedded scripts, URLs with parameters
PlatformEquivalent
macOSstrings is from LLVM/cctools: strings -a sample.bin; no -e l — use iconv/python below, or brew install binutils → gstrings -e l
WindowsSysinternals strings.exe -a -n 6 sample.bin scans ASCII and Unicode by default (-u Unicode only, -a ASCII only, -o offsets, -s recurse); bstrings (EZ Tools) adds regex and built-in IOC patterns — see EZ Tools
PowerShellSelect-String -Path sample.bin -Pattern 'http' -Encoding Unicode for a quick UTF-16 grep, or [IO.File]::ReadAllBytes + regex
AnyFLOSS (Mandiant floss sample.exe) — recovers obfuscated and stack strings from PE files that plain strings never sees; run it after strings disappoints
# UTF-16 strings on macOS/Windows-less environments without -e l
python3 -c "import re,sys;d=open(sys.argv[1],'rb').read();print('\n'.join(m.group().decode('utf-16le') for m in re.finditer(rb'(?:[\x20-\x7e]\x00){6,}',d)))" sample.bin

Making strings output useful: the IOC pass

Save the full output once (strings -a -n 6 sample.bin > s.txt; strings -a -n 6 -e l sample.bin >> s.txt) and grep the file instead of re-running.

S=s.txt
grep -Eio 'https?://[a-z0-9./?=_%:-]+' $S | sort -u                          # URLs
grep -Eo '\b([0-9]{1,3}\.){3}[0-9]{1,3}\b' $S | sort -u | grep -Ev '^(0|127|255)\.'   # IPv4 (drops version-number noise imperfectly — eyeball it)
grep -Eio '\b[a-z0-9.-]+\.(com|net|org|io|ru|cn|top|xyz|info|biz|onion|pw|cc|su)\b' $S | sort -u   # domains
grep -Eio '[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}' $S | sort -u                # emails
grep -Ei '\\\\[^\\ ]+\\[^\\ ]+' $S | sort -u                                   # UNC paths
grep -Ei 'HKEY_|HKLM|HKCU|CurrentVersion\\Run|Software\\Microsoft' $S | sort -u   # registry
grep -Ei '\.(exe|dll|bat|ps1|vbs|js|hta|scr|lnk|tmp|dat|log)\b' $S | sort -u   # filenames
grep -Ei 'C:\\|%APPDATA%|%TEMP%|\\Temp\\|\\Users\\|/tmp/|/dev/shm|/var/tmp' $S | sort -u   # paths
grep -Ei 'powershell|cmd\.exe|/c |-enc|-nop|-w hidden|IEX|Invoke-|DownloadString|FromBase64|wscript|cscript|mshta|rundll32|regsvr32|certutil|bitsadmin|schtasks|sc \|net user|whoami' $S   # LOLBins & PS
grep -Ei 'CreateRemoteThread|VirtualAlloc|WriteProcessMemory|NtUnmapViewOfSection|SetWindowsHookEx|IsDebuggerPresent|GetTickCount|CryptEncrypt|InternetOpen|WinHttp|URLDownloadToFile|ShellExecute|WinExec|RegSetValue|AdjustTokenPrivileges|OpenProcess|LoadLibrary|GetProcAddress' $S | sort -u   # suspicious imports
grep -Ei 'user-agent|mozilla/|accept:|content-type' $S                        # hardcoded HTTP client
grep -Ei 'password|passwd|pwd=|token|secret|api[_-]?key|BEGIN (RSA|OPENSSH|EC) PRIVATE|AKIA[0-9A-Z]{16}' $S   # credentials
grep -Ei 'mutex|Global\\|Local\\' $S                                           # mutex names → hunt on other hosts
grep -Ei 'pdb$|\.pdb\b|[A-Z]:\\Users\\[^\\]+\\(source|Desktop|Documents)' $S   # PDB path = developer username & project name
grep -Ei 'upx|aspack|themida|vmprotect|mpress|petite|\.packed|this program cannot be run' $S   # packer strings
grep -Eo '[A-Za-z0-9+/]{40,}={0,2}' $S | head                                  # base64 blobs → decode below
grep -Eo '[0-9a-f]{32}\b|[0-9a-f]{40}\b|[0-9a-f]{64}\b' $S | sort -u | head   # hashes / hex keys
grep -Eio '(bitcoin|btc|monero|xmr|wallet|\.onion|ransom|decrypt|your files)' $S   # ransomware notes
# Decode what you found
echo 'SQBFAFgAIAAoAE4AZQB3AC0ATwBiAGoAZQBjAHQA' | base64 -d | iconv -f utf-16le -t utf-8   # PowerShell -enc is UTF-16LE base64
echo 'aHR0cDov...' | base64 -d | file -                                                    # what is inside the blob?
printf '\x68\x74\x74\x70' | xxd; echo 68747470 | xxd -r -p                                 # hex ↔ bytes
python3 -c "import sys;print(''.join(chr(ord(c)^0x41) for c in open('blob','rb').read().decode('latin1')))"   # single-byte XOR guess
# Brute-force single-byte XOR / ROT / base64 layers: CyberChef "Magic" op, or `xortool -c 20 blob`, or `unxor`

[!tip] Strings are cheap for the attacker to fake Decoy strings (legitimate-looking URLs, fake PDB paths, whole English dictionaries) are common in packed samples. A binary with almost no strings, or only library boilerplate, is more suspicious than one full of them: it is packed or the strings are built at runtime — run FLOSS, or dump it from memory after it unpacks (see Volatility windows.dumpfiles / malfind).

Hex: xxd, hexdump, od, editors

xxd sample.bin | less                     # canonical: offset, hex, ASCII
xxd -s 0x3C -l 4 sample.bin               # -s seek, -l length: read the PE header offset
xxd -s -64 sample.bin                     # last 64 bytes (appended data?)
xxd -c 32 -g 1 sample.bin | head          # 32 bytes per line, grouped by 1
xxd -p sample.bin | head -c 200           # plain hex, no formatting (for grep / diff)
xxd -r -p hex.txt > out.bin               # hex → binary
hexdump -C sample.bin | head              # BSD-style canonical (macOS default)
od -A x -t x1z -v sample.bin | head       # od: hex offsets, 1-byte hex, ASCII, no * for repeats
cmp -l a.bin b.bin | head                 # byte-level diff; `vbindiff a b`, `radiff2 -x a b` for visual
dd if=sample.bin bs=1 skip=$((0x1000)) count=512 2>/dev/null | xxd | head   # cut a region
Format-Hex .\sample.bin -Offset 0x3C -Count 4
Format-Hex .\sample.bin | Select -Last 4
[BitConverter]::ToString((Get-Content .\sample.bin -Encoding Byte -TotalCount 16)) -replace '-',' '

GUI hex editors: HxD (Windows, free, huge files, disk/RAM editing, data inspector), ImHex (cross-platform, pattern language decodes structures for you, hex + entropy + strings + yara in one), 010 Editor (paid, binary templates for every format), hexyl (terminal, coloured). Registry hive, PE and NTFS record templates exist for all three — worth it when you need to read a structure by hand.

Metadata: exiftool

exiftool sample.jpg                            # everything: camera, GPS, timestamps, software, author
exiftool -G1 -a -s sample.docx                 # group names, all duplicates, tag names as they are in the file
exiftool -a -u -g1 -ee sample.pdf              # unknown tags, embedded streams
exiftool -gps:all -n photo.jpg                 # coordinates in decimal
exiftool -Author -Creator -Producer -CreateDate -ModifyDate *.pdf *.doc*       # who made the docs, with what
exiftool -r -csv -common -CreateDate -Author /mnt/img/home/*/Documents > docs.csv   # recurse, CSV for Timeline Explorer
exiftool -time:all -a -G0:1 -s sample.docx     # every timestamp incl. Office internal ones vs filesystem
exiftool -if '$gpslatitude' -r -p '$filename,$gpslatitude,$gpslongitude' .   # only geotagged files
exiftool -X sample.jpg > meta.xml; exiftool -j sample.jpg > meta.json
exiftool -all= copy.jpg                         # strip (never on evidence — for your own redaction)

What to read: Office Creator/LastModifiedBy/Company/RevisionNumber/TotalEditTime/Template (normal.dotm vs something odd), Application and AppVersion (a “2019 Word” doc from a 2010 build); PDF Producer/Creator (LibreOffice, Microsoft: Print To PDF, mPDF from a webapp, Ghostscript), CreateDate vs ModifyDate, XMP history; images Make/Model/Software/GPSPosition/DateTimeOriginal, thumbnail that does not match the image (edited photo); LNK/EXE exiftool reads PE version info (CompanyName, OriginalFileName — a svchost.exe whose original name is stealer.exe).

Archives, containers, embedded objects

# Office docs are ZIPs — look inside without Office
unzip -l sample.docx; unzip -p sample.docx word/vbaProject.bin | file -      # macro container present?
unzip -p sample.docx word/_rels/document.xml.rels | grep -io 'target="http[^"]*"'   # remote template injection
unzip -p sample.docx docProps/core.xml docProps/app.xml                      # metadata XML
7z l sample.bin; 7z x -osample_extracted sample.bin                          # 7z opens almost anything: zip, cab, msi, iso, vhd, wim, chm, pe resources
binwalk sample.bin                          # signature scan for embedded files (firmware, but also polyglots and stego)
binwalk -e sample.bin                       # extract them (into _sample.bin.extracted/)
binwalk -E sample.bin                       # entropy graph — flat high entropy = encrypted/compressed/packed
binwalk -R '\x50\x4b\x03\x04' sample.bin    # raw byte search with offsets
foremost -t all -i sample.bin -o carved/    # carve known types out of ANY blob (same tool as disk carving below)
# PE quick look (Linux) — imports, sections, entropy, timestamps
readpe -h sample.exe; readpe -i sample.exe | head -60      # pev
pescan sample.exe                                          # pev heuristics
python3 -c "import pefile;p=pefile.PE('sample.exe');print(p.FILE_HEADER.dump());[print(e.dll,[i.name for i in e.imports][:8]) for e in p.DIRECTORY_ENTRY_IMPORT]"
diec sample.exe                                            # Detect It Easy: compiler, packer, protector
# Windows GUI: pestudio (indicators, imports scored, strings, VT lookup), DiE, CFF Explorer, PE-bear

Documents: PDF and Office maldoc triage

# PDF
pdfid.py sample.pdf                          # counts of /JS /JavaScript /OpenAction /AA /Launch /EmbeddedFile /URI /ObjStm — any of the first five = open it further
pdf-parser.py -a sample.pdf                  # stats: objects by type
pdf-parser.py --search JavaScript sample.pdf # find the object
pdf-parser.py -o 12 -f -w sample.pdf         # dump object 12, filters applied, raw
pdf-parser.py --search /Launch sample.pdf; pdf-parser.py --search /URI sample.pdf
peepdf -i sample.pdf                         # interactive; `js_analyse` / `extract js`
qpdf --qdf --object-streams=disable sample.pdf out.pdf   # decompress everything so grep/strings work on it
strings out.pdf | grep -Ei 'javascript|/JS|/Launch|/URI|/EmbeddedFile|/OpenAction|cmd|powershell'

# Office (OLE and OOXML) — oletools
oleid sample.doc                             # summary: encrypted? VBA? XLM? external relationships? flash?
olevba sample.docm                           # dump macros + auto-exec triggers + suspicious keywords + IOCs table
olevba --decode --deobf sample.docm          # decode hex/base64/StrReverse, attempt deobfuscation
olevba --reveal sample.docm                  # macro source with obfuscated strings replaced
oledump.py sample.doc                        # streams; 'M' = macro stream; -s 7 -v = decompress stream 7
oledump.py -p plugin_http_heuristics sample.doc
mraptor sample.doc                           # AutoExec + Write/Execute = suspicious, one line
rtfobj sample.rtf                            # embedded OLE objects in RTF (Equation Editor exploits)
msodde sample.docx                           # DDE field attacks
xlmdeobfuscator -f sample.xls                # Excel 4.0 (XLM) macros

Hashing, fuzzy hashing, known-good/bad

sha256sum sample.bin; md5sum sample.bin; sha1sum sample.bin
hashdeep -c md5,sha1,sha256 -r ./samples/ > hashes.txt                    # recursive multi-hash
hashdeep -c sha256 -r -a -k known-good.txt ./bin/                          # audit dir against a known set (-a audit, -k known)
hashdeep -c sha256 -r -m -k nsrl.txt /mnt/img/usr/bin                      # -m: show only files that MATCH known (whitelist noise)
hashdeep -c sha256 -r -x -k nsrl.txt /mnt/img/usr/bin                      # -x: show only UNKNOWN files — the review list
ssdeep -b sample.bin                                                       # context-triggered piecewise hash
ssdeep -bl -r ./samples/ > fuzzy.txt; ssdeep -bm fuzzy.txt new.bin         # match a new sample against a set (score 0–100)
ssdeep -d -r ./samples/                                                    # cluster near-duplicates within a directory
tlsh -f sample.bin                                                         # TLSH — better on small/heavily-modified files
# Look up, don't upload (an upload tells the attacker you found it):
#   VirusTotal hash search, MalwareBazaar, Hybrid Analysis, `vt file <sha256>` CLI, ANY.RUN search
Get-FileHash .\sample.bin -Algorithm SHA256                # MD5, SHA1, SHA256, SHA384, SHA512
Get-ChildItem -Recurse | Get-FileHash -Algorithm SHA256 | Export-Csv hashes.csv
certutil -hashfile .\sample.bin SHA256                     # no PowerShell
certutil -hashfile .\sample.bin MD5
sigcheck64.exe -a -h -vt .\sample.exe                     # Sysinternals: signature, version, hashes, VirusTotal (-vt requires accepting ToS)
sigcheck64.exe -e -u -vr -s C:\Windows\System32 > unsigned.txt   # unsigned exes in a tree

Carving: files from unallocated space, swap, memory

# Get the blob: unallocated blocks of a partition (Sleuth Kit), or the whole image, or pagefile/hiberfil/mem
blkls -o 2048 disk.dd > unalloc.raw

# foremost — header/footer carving, config-driven, fast
foremost -t jpg,png,pdf,doc,zip,exe -i unalloc.raw -o carved-foremost/     # -t types (or all), writes audit.txt with offsets
foremost -c /etc/foremost.conf -i disk.dd -o carved/                      # custom signatures in the conf
# scalpel — same idea, faster, edit /etc/scalpel/scalpel.conf to UNCOMMENT the types you want first
scalpel -c /etc/scalpel/scalpel.conf -o carved-scalpel/ unalloc.raw
# photorec — best for media (400+ formats), interactive TUI, works on damaged fs; /cmd for scripting
photorec /log /d carved-photorec/ /cmd disk.dd fileopt,everything,enable,search
# bulk_extractor — does NOT carve files; it scans EVERY byte for FEATURES: emails, URLs, IPs, phone numbers, credit cards,
#   JSON, base64, EXIF, zip/gzip/rar contents (recursively decompressed!), Windows PE headers, hex keys, domains
bulk_extractor -o be-out/ disk.dd                          # 10–30 min per 100 GB; multi-threaded
bulk_extractor -o be-out/ -E email -E url -E domain -E exif unalloc.raw    # -E enable only listed scanners
ls be-out/            # email.txt url.txt domain.txt ip.txt telephone.txt ccn.txt exif.txt zip.txt json.txt *_histogram.txt
head be-out/url_histogram.txt be-out/email_histogram.txt   # ranked — top hits first
bulk_extractor -o be-out/ -F iocs.txt disk.dd              # -F: search for your own list of strings (offsets to features.txt)
bulk_extractor -o be-out/ -f 'Invoke-|-enc ' disk.dd       # -f: regex
# Every hit carries a byte offset (or "offset-ZIP-offset" for compressed) → dd/xxd there, or `fiwalk`/`identify_filenames.py` to map offset → filename via the fs
identify_filenames.py --all be-out/ be-out-annotated/ --image disk.dd
# Manual carving when you know the header: find offsets, cut
grep -obUaP '\xFF\xD8\xFF\xE0' unalloc.raw | head            # -o offsets, -b byte offset, -U binary, -a text, -P perl regex
python3 - <<'PY'
import re
d=open('unalloc.raw','rb').read()
for i,m in enumerate(re.finditer(rb'%PDF-1\.\d.*?\x25\x25EOF', d, re.S)):
    open(f'carved_{i}.pdf','wb').write(m.group()); print(i, m.start(), len(m.group()))
PY
# Strings over the whole blob, with offsets, into the IOC pass above
strings -a -t x -n 8 unalloc.raw > unalloc-strings.txt; strings -a -t x -n 8 -e l unalloc.raw >> unalloc-strings.txt
# Windows pagefile/hiberfil: strings + bstrings work directly; decompress hiberfil first for real analysis
#   hibr2bin.exe hiberfil.sys hiber.raw   (Comae/Magnet)   then Volatility / strings on hiber.raw

[!info] What carving cannot do Fragmented files come out corrupt (only the first fragment, or garbage joined on). SSDs with TRIM zero deleted blocks quickly — carving an SSD imaged days after deletion mostly yields nothing. Encrypted/compressed containers carve as one opaque blob. Carved files have no name, no path, no timestamps: to get those back, match the carved file’s hash/offset to $MFT/fls -d deleted entries or the USN journal.

YARA: match what you already know

yara -r rules/ sample.bin                                  # recurse a rules dir
yara -s rule.yar sample.bin                                # -s print matching strings + offsets
yara -m -s rules.yar sample.bin                            # -m print rule metadata
yara -r -w -f rules/ /mnt/img/home/                        # -w no warnings, -f fast mode
yara -C compiled.yarc sample.bin; yarac rules/*.yar compiled.yarc   # precompile big rule sets
yara rules.yar 1234                                        # scan a live PID (Linux, root)
yara -D sample.bin                                         # dump module data (pe, elf, hash, math)
yara -d filename=sample.bin -d filesize=$(stat -c%s sample.bin) rules.yar sample.bin   # external variables
yara-x scan rules/ sample.bin                              # yara-x: the Rust rewrite, same syntax, faster, better errors
rule triage_suspicious_pe_strings
{
    meta:
        author = "DAEMON"
        description = "Quick triage: PE with injection APIs + a URL + a PowerShell flag"
    strings:
        $api1 = "VirtualAllocEx" ascii
        $api2 = "WriteProcessMemory" ascii
        $api3 = "CreateRemoteThread" ascii
        $url  = /https?:\/\/[a-z0-9.\-]+\/[a-z0-9\/._-]*/ ascii wide nocase
        $ps   = "-enc" ascii wide nocase
        $ps2  = "FromBase64String" ascii wide
    condition:
        uint16(0) == 0x5A4D and filesize < 5MB and
        2 of ($api*) and ($url or any of ($ps*))
}

Rule sources: Neo23x0/signature-base (Loki/Thor), Yara-Rules/rules, ReversingLabs, Elastic protections-artifacts, InQuest awesome-yara index, ESET, Malpedia (login), plus the packer/crypto/capability rules in mandiant/capa (capa sample.exe gives you ATT&CK capabilities without writing rules). Keep an iocs.yar per case with the hashes, mutexes, PDB paths and URLs you pulled out of strings — then scan every other host’s triage collection with it.

Ten-minute triage checklist

f=sample.bin
file -k $f; sha256sum $f; ssdeep -b $f; exiftool -G1 -s $f | head -40
xxd $f | head -4; xxd $f | tail -4
strings -a -n 6 $f > s.txt; strings -a -n 6 -e l $f >> s.txt; wc -l s.txt
grep -Eio 'https?://[^ "]+|\b([0-9]{1,3}\.){3}[0-9]{1,3}\b|[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}' s.txt | sort -u
grep -Ei 'powershell|cmd\.exe|-enc|VirtualAlloc|WriteProcessMemory|CreateRemoteThread|HKCU|HKLM|\\Temp\\|\.pdb' s.txt | sort -u | head -40
binwalk $f | head; binwalk -E $f >/dev/null && echo "see entropy png"
diec $f 2>/dev/null || pescan $f 2>/dev/null
yara -r ~/rules/ $f; capa $f 2>/dev/null | head -40
# then decide: benign / known-bad (hash hit) / needs sandbox (ANY.RUN, CAPE, Joe) / needs a reverser
  1. Identity: file -k, magic head/tail, size, entropy. Packed? Polyglot? Appended data?
  2. Hashes: SHA-256 to VT/MalwareBazaar search (do not upload yet); ssdeep against your case corpus.
  3. Metadata: exiftool — author, tool, timestamps, PDB path, version info vs filename.
  4. Strings, both encodings, then the IOC greps. Save everything to the case notes with offsets.
  5. Structure: imports/sections (PE), objects (PDF), macros (Office), embedded files (binwalk, 7z l).
  6. Match: YARA rule sets, capa. Write the case rule from what you found.
  7. Decide the next stop: sandbox, Volatility for a memory-resident stage, or a reverser.
  • EZ Tools & KAPE — bstrings, Hasher, EZViewer on Windows
  • Linux forensics — where unallocated space comes from (blkls), Sleuth Kit
  • Acquisition — getting the disk/memory image to carve
  • Volatility 3 — dumping unpacked binaries from memory for a second strings pass
  • Hashing — algorithm reference
On this page

☧ CPTS · ordered posts

Locked

Unlock with your Main_Key through local GPG.

Start the local GPG helper

In your cheatsheet checkout, run:

npm run unlock:helper

Open the link it prints, or paste its pairing code below. Keep the terminal open until GPG finishes.

Import an index you already decrypted

Download the encrypted index, then decrypt with GPG:

gpg --output report-index.json --decrypt report-index.gpg

Your private key stays in GPG. The decrypted index is saved in this browser so you can reopen it after navigation, refreshes and restarts. Lock this browser or clear this site's browser data to remove the saved index. Nothing is uploaded.