Wednesday, November 6, 2013

HashTag: Password Hash Identification

Interested in password cracking or cryptography? Check this out. is a tool written in python which parses and identifies various password hashes based on their type. HashTag was inspired by attending PasswordsCon 13 in Las Vegas, KoreLogic's 'Crack Me If You Can' competition at Defcon, and the research of iphelix and his toolkit PACK (password analysis and cracking kit). HashTag supports the identification of over 250 hash types along with matching them to over 110 hashcat modes. HashTag is able to identify a single hash, parse a single file and identify the hashes within it, or traverse a root directory and all subdirectories for potential hash files and identify any hashes found.

Click here to download source code or access it online at OnlineHashCrack

One of the biggest aspects of this tool is the identification of password hashes. The main attributes I used to distinguish between hash types are character set (hexadecimal, alphanumeric, etc.), hash length, hash format (e.g. 32 character hash followed by a colon and a salt), and any specific substrings (e.g. '$1$'). A lot of password hash strings can't be identified as one specific hash type based on these attributes. For example, MD5 and NTLM hashes are both 32 character hexadecimal strings. In these cases I make an exhaustive list of possible types and have the tool output reflect that. During development I created an excel spreadsheet which contains much of the hash information which can be found here or here.

Usage: {-sh hash |-f file |-d directory} [-o output_filename] [-hc] [-n]

Note: When identifying a single hash on *nix operating systems, remember to use single quotes to prevent interpolation. (e.g. python -sh '$1$abc$12345')

-h, --help show this help message and exit
-sh SINGLEHASH, --singleHash SINGLEHASH Identify a single hash
-f FILE, --file FILE Parse a single file for hashes and identify them
-d DIRECTORY, --directory DIRECTORY Parse, identify, and categorize hashes within a directory and all subdirectories
-o OUTPUT, --output OUTPUT Filename to output full list of all identified hashes
--file default filename: HashTag/HashTag_Output_File.txt
--directory default filename: HashTag/HashTag_Hash_File.txt
-hc, --hashcatOutput --file: Output a file per different hash type found, if corresponding hashcat mode exists
--directory: Appends hashcat mode to end of separate files
-n, --notFound --file: Include unidentifiable hashes in the output file. Good for tool debugging (Is it Identifying properly?)

Identify a single hash (-sh): -sh $1$MtCReiOj$zvOdxVzPtrQ.PXNW3hTHI0
single hash example -sh 7026360f1826f8bc

single hash example 2 -sh 3b1015ccf38fc2a32c18674c166fa447

single hash example 3

Parsing and identifying hashes from a file (-f): -f testdir\street-hashes.10.txt -hc
hashes file example
Here is the output file. Each identified hash outputs the hash, char length, hashcat modes (if found) , and possible hash types:
Output file
Using the -hc/--hashcat argument we get a file for each hash type if a corresponding hashcat mode is found. This makes the process of cracking hashes with hashcat much easier as you immediately have the mode and input file of hashes:
file listing output
Output from a file with many different hash types (the filenames are hashcat modes and inside are all hashes of that type):
hashtag output directory with multiple files

Traversing Directories and Identifying Hashes (-d): -d ./testdir -hc
directory example

The output consists of three main things:

  • Folders containing copies of potentially password protected files. This makes it easy to group files based on extension and attempt to crack them.
  • HashTag default files - A listing of all hashes, password protected files the tool doesn't recognize, and hashes the tool can't identify (good for tool debugging).
  • Files for each identified hash type - each file contains a list of hashes. The -hc/--hashcat argument will append the hashcat mode (if found) to the filename.
hashtag output directory

Resources: Quite a bit of research went into the difference between password hash types. During this research I found a script called Hash Identifier which was actually included in one of the Backtrack versions. After looking it over I feel my tool has a lot more functionality, efficiency, and accuracy. My other research ranged from finding different hash examples to generating my own hashes via the passlib module. I would like to give credit to the following resources which all had some impact in the creation of this tool.

As always, if you see any coding errors, false assumptions (hash identification), or have constructive criticism please contact me. Hope you like it!


  1. #!/usr/bin/python is very much wrong: python almost never exists in /usr/bin and usually exists in /usr/local/bin.

    #!/usr/bin/env python is better. This assumes it functions with python 2 both 2 and 3. For just python 3 use #!/usr/bin/env python3

    1. this comment is very much wrong. modern linux distributions started aggregating binaries in /usr/bin.

      $> which python

      however the env method should be considered.

    2. Just to nitpick - see the first image; he's running this on WinX in cmd.exe which means the shebang path is ignored, though python will read any shebang line flags/parameters that are set.

  2. this guy goes out of his way to write this and you bitch about his first line of code...fuck you bob.

    Awesome job btw I hate having to remember hash cats syntax

  3. In the your first case study, there is an error as following...

    MacBook-Air:hashtag v0n$ python -sh $1$MtCReiOj$zvOdxVzPtrQ.PXNW3hTHI0

    Hash not found: .PXNW3hTHI0
    MacBook-Air:hashtag v0n$

    1. thk for the script !
      but i have the same error with cygwin :

      xx@yy ~$ python
      Python 2.7.5 (default, Oct 2 2013, 22:34:09)
      [GCC 4.8.1] on cygwin
      Type "help", "copyright", "credits" or "license" for more information.
      [1]+ Stopped python
      xx@yy ~$ python -sh $1$MtCReiOj$zvOdxVzPtrQ.PXNW3hTHI0

      Hash not found: .PXNW3hTHI0

    2. Thanks for the feedback. This only occurs on linux systems depending on the input. Just use single uninterpolated single quotes around the hash.


      python -sh '$1$MtCReiOj$zvOdxVzPtrQ.PXNW3hTHI0'

    3. thank you ! it's perfect with single quotes

  4. Thanks for creating this and sharing! Very useful :)

  5. This is awesome. Thanks for taking the time.

  6. It seems the sooner some jerkoff with aspergers makes a comment on semantics, the better the tools is, so I have high hopes! Thanks for taking the time to make this and put it out there.