Hash-Identifier

hash-identifier (and its faster CLI cousin hashid) takes an unknown hash and tells you which algorithms could have produced it: it reads the length, character set, and structure, then prints a ranked list of candidates like MD5, SHA-1, NTLM, bcrypt, or sha512crypt. It does not crack anything; it turns “I found a hash, what is it?” into the correct cracking mode so you stop guessing. Reach for it the moment a dumped credential, a config value, or a forensic artifact hands you a string you cannot name.

Mental model: hashid -m 'HASH' - identify, read the [Hashcat Mode: N], hand that number to hashcat. Everything else is one flag away.

New to hashes? Core concepts
  • Hash / digest: a fixed-length fingerprint of some input, for example 5f4dcc3b5aa765d61d8327deb882cf99 is a 32-char hex MD5
  • Length: the biggest clue; 32, 40, 64, 128 hex chars each map to a small set of algorithms
  • Character set: hex-only, base64-ish (+/=), or printable-with-markers narrows the field before length does
  • Prefix / tag: $1$, $5$, $6$, $2y$, $y$, {SSHA} announce the type outright; read them and skip the guess
  • Salt: random bytes folded in so equal passwords hash differently, usually stored inline as $id$salt$digest
  • Hashcat mode / JtR format: the real output you want, for example -m 0 / --format=raw-md5 for MD5, -m 1000 / nt for NTLM
  • Length collision: many algorithms share a length (32 hex could be MD5, NTLM, MD4, an LM half), so a match is a candidate, never proof
When to reach for a hash identifier (and when not)

Reach for it to name an unknown hash from a CTF dump, a config file, or a forensic artifact, to triage a mixed pile before cracking, or to get the right hashcat -m or john --format fast without memorizing every format.

Reach for something else when the source already names the format (a /etc/shadow line is crypt, an NTDS dump is NTLM, a .htpasswd line tells you by its prefix), when the string carries an unambiguous $prefix$ (just read it), or when you need the whole salted hash:salt structure to crack (identifying the bare digest will not give you a working mode). The actual cracking is hashcat or john, never this tool.

Install, update, verify#

sudo apt update && sudo apt install -y hash-identifier hashid   # Debian / Ubuntu / Kali
pipx install name-that-hash                                     # nth: richer identifier (optional)
pipx install hashid                                             # isolated install off Kali

sudo apt install --only-upgrade -y hash-identifier hashid       # update

command -v hashid hash-identifier    # confirm both are on PATH
hashid --version                     # confirm the version
hashid '5f4dcc3b5aa765d61d8327deb882cf99'   # self-test: candidate list should lead with MD5

hashid reads a hash as a positional argument (or one per line from a file or STDIN); hash-identifier is interactive only and prompts for HASH:. The classic tool may also be invoked as hash-id.py depending on how it was installed.

Flags you’ll actually use#

These are hashid, the scriptable workhorse (the classic hash-identifier takes no flags, it just prompts). Skim these first; the cheat sheet below is these flags combined.

FlagDoesFlagDoes
-mhashid: add hashcat mode [Hashcat Mode: N]nth -tname-that-hash: identify one string
-jhashid: add john format [JtR Format: name]nth -fnth: identify a file, one hash per line
-ehashid: include rare / salted matchesnth -gnth: greppable JSON output for scripts
-o FILEhashid: write results to a filenth -anth: accessible output (no ASCII art)
FILEhashid: positional file = one hash per linenth -enth: extract a hash from surrounding junk
- / STDINhashid: pipe hashes in (cat f | hashid -m)nth -b64nth: base64-decode before identifying

Cheat sheet#

Every block starts simple and adds one flag at a time, so you can stop at the line that does the job.

# Build up an identify: stop at the line you need
hashid 'HASH'                 # 1. ranked candidate list (length + charset)
hashid -m 'HASH'              # 2. + hashcat mode: [Hashcat Mode: 0]
hashid -j 'HASH'              # 3. + john format:  [JtR Format: raw-md5]
hashid -mj 'HASH'             # 4. + both at once (what you usually want)
hashid -mje 'HASH'            # 5. + rare / salted formats too (when 1-4 miss)

# Triage many hashes
hashid -m hashes/dump.txt                    # a file: one candidate block per line
cat hashes/dump.txt | hashid -m              # or pipe them in on STDIN
hashid -mj hashes/dump.txt -o notes/ids.txt  # save the ids + modes to notes

# Clean the input first (the usual cause of a bad guess)
tr -d '[:space:]' < hashes/raw.txt > hashes/clean.txt   # strip stray whitespace / newlines
cut -d: -f2 hashes/creds.txt > hashes/only.txt          # drop the user: field, keep the digest

# name-that-hash: richer output, summaries, links
nth -t 'HASH'                 # one hash, with hashcat + john lines filled in
nth -f hashes/dump.txt        # a whole file
nth -g -t 'HASH' | jq .       # JSON out, pipe into a script
nth -a -t 'HASH'              # plain text, no ASCII art (screen readers / logs)

# Classic interactive tool (no flags, it prompts you)
hash-identifier               # paste each hash at the HASH: prompt; blank line to exit

# Read a prefix and skip the tool entirely (verify, do not assume)
# $1$...   md5crypt      hashcat -m 500    john --format=md5crypt
# $5$...   sha256crypt   hashcat -m 7400   john --format=sha256crypt
# $6$...   sha512crypt   hashcat -m 1800   john --format=sha512crypt
# $2a/b/y$ bcrypt        hashcat -m 3200   john --format=bcrypt
# $y$...   yescrypt      modern crypt default; identify by prefix, crack with john
# {SSHA}   salted SHA-1  hashcat -m 111    (Netscape / LDAP SSHA)

# Length cues for bare hex (a candidate, never proof)
# 32 hex   MD5 / NTLM / MD4   hashcat -m 0 / 1000 / 900
# 40 hex   SHA-1              hashcat -m 100
# 64 hex   SHA-256            hashcat -m 1400
# 128 hex  SHA-512            hashcat -m 1700

Command breakdowns#

Each block below explains one situation, the exact command, and what to expect back.

Identify a single unknown hash#

hashid '5f4dcc3b5aa765d61d8327deb882cf99'

Prints [+] MD5, [+] NTLM, [+] MD4, and other 32-hex candidates, most likely first. The list is driven by length and character set, so treat every line as a candidate to confirm, not a fact.

Get the hashcat mode to crack with#

hashid -m '5f4dcc3b5aa765d61d8327deb882cf99'

Annotates each candidate as [+] MD5 [Hashcat Mode: 0], [+] NTLM [Hashcat Mode: 1000]. That number goes straight into hashcat -m 0. This is the flag you will use nine times out of ten.

Get the John the Ripper format name#

hashid -j '5f4dcc3b5aa765d61d8327deb882cf99'

Adds [JtR Format: raw-md5], the string john wants after --format=. Combine both with hashid -mj 'HASH' when you have not decided which cracker to use.

Identify a SHA-1 hash#

hashid -m 'aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d'

Forty hex chars: the top candidate is SHA-1, [Hashcat Mode: 100]. RIPEMD-160 and a few others share the length, so confirm against the source if the crack will cost real time.

Read a crypt-style shadow hash by its prefix#

hashid -m '$6$abc123$Zr...trimmed...0/'

The $6$ prefix is decisive: sha512crypt, [Hashcat Mode: 1800]. $1$ is md5crypt (500), $5$ is sha256crypt (7400). These come from /etc/shadow, and the prefix beats any length heuristic.

Recognize a bcrypt hash and its cost#

hashid -m '$2y$10$abcdefghijklmnopqrstuv...trimmed'

$2a$ / $2b$ / $2y$ is bcrypt, [Hashcat Mode: 3200]. The 10 right after is the cost factor: each step doubles the work, so a high cost means a small, targeted wordlist and realistic expectations.

Triage a whole file of mixed hashes#

hashid -m hashes/dump.txt

Pass the file as the positional argument (there is no -f flag) and hashid analyzes one hash per line, printing an Analyzing '...' header and candidates for each. Sort the output into per-type files so each cracking run uses one consistent mode.

Pipe hashes in from another command#

cut -d: -f2 creds.txt | hashid -m

With no argument hashid reads STDIN, so you can strip the user: field with cut and identify only the digests in one pass. Handy when the dump is user:hash per line.

Save the identifications to your notes#

hashid -mj hashes/dump.txt -o notes/hash-ids.txt

-o writes the full annotated list to a file instead of the terminal, keeping a clean record of what each hash probably is with both crack-mode hints. Re-runnable and greppable later.

Widen the search to rare or salted formats#

hashid -e 'somethingunusuallooking=='

Without -e, hashid hides less-likely and salted-password matches to keep the list short. Add it when the common guesses miss, for odd application-specific or base64-wrapped hashes.

nth -t '5f4dcc3b5aa765d61d8327deb882cf99'

nth prints the same candidates with a one-line description, a “least likely” section, and hashcat/john lines already filled in. Better ranking on some odd formats, at the cost of a separate install.

Get machine-readable output for a script#

nth -g -t '5f4dcc3b5aa765d61d8327deb882cf99' | jq .

-g emits JSON instead of the banner UI, so a script can parse the candidate names and modes and branch on them. Use -a instead when you want plain text without the ASCII art (screen readers, log files).

Extract a hash buried in other text#

nth -e -t '####5f4dcc3b5aa765d61d8327deb882cf99####'

nth’s -e (extreme) finds the hash inside surrounding junk instead of failing on the whole string, so you can paste a log line or a config fragment and still get an identification. Note that hashid’s -e means something different (extended matches).

Inspect hashes one at a time interactively#

hash-identifier

The classic tool takes no arguments: it prompts HASH:, you paste one string, it prints length-based candidates, and it loops for the next. A blank line or Ctrl-C exits. Fine for a quick manual look, but no mode hints.

Reading the output#

  • [+] MD5 [Hashcat Mode: 0][JtR Format: raw-md5] - one candidate; the bracketed values are exactly what hashcat -m and john --format= want.
  • The first line is the most likely, not the only one. Read the whole block; length collisions put several real options together.
  • [+] Unknown hash means nothing matched: the input is truncated, base64-wrapped (try hashid -e or nth -b64), or carries stray whitespace.
  • Analyzing '...' headers appear when you pass a file or STDIN, one per input line, so you can tell which candidates belong to which hash.
  • A $prefix$ in the string overrides the ranking: trust $6$, $2y$, or {SSHA} over any length-based guess listed near it.

Troubleshooting#

ProblemCauseFix
command not foundNot installed / stale PATHReinstall; open a fresh shell
[+] Unknown hashTruncated, wrapped, or salted inputAdd -e; try nth -b64; check the source format
Identified the usernamePassed the whole user:hash linecut -d: -f2 first, keep only the digest
Length looks off by one or twoTrailing newline or spacetr -d '[:space:]' before identifying
-f throws an errorhashid has no -f flagPass the file as a positional arg, or pipe on STDIN
Wrong crack mode chosenLength collision (MD5 vs NTLM)Use context; test both -m 0 and -m 1000 on one sample
Candidates differ from a guideVersion / format-DB changesCheck hashid --version; cross-check with nth

Gotchas#

  • -m prints the hashcat number, not proof of the algorithm. A 32-hex string is MD5 and NTLM and MD4; where you found it breaks the tie, not the tool.
  • NTLM and MD5 are byte-for-byte indistinguishable (both 32 hex). If a raw-md5 crack stalls on a Windows dump, it is almost certainly NTLM (-m 1000).
  • A user:hash line silently identifies the wrong field. hashid analyzes the whole string, so the username changes the length and poisons the guess; strip to the digest first.
  • hashid takes files as a positional argument, not -f. hashid -f file errors, while hashid file or cat file | hashid works. The -f flag belongs to nth.
  • A trailing newline changes the apparent length. Pasting from a browser or echo without -n adds a byte, and 33 “hex” chars matches nothing; tr -d '[:space:]' fixes it.

Pairs with#

hashcat cracks on the GPU with the -m number this prints; john cracks on the CPU with the --format= name from -j. Point either at a wordlist from seclists. When you would rather attack the live login than the offline hash, reach for hydra. name-that-hash is the friendlier identifier when you want summaries and links, and the classic hash-identifier is fine for a one-off manual look, but hashid stays the most scriptable; once you learn the common length-to-type map you will name most hashes by eye and only reach for a tool on the odd ones.

Find us elsewhere

Merch, stickers, and moreSupport the work at the Solvere Labs shop