Tech Solvency / pub / bin / mdxfind


MDXfind logo - diagonal magnifying glass with a large hash under the glass, and a lemniscate below. Background is gradient lilac.

MDXfind
the deep-dive, CPU-based hash-cracking tool

Latest versions:

MDXfind 1.136 (2025-11-10)
MDsplit 1.24 (2025-08-28)


Jump to download



What is MDXfind?

MDXfind is a command-line hash-cracking tool for security researchers, pen testers, etc.

MDXfind "runs large numbers of unsolved hashes, using many algorithms, against large numbers of plaintext words, very quickly" (Waffle, primary author).

MDXfind is somewhat different from other hash-cracking software (see below). The learning curve may be a little steep at first, but if you have a pile of hashes of unknown type, or a hundred million hashes that you need to pare down quickly for other attacks ... MDXfind may be the perfect tool for the job.

While MDXfind is CPU based (which may seem odd in the era of GPU cracking), don't worry -- its core features work nicely on CPU!


How MDXfind is different

Feature differences

Operational differences

Other MDXfind features

When to use MDXfind

When not to use MDXfind

What MDXfind is not


Requirements

MDXfind is distributed as standalone binaries for the command line. There is no installer, and there is no GUI.

MDXfind should work "out of the box" on: Windows 32/64, Linux (x86 32/64, ARM6/7/8, and POWER8), FreeBSD 64, macOS (Intel or M), and Linux POWER8. See file(1) output for minimum kernel versions.

MDXfind uses the following libraries. As of version 1.130, these are included directly (no dependencies required).

If you have an update to these requirements, let me know.


Help and examples

Simple example usage:

This example shows a basic mdxfind run, followed by using mdsplit to remove all discovered solutions from the target.

Note: on the Windows command line, use double quotes instead of single quotes around the regex.

$ cat example-hashes.txt
5a22e6c339c96c9c0513a46e44c39683
5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8
5f4dcc3b5aa765d61d8327deb882cf99
696d29e0940a4957748fe3fc9efd22a3
7b3b4de00794a247cf8df8e6fbfe19bf
8846f7eaee8fb117ad06bdd830b7586c

$ cat example-wordlist.dict
password

# Run the attack. All three requested hash types 
# are attempted in a single attack run.
$ mdxfind -h '^(SHA1|MD5|NTLM)$' \
   -i 3 -f example-hashes.txt example-wordlist.dict \
   | tee -a example-found.res

Iterations set to 3
Working on hash types: MD5 SHA1 NTLM
Took 0.00 seconds to read hashes
Searching through 6 unique hex hashes from example-hashes.txt
Maximum hash chain depth is 1
Minimum hash length is 32 characters
Using 2 cores

Done - 2 threads caught
1 lines processed in 0 seconds
1.00 lines per second
0.00 seconds hashing, 11 total hash calculations
0.01M hashes per second (approx)
1 total files
1 MD5x01 hashes found
1 MD5x02 hashes found
1 MD5x03 hashes found
1 SHA1x01 hashes found
1 NTLMx01 hashes found
5 Total hashes found
MD5x01 5f4dcc3b5aa765d61d8327deb882cf99:password
MD5x02 696d29e0940a4957748fe3fc9efd22a3:password
MD5x03 5a22e6c339c96c9c0513a46e44c39683:password
SHA1x01 5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8:password
NTLMx01 8846f7eaee8fb117ad06bdd830b7586c:password

$ cat example-found.res
MD5x01 5f4dcc3b5aa765d61d8327deb882cf99:password
MD5x02 696d29e0940a4957748fe3fc9efd22a3:password
MD5x03 5a22e6c339c96c9c0513a46e44c39683:password
SHA1x01 5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8:password
NTLMx01 8846f7eaee8fb117ad06bdd830b7586c:password

# Remove all found hashes from our target file, 
# distributing hash:found pairs into separate files
# per algorithm.
# This can be done iteratively (new results will append).

# Check how big the target hashfile is.
$ wc -l example-hashes.txt
6 example-hashes.txt
# Make a backup - we're about to change it.
$ cp -p example-hashes.txt example-hashes.txt.orig

# Split the founds per type; remove hashes from target.
$ mdsplit -f example-found.res example-hashes.txt
5 result lines processed, 5 types found
MD5x01 MD5x02 MD5x03 NTLMx01 SHA1x01
example-hashes.txt had 5 hits

Total 5 hashes found

# Check our split files.
$ head -n 1 example-hashes.*x0*
==> example-hashes.MD5x01 <==
5f4dcc3b5aa765d61d8327deb882cf99:password

==> example-hashes.MD5x02 <==
696d29e0940a4957748fe3fc9efd22a3:password

==> example-hashes.MD5x03 <==
5a22e6c339c96c9c0513a46e44c39683:password

==> example-hashes.NTLMx01 <==
8846f7eaee8fb117ad06bdd830b7586c:password

==> example-hashes.SHA1x01 <==
5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8:password

# The found hashes have been removed from the target.
$ wc -l example-hashes.txt*
1 example-hashes.txt
5 example-hashes.txt.orig

Slightly more advanced example

(adapted from @winxp5421's talk, with each line explicated):

# Try all unsalted hash types, up to five iterations.
$ mdxfind -h ALL -h '!salt,!user,!crypt' -i 5 \
    -f unknown.txt /dict/top-10k-pass.dict \
    | tee -a out.res

   # Search every algorithm, except ...
   -h ALL

   # ... skip salted explicit (!salt), implicit (!crypt)
   -h '!salt,!user,!crypt'

   # Iterate 1 to 5 times, inclusive.
   -i 5

   # Specify target hashlist.
   -f unknown.txt

   # Specify wordlist (input dictionary).
   /dict/top-10k.pass.dict

   # Append to outfile (where results go).
   | tee -a out.res

(Using  '| tee -a out.res'   lets you watch the output; use  ' > out.res'  instead if you won't want to watch, or tee isn't available on your system.)

Specifying hash types

To tell MDXfind which hash types you want to try, you use use regular expressions that matches the hash types. Case-insensitivity is always implied.

To see the list of available hash types, run MDXfind with just -h with no other parameters.

At startup, you can see which hash types were selected (the "Working on hash types:" line). You can use this to check whether your regex is doing what you're expecting.

Tip: if you know you only need one or more specific hash types, your attack will be much faster if you only specify just the relevant types.

Examples:

Note: on the Windows command line, use double quotes instead of single quotes around the regex.

# Match only a single hash type.
$ mdxfind -h '^MD5$' [...]

# Match all hash types beginning with MD5.
# (usually means MD5 was the last step in the algorithm)
# Note the difference from above - no '$' at the end.
$ mdxfind -h '^MD5' [...]

# Only match these three specific hash types.
$ mdxfind -h '^(SHA1|MD5|NTLM)$' [...]

# Match all hash types beginning with these strings.
# Again, note the missing '$'.
$ mdxfind -h '^(SHA1|MD5|NTLM)' [...]

# Match all hash types *except* any containing these string..
# Exclamation points may have special meaning in your shell,
# so quoting may be necessary.
mdxfind -h ALL -h '!salt,!user,!crypt,!revp,!leet' [...]

As of version 1.133, the undocumented -m flag, which lets you specify hash types using hashcat mode IDs (one or more separated by commas) now also supported a -m eNN syntax, which lets you specify an mdxfind hash type using its position in -h (1 for MD5, etc.)

Threading

By default, MDXfind will politely but thoroughly use all available cores/threads. To override this, you can use -t [N] (where N is the number of threads to use).

Generating hashes with -z

You can use mdxfind's -z flag to generate arbitrary hashes:

# Use NUL instead of /dev/null on Windows
$ echo password | mdxfind -h "^MD5$" -z -f /dev/null -i 5 stdin 2>/dev/null
MD5x01 5f4dcc3b5aa765d61d8327deb882cf99:password
MD5x02 696d29e0940a4957748fe3fc9efd22a3:password
MD5x03 5a22e6c339c96c9c0513a46e44c39683:password
MD5x04 e777a29bee9227c8a6a86e0bad61fc40:password
MD5x05 7b3b4de00794a247cf8df8e6fbfe19bf:password

Expanded examples:

Generating sequences of bytes with $TESTVEC

$TESTVEC[bytes x count] is a way to create patterns up to 2,000,000 bytes as a candidate for any algorithm. Typically, these are used as ways to create known patterns to test algorithms.

$TESTVEC accepts one or more byte, and repeats them the specified number of times, to a maximum size of 2,000,000 bytes (bytes x repetition size).

Such sequences are also part of the FIPS 140-2 standard:

A file containing the binary-coded form of the ASCII string which consists of 1,000,000 repetitions of the character "a" results in a SHA-1 message digest of 34aa973c d4c4daa4 f61eeb2b dbad2731 6534016f.
# Simple example - a single NUL byte:
$ echo '$TESTVEC[00 x 1]' \
  | mdxfind -h ^sha1$ -z -f /dev/null stdin 2>/dev/null
SHA1x01 5ba93c9db0cff93f52b521d7420e43f6eda2784f:$TESTVEC[00 x 1]

# ... which is equivalent to:
$ echo -n '\x00' | xxd -p -r | sha1sum
5ba93c9db0cff93f52b521d7420e43f6eda2784f  -

# The classic FIPS example - byte \x61, repeated 1 million times.
$ echo '$TESTVEC[61 x 1000000]' \
  | mdxfind -h ^sha1$ -z -f /dev/null stdin 2>/dev/null
SHA1x01 34aa973cd4c4daa4f61eeb2bdbad27316534016f:$TESTVEC[61 x 1000000]

$TESTVEC was introduced in MDXfind 1.16 in May 2014.

Output and tuning

Cracking output goes straight to stdout (unless redirected). Each hash:solution pair is prefixed with the discovered hash type and iteration (x99 syntax):

MD5x01 5f4dcc3b5aa765d61d8327deb882cf99:password
MD5x02 696d29e0940a4957748fe3fc9efd22a3:password
MD5x03 5a22e6c339c96c9c0513a46e44c39683:password
SHA1x01 5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8:password
NTLMx01 8846f7eaee8fb117ad06bdd830b7586c:password

MDXfind will periodically show a status / progress "comfort message" line (every 15 seconds). This status output goes to stderr, so if you are directing output somewhere else, the status line will be the only thing you see while the attack is in progress:

Working on mybigwordlist w=62, line 2771, Found=2809, 0.54Mh/s, 184.73c/s
Working on mybigwordlist w=62, line 5542, Found=8532, 0.74Mh/s, 184.73c/s

H/s is hash operations per second (often more than one in each attempt of a hashtype)

c/s is candidates per second (e.g., bcrypt attempts per second)

Note that initial values may take time to populate (the first job has to complete).

Status output and tuning commentary, from Waffle:


mdsplit - mdxfind's companion tool

The purpose of mdsplit is to remove hashes with solutions from a target hashlist, using MDXfind result files (traditionally named with a .res extension) as a reference, separating them into per-hashtype files with the hash type as the files extension.

Typical usage examples:

# Remove all hashes found in foo.res from unsolved.hashes.txt.
mdsplit -f foo.res unsolved-hashes.txt

# Do the same for multiple files, from stdin.
cat foo.res bar.res | mdsplit unsolved-hashes.txt

# Run a cracking job, automatically sending mdxfind output to mdsplit.
cat unfound-hashset*.txt | mdxfind -i 3 /tmp/words | mdsplit *.txt

If you are working with a results file that does not contain hash-type prefixes (such as a potfile from hashcat or john), you can use the -t flag to specify a default hash type. (Of course, if your potfile contains more than one "silent" hash type, this won't work.)

When working with large hashlists (millions+), other tools like John the Ripper and hashcat can take non-trivial time to process the hashlist at each startup. (When doing many small attacks, this can sometimes mean that the startup time is higher than the attack time!). So a very common workflow is to use mdxfind to find a lot of hashes early, and then mdsplit to remove the found hashes from your target hashlist. This can reduce your target to a manageable size for other tools. For hashcat users, this is similar to hashcat's --remove, but after the fact.


Full usage output

See usage.txt for the default command-line usage output for both mdxfind and mdsplit. To see full usage for mdxfind, use the -? parameter.


Changelog

Here is the full known changelog (text file) for both mdxfind and mdsplit.


Metadata

The upstream distribution from Waffle just contains binaries. I generate some useful metadata and maintain a changelog here, but my metadata is not in the distribution zipfile.

There is also a little bit of metadata provided to me directly by Waffle (but isn't part of the zipfile):


References

Talks

Forum posts

Posts with more info and examples:

(Moved/broken references, necromancy TBD - see Wayback Machine in the meantime:)
Google search for MDXfind on Hashkiller forums | usage from hashes.org forums | thread 1 | thread 2 | thread 3

Other references

See also


Download

NOTE: MDXfind is distributed as standalone binaries for the command line. There is no installer, and there is no GUI.

In the directory below, you will see two zipfiles:

Note:

Where's the source?

MDXfind is not currently open source (no public GitHub, etc.), but it is free to use.

How is MDXfind licensed?

Permission is granted to use, copy, share, and redistribute this software for non-commercial purposes only.

Modifications and derivative works are allowed, provided they are not used or distributed for commercial benefit.

Redistribution of unmodified copies is permitted only for non-commercial purposes.

Any commercial use, sale, or distribution for profit is strictly prohibited.

Icon  Name                    Last modified      Size  Description
[PARENTDIR] Parent Directory - [DIR] archive/ 2025-08-27 02:49 - retired/older files [TXT] CHANGES.txt 2025-11-11 01:05 15K Changelog* [   ] mdxfind-latest.zip 2025-11-11 00:53 16M stable symlink to latest [   ] mdxfind-1.136.zip 2025-11-11 00:53 16M [BIN] mdxfind-32.exe 2025-11-10 20:12 4.0M (32-bit) [BIN] mdxfind.exe 2025-11-10 19:01 3.8M [BIN] mdxfind.static 2025-11-10 17:45 3.9M DEPRECATED - use mdxfind [BIN] mdxfind 2025-11-10 17:45 3.9M [BIN] mdxfind.power8 2025-11-10 17:40 3.0M [BIN] mdxfind-32 2025-11-10 17:08 3.3M (32-bit) [TXT] usage.txt 2025-11-10 16:38 2.8K mdxfind/mdsplit usage* [BIN] mdxfind.arm6 2025-11-10 16:38 2.4M e.g. Pi v1 x32 [TXT] file-output.txt 2025-11-10 16:38 4.1K file(1) binary details* [TXT] algorithms.txt 2025-11-10 16:38 10K supported hash types* [TXT] CHECKSUMS.SHA256.txt 2025-11-10 16:38 2.1K SHA256 checksums* [TXT] CHECKSUMS.MD5.txt 2025-11-10 16:38 1.2K MD5 checksums* [BIN] mdxfind.freebsd 2025-11-10 16:37 4.1M [BIN] mdxfind.arm7 2025-11-10 16:32 2.5M e.g. Pi early 2 B x32 [BIN] mdxfind.macm1 2025-11-10 16:27 4.9M DEPRECATED - use mdxfind.mac (universal) [BIN] mdxfind.mac 2025-11-10 16:27 4.9M [BIN] mdsplit.macm1 2025-10-24 14:52 342K DEPRECATED - use mdsplit.mac (universal) [BIN] mdsplit.mac 2025-10-24 14:52 342K [BIN] mdsplit-32.exe 2025-09-12 14:16 92K (32-bit) [BIN] mdsplit.exe 2025-09-12 14:16 166K [BIN] mdsplit-32 2025-09-12 14:15 94K (32-bit) [BIN] mdsplit.arm8 2025-09-12 14:14 131K e.g. Pi 3+ x64 [BIN] mdsplit.static 2025-09-12 14:09 159K DEPRECATED - use mdsplit [BIN] mdsplit 2025-09-12 14:09 159K [BIN] mdsplit.freebsd 2025-09-12 14:09 158K [BIN] mdxfind.arm8 2025-09-12 14:09 2.1M e.g. Pi 3+ x64 [BIN] mdsplit.power8 2025-09-12 14:07 259K [BIN] mdsplit.arm7 2025-09-12 14:03 74K e.g. Pi early 2 B x32 [BIN] mdsplit.arm6 2025-09-12 14:03 74K e.g. Pi v1 x32 [TXT] maphashcat.txt 2025-08-26 00:27 8.6K hashcat mode -> algo map** [TXT] algo_defs.txt 2025-08-26 00:27 22K algo name -> ID map** [TXT] top-10k-pass.dict 2025-08-18 22:46 80K HashMob's top10k list* [TXT] example-found.res 2025-08-18 22:00 255 Example cracking results* [TXT] example-hashes.txt 2025-08-18 18:49 206 Example hashes* [TXT] example-wordlist.dict 2025-08-18 17:34 9 Example wordlist* [   ] mdsplit-old.txt 2019-09-01 22:33 2.5K old Perl version (ref)

* File not part of the distro -- metadata added by me (errors mine, not Cynosure Prime's)
** File not part of the distro -- metadata added by Waffle

Credits

All credit to Waffle and hops of CynoSure Prime for this powerful hash-cracking tool. A serious amount of careful thought and insight has gone into making it reliable and efficient.


.. Up to /pub/bin
<- Back to Tech Solvency