Skip to content
All posts
revrevised March 31, 20264 min read

Triage at scale: hashing, similarity, and finding the odd sample

When a challenge hands you a folder of a hundred binaries and one is different, reversing each by hand is the wrong move. Import hashing, fuzzy hashing, and YARA turn a pile of samples into a sorted, searchable set.

A particular kind of rev or forensics challenge does not hand you one binary - it hands you many. A folder of a hundred samples where one is the real payload and the rest are decoys. A set of files that are all 'the same malware' except one variant that carries the flag. A capture full of dropped executables. Reversing each by hand is exactly what the challenge is betting you will do. The faster path is to treat the pile as data: hash it, cluster it, and let the outlier fall out.

The techniques below come from real malware analysis, where analysts triage thousands of samples a day and cannot open each in a disassembler. The same tools collapse a CTF's decoy pile into a sorted set in seconds.

Cryptographic hashes: the exact-match layer

Start with the obvious. A SHA-256 of every file tells you which ones are byte-identical - though a Merkle-Damgard hash extends, so identical prefixes and identical files are not the same claim - deduplicating the pile and revealing that ninety of the hundred are literally the same file. It also lets you check each hash against VirusTotal or a known-sample database, which sometimes identifies the family (or the challenge's source) outright.

sha256sum * | sort | uniq -c -w64 | sort -rn
# Groups identical files. The counts tell you the decoy structure at a glance:
# 90 copies of one hash, 9 of another, and 1 unique file -> look at the unique one.
Exact hashing does not survive a single flipped byte, which is the point - it separates 'identical' from 'merely similar' and hands you the singletons.

Fuzzy hashing: the similarity layer

  1. 500 files

    one of them is the challenge

  2. SHA-256

    exact duplicates collapse

  3. ssdeep / TLSH

    near-duplicates cluster

  4. imphash

    recompiles cluster too

  5. the outlier

Three hashes at three resolutions. You are not identifying malware here - you are shrinking a pile until one file has nothing to hide behind.

Cryptographic hashes change completely when one byte changes, so they cannot tell you that two files are 99% the same. Fuzzy hashes are built to do exactly that: they produce a hash you can compare for similarity, giving a percentage rather than a yes/no. This is how you find the sample that is almost like the others but not quite - the modified one.

# ssdeep: context-triggered piecewise hashing, the classic.
ssdeep -r . > hashes.txt
ssdeep -m hashes.txt *              # match each file against the set, with %

# TLSH is the modern alternative - more robust, better at scale.
# A file that scores 95% against the herd but has a small unique region
# is where the planted difference (and the flag) lives.
ssdeep clusters near-duplicates; the outlier is the file whose best match to the rest is meaningfully lower than everyone else's.

Structural hashes: same code, different bytes

For executables specifically, you can hash structure rather than raw bytes, which catches samples that share code but were compiled or packed differently. The import hash (imphash) is a hash of a PE's import table in order - two binaries built from the same source have the same imports in the same order, so the same imphash, even if other bytes differ. Rich header hashes and section-layout hashes do the same job from other angles.

  • imphash - identical import tables. Groups samples from the same toolchain/source even across recompiles.
  • Rich header hash - the undocumented PE metadata Microsoft compilers embed; a strong fingerprint of the exact build environment.
  • Section hashes - hash each section separately; a shared .text with a different .data isolates where the samples diverge.

YARA: describe the thing you are hunting for

Once you know what distinguishes the interesting sample - a string, a byte pattern, a specific import - a YARA rule turns that description into a scanner that finds every file matching it. YARA is the connective tissue of malware triage: you notice a feature in one sample and immediately ask 'which others have it?'.

rule has_flag_marker {
    strings:
        $a = "flag{" nocase
        $b = { 6a 00 68 ?? ?? ?? ?? e8 }      // a wildcarded byte pattern
    condition:
        any of them
}
// yara -r has_flag_marker.yar ./samples/
Strings and wildcarded byte patterns are the two workhorses. A rule that matches exactly one file in the pile has found your target.

The triage order

  1. Exact match

    SHA-256 everything and group. The singletons and the decoy structure both show up here.

  2. Near match

    Fuzzy-hash with ssdeep or TLSH to cluster relatives and surface the almost-but-not-quite sample.

  3. Structural match

    For PEs, imphash and section hashes catch shared code behind different bytes.

  4. Profile the majority

    Then hunt the file that breaks the profile.

  5. Write the rule

    A YARA rule for the distinguishing feature, confirmed to match exactly the sample you expect.

  6. Only now, disassemble

    One sample, chosen by everything above.