Files
hate_crack/hate_crack.py
T

2043 lines
82 KiB
Python
Executable File

#!/usr/bin/env python3
# Methodology provided by Martin Bos (pure_hate) - https://www.trustedsec.com/team/martin-bos/
# Original script created by Larry Spohn (spoonman) - https://www.trustedsec.com/team/larry-spohn/
# Python refactoring and general fixing, Justin Bollinger (bandrel) - https://www.trustedsec.com/team/justin-bollinger/
# Hashview integration by Justin Bollinger (bandrel) and Claude Sonnet 4.5
# special thanks to hans for all his hard work on hashview and creating APIs for us to use
import subprocess
import sys
import os
import random
import re
import json
import binascii
import shutil
try:
import requests
REQUESTS_AVAILABLE = True
except ImportError:
REQUESTS_AVAILABLE = False
# python2/3 compatability
try:
input = raw_input
except NameError:
pass
hate_path = os.path.dirname(os.path.realpath(__file__))
if not os.path.isfile(hate_path + '/config.json'):
print('Initializing config.json from config.json.example')
shutil.copy(hate_path + '/config.json.example',hate_path + '/config.json')
with open(hate_path + '/config.json') as config:
config_parser = json.load(config)
with open(hate_path + '/config.json.example') as defaults:
default_config = json.load(defaults)
hcatPath = config_parser['hcatPath']
hcatBin = config_parser['hcatBin']
hcatTuning = config_parser['hcatTuning']
hcatWordlists = config_parser['hcatWordlists']
hcatOptimizedWordlists = config_parser['hcatOptimizedWordlists']
hcatRules = []
try:
maxruntime = config_parser['bandrelmaxruntime']
except KeyError as e:
print('{0} is not defined in config.json using defaults from config.json.example'.format(e))
maxruntime = default_config['bandrelmaxruntime']
try:
bandrelbasewords = config_parser['bandrel_common_basedwords']
except KeyError as e:
print('{0} is not defined in config.json using defaults from config.json.example'.format(e))
bandrelbasewords = default_config['bandrel_common_basedwords']
try:
pipal_count = config_parser['pipal_count']
except KeyError as e:
print('{0} is not defined in config.json using defaults from config.json.example'.format(e))
pipal_count = default_config['pipal_count']
try:
pipalPath = config_parser['pipalPath']
except KeyError as e:
print('{0} is not defined in config.json using defaults from config.json.example'.format(e))
pipalPath = default_config['pipalPath']
try:
hcatDictionaryWordlist = config_parser['hcatDictionaryWordlist']
except KeyError as e:
print('{0} is not defined in config.json using defaults from config.json.example'.format(e))
hcatDictionaryWordlist = default_config['hcatDictionaryWordlist']
try:
hcatHybridlist = config_parser['hcatHybridlist']
except KeyError as e:
print('{0} is not defined in config.json using defaults from config.json.example'.format(e))
hcatHybridlist = default_config[e.args[0]]
try:
hcatCombinationWordlist = config_parser['hcatCombinationWordlist']
except KeyError as e:
print('{0} is not defined in config.json using defaults from config.json.example'.format(e))
hcatCombinationWordlist = default_config[e.args[0]]
try:
hcatMiddleCombinatorMasks = config_parser['hcatMiddleCombinatorMasks']
except KeyError as e:
print('{0} is not defined in config.json using defaults from config.json.example'.format(e))
hcatMiddleCombinatorMasks = default_config[e.args[0]]
try:
hcatMiddleBaseList = config_parser['hcatMiddleBaseList']
except KeyError as e:
print('{0} is not defined in config.json using defaults from config.json.example'.format(e))
hcatMiddleBaseList = default_config[e.args[0]]
try:
hcatThoroughCombinatorMasks = config_parser['hcatThoroughCombinatorMasks']
except KeyError as e:
print('{0} is not defined in config.json using defaults from config.json.example'.format(e))
hcatThoroughCombinatorMasks = default_config[e.args[0]]
try:
hcatThoroughBaseList = config_parser['hcatThoroughBaseList']
except KeyError as e:
print('{0} is not defined in config.json using defaults from config.json.example'.format(e))
hcatThoroughBaseList = default_config[e.args[0]]
try:
hcatPrinceBaseList = config_parser['hcatPrinceBaseList']
except KeyError as e:
print('{0} is not defined in config.json using defaults from config.json.example'.format(e))
hcatPrinceBaseList = default_config[e.args[0]]
try:
hcatGoodMeasureBaseList = config_parser['hcatGoodMeasureBaseList']
except KeyError as e:
print('{0} is not defined in config.json using defaults from config.json.example'.format(e))
hcatGoodMeasureBaseList = default_config[e.args[0]]
try:
hashview_url = config_parser['hashview_url']
except KeyError as e:
print('{0} is not defined in config.json using defaults from config.json.example'.format(e))
hashview_url = default_config.get('hashview_url', 'https://localhost:8443')
try:
hashview_api_key = config_parser['hashview_api_key']
except KeyError as e:
print('{0} is not defined in config.json using defaults from config.json.example'.format(e))
hashview_api_key = default_config.get('hashview_api_key', '')
hcatExpanderBin = "expander.bin"
hcatCombinatorBin = "combinator.bin"
hcatPrinceBin = "pp64.bin"
def verify_wordlist_dir(directory, wordlist):
if os.path.isfile(wordlist):
return wordlist
elif os.path.isfile(directory + '/' + wordlist):
return directory + '/' + wordlist
else:
print('Invalid path for {0}. Please check configuration and try again.'.format(wordlist))
quit(1)
# hashcat biniary checks for systems that install hashcat binary in different location than the rest of the hashcat files
if os.path.isfile(hcatBin):
pass
elif os.path.isfile(hcatPath.rstrip('/') + '/' + hcatBin):
hcatBin = hcatPath.rstrip('/') + '/' + hcatBin
else:
print('Invalid path for hashcat binary. Please check configuration and try again.')
quit(1)
#verify and convert wordlists to fully qualified paths
hcatMiddleBaseList = verify_wordlist_dir(hcatWordlists, hcatMiddleBaseList)
hcatThoroughBaseList = verify_wordlist_dir(hcatWordlists, hcatThoroughBaseList)
hcatPrinceBaseList = verify_wordlist_dir(hcatWordlists, hcatPrinceBaseList)
hcatGoodMeasureBaseList = verify_wordlist_dir(hcatWordlists, hcatGoodMeasureBaseList)
for x in range(len(hcatDictionaryWordlist)):
hcatDictionaryWordlist[x] = verify_wordlist_dir(hcatWordlists, hcatDictionaryWordlist[x])
for x in range(len(hcatHybridlist)):
hcatHybridlist[x] = verify_wordlist_dir(hcatWordlists, hcatHybridlist[x])
hcatCombinationWordlist[0] = verify_wordlist_dir(hcatWordlists, hcatCombinationWordlist[0])
hcatCombinationWordlist[1] = verify_wordlist_dir(hcatWordlists, hcatCombinationWordlist[1])
hcatHashCount = 0
hcatHashCracked = 0
hcatBruteCount = 0
hcatDictionaryCount = 0
hcatMaskCount = 0
hcatFingerprintCount = 0
hcatCombinationCount = 0
hcatHybridCount = 0
hcatExtraCount = 0
hcatRecycleCount = 0
hcatProcess = 0
# Help
def usage():
print("usage: python hate_crack.py <hash_file> <hash_type>")
print("\nThe <hash_type> is attained by running \"{hcatBin} --help\"\n".format(hcatBin=hcatBin))
print("Example Hashes: http://hashcat.net/wiki/doku.php?id=example_hashes\n")
def ascii_art():
print(r"""
___ ___ __ _________ __
/ | \_____ _/ |_ ____ \_ ___ \____________ ____ | | __
/ ~ \__ \\ __\/ __ \ / \ \/\_ __ \__ \ _/ ___\| |/ /
\ Y // __ \| | \ ___/ \ \____| | \// __ \\ \___| <
\___|_ /(____ /__| \___ >____\______ /|__| (____ /\___ >__|_ \
\/ \/ \/_____/ \/ \/ \/ \/
Version 1.09
""")
# Counts the number of lines in a file
def lineCount(file):
try:
with open(file) as outFile:
count = 0
for line in outFile:
count = count + 1
return count
except:
return 0
# Brute Force Attack
def hcatBruteForce(hcatHashType, hcatHashFile, hcatMinLen, hcatMaxLen):
global hcatBruteCount
global hcatProcess
hcatProcess = subprocess.Popen(
"{hcbin} -m {hash_type} {hash_file} --session {session_name} -o {hash_file}.out --increment --increment-min={min} "
"--increment-max={max} -a 3 ?a?a?a?a?a?a?a?a?a?a?a?a?a?a {tuning} --potfile-path={hate_path}/hashcat.pot".format(
hcbin=hcatBin,
hash_type=hcatHashType,
hash_file=hcatHashFile,
session_name=os.path.basename(hcatHashFile),
min=hcatMinLen,
max=hcatMaxLen,
tuning=hcatTuning,
hate_path=hate_path), shell=True)
try:
hcatProcess.wait()
except KeyboardInterrupt:
print('Killing PID {0}...'.format(str(hcatProcess.pid)))
hcatProcess.kill()
hcatBruteCount = lineCount(hcatHashFile + ".out")
# Dictionary Attack
def hcatDictionary(hcatHashType, hcatHashFile):
global hcatDictionaryCount
global hcatProcess
hcatProcess = subprocess.Popen(
"{hcatBin} -m {hcatHashType} {hash_file} --session {session_name} -o {hash_file}.out {optimized_wordlists}/* "
"-r {hcatPath}/rules/best66.rule {tuning} --potfile-path={hate_path}/hashcat.pot".format(
hcatPath=hcatPath,
hcatBin=hcatBin,
hcatHashType=hcatHashType,
hash_file=hcatHashFile,
session_name=os.path.basename(hcatHashFile),
optimized_wordlists=hcatOptimizedWordlists,
tuning=hcatTuning,
hate_path=hate_path), shell=True)
try:
hcatProcess.wait()
except KeyboardInterrupt:
print('Killing PID {0}...'.format(str(hcatProcess.pid)))
hcatProcess.kill()
for wordlist in hcatDictionaryWordlist:
hcatProcess = subprocess.Popen(
"{hcatBin} -m {hcatHashType} {hash_file} --session {session_name} -o {hash_file}.out {hcatWordlist} "
"-r {hcatPath}/rules/d3ad0ne.rule {tuning} --potfile-path={hate_path}/hashcat.pot".format(
hcatPath=hcatPath,
hcatBin=hcatBin,
hcatHashType=hcatHashType,
hash_file=hcatHashFile,
session_name=os.path.basename(hcatHashFile),
hcatWordlist=wordlist,
tuning=hcatTuning,
hate_path=hate_path), shell=True)
try:
hcatProcess.wait()
except KeyboardInterrupt:
print('Killing PID {0}...'.format(str(hcatProcess.pid)))
hcatProcess.kill()
hcatProcess = subprocess.Popen(
"{hcatBin} -m {hcatHashType} {hash_file} --session {session_name} -o {hash_file}.out {hcatWordlist} "
"-r {hcatPath}/rules/T0XlC.rule {tuning} --potfile-path={hate_path}/hashcat.pot".format(
hcatPath=hcatPath,
hcatBin=hcatBin,
hcatHashType=hcatHashType,
hash_file=hcatHashFile,
session_name=os.path.basename(hcatHashFile),
hcatWordlist=wordlist,
tuning=hcatTuning,
hate_path=hate_path), shell=True)
try:
hcatProcess.wait()
except KeyboardInterrupt:
print('Killing PID {0}...'.format(str(hcatProcess.pid)))
hcatProcess.kill()
hcatDictionaryCount = lineCount(hcatHashFile + ".out") - hcatBruteCount
# Quick Dictionary Attack (Optional Chained Rules)
def hcatQuickDictionary(hcatHashType, hcatHashFile, hcatChains, wordlists):
global hcatProcess
hcatProcess = subprocess.Popen(
"{hcatBin} -m {hcatHashType} {hash_file} --session {session_name} -o {hash_file}.out "
"'{wordlists}' {chains} {tuning} --potfile-path={hate_path}/hashcat.pot".format(
hcatBin=hcatBin,
hcatHashType=hcatHashType,
hash_file=hcatHashFile,
session_name=os.path.basename(hcatHashFile),
wordlists=wordlists,
chains=hcatChains,
tuning=hcatTuning,
hate_path=hate_path), shell=True)
try:
hcatProcess.wait()
except KeyboardInterrupt:
print('Killing PID {0}...'.format(str(hcatProcess.pid)))
hcatProcess.kill()
# Top Mask Attack
def hcatTopMask(hcatHashType, hcatHashFile, hcatTargetTime):
global hcatMaskCount
global hcatProcess
subprocess.Popen(
"cat {hash_file}.out | cut -d : -f 2 > {hash_file}.working".format(
hash_file=hcatHashFile), shell=True).wait()
hcatProcess = subprocess.Popen(
"{hate_path}/PACK/statsgen.py {hash_file}.working -o {hash_file}.masks".format(
hash_file=hcatHashFile,
hate_path=hate_path), shell=True)
try:
hcatProcess.wait()
except KeyboardInterrupt:
print('Killing PID {0}...'.format(str(hcatProcess.pid)))
hcatProcess.kill()
hcatProcess = subprocess.Popen(
"{hate_path}/PACK/maskgen.py {hash_file}.masks --targettime {target_time} --optindex -q --pps 14000000000 "
"--minlength=7 -o {hash_file}.hcmask".format(
hash_file=hcatHashFile,
target_time=hcatTargetTime,
hate_path=hate_path), shell=True)
try:
hcatProcess.wait()
except KeyboardInterrupt:
print('Killing PID {0}...'.format(str(hcatProcess.pid)))
hcatProcess.kill()
hcatProcess = subprocess.Popen(
"{hcatBin} -m {hash_type} {hash_file} --session {session_name} -o {hash_file}.out -a 3 {hash_file}.hcmask {tuning} "
"--potfile-path={hate_path}/hashcat.pot".format(
hcatBin=hcatBin,
hash_type=hcatHashType,
hash_file=hcatHashFile,
session_name=os.path.basename(hcatHashFile),
tuning=hcatTuning,
hate_path=hate_path), shell=True)
try:
hcatProcess.wait()
except KeyboardInterrupt:
print('Killing PID {0}...'.format(str(hcatProcess.pid)))
hcatProcess.kill()
hcatMaskCount = lineCount(hcatHashFile + ".out") - hcatHashCracked
# Fingerprint Attack
def hcatFingerprint(hcatHashType, hcatHashFile):
global hcatFingerprintCount
global hcatProcess
crackedBefore = lineCount(hcatHashFile + ".out")
crackedAfter = 0
while crackedBefore != crackedAfter:
crackedBefore = lineCount(hcatHashFile + ".out")
subprocess.Popen("cat {hash_file}.out | cut -d : -f 2 > {hash_file}.working".format(
hash_file=hcatHashFile), shell=True).wait()
hcatProcess = subprocess.Popen(
"{hate_path}/hashcat-utils/bin/{expander_bin} < {hash_file}.working | sort -u > {hash_file}.expanded".format(
expander_bin=hcatExpanderBin,
hash_file=hcatHashFile,
hate_path=hate_path), shell=True)
try:
hcatProcess.wait()
except KeyboardInterrupt:
print('Killing PID {0}...'.format(str(hcatProcess.pid)))
hcatProcess.kill()
hcatProcess = subprocess.Popen(
"{hcatBin} -m {hash_type} {hash_file} --session {session_name} -o {hash_file}.out -a 1 {hash_file}.expanded "
"{hash_file}.expanded {tuning} --potfile-path={hate_path}/hashcat.pot".format(
hcatBin=hcatBin,
hash_type=hcatHashType,
hash_file=hcatHashFile,
session_name=os.path.basename(hcatHashFile),
tuning=hcatTuning,
hate_path=hate_path), shell=True)
try:
hcatProcess.wait()
except KeyboardInterrupt:
print('Killing PID {0}...'.format(str(hcatProcess.pid)))
hcatProcess.kill()
crackedAfter = lineCount(hcatHashFile + ".out")
hcatFingerprintCount = lineCount(hcatHashFile + ".out") - hcatHashCracked
# Combinator Attack
def hcatCombination(hcatHashType, hcatHashFile):
global hcatCombinationCount
global hcatProcess
hcatProcess = subprocess.Popen(
"{hcatBin} -m {hash_type} {hash_file} --session {session_name} -o {hash_file}.out -a 1 {left} "
"{right} {tuning} --potfile-path={hate_path}/hashcat.pot".format(
hcatBin=hcatBin,
hash_type=hcatHashType,
hash_file=hcatHashFile,
session_name=os.path.basename(hcatHashFile),
word_lists=hcatWordlists,
left=hcatCombinationWordlist[0],
right=hcatCombinationWordlist[1],
tuning=hcatTuning,
hate_path=hate_path),
shell=True)
try:
hcatProcess.wait()
except KeyboardInterrupt:
print('Killing PID {0}...'.format(str(hcatProcess.pid)))
hcatProcess.kill()
hcatCombinationCount = lineCount(hcatHashFile + ".out") - hcatHashCracked
# Hybrid Attack
def hcatHybrid(hcatHashType, hcatHashFile):
global hcatHybridCount
global hcatProcess
for wordlist in hcatHybridlist:
hcatProcess = subprocess.Popen(
"{hcatBin} -m {hash_type} {hash_file} --session {session_name} -o {hash_file}.out -a 6 -1 ?s?d {wordlist} ?1?1 "
"{tuning} --potfile-path={hate_path}/hashcat.pot".format(
hcatBin=hcatBin,
hash_type=hcatHashType,
hash_file=hcatHashFile,
session_name=os.path.basename(hcatHashFile),
wordlist=wordlist,
tuning=hcatTuning,
hate_path=hate_path), shell=True)
try:
hcatProcess.wait()
except KeyboardInterrupt:
print('Killing PID {0}...'.format(str(hcatProcess.pid)))
hcatProcess.kill()
hcatProcess = subprocess.Popen(
"{hcatBin} -m {hash_type} {hash_file} --session {session_name} -o {hash_file}.out -a 6 -1 ?s?d {wordlist} ?1?1?1 "
"{tuning} --potfile-path={hate_path}/hashcat.pot".format(
hcatBin=hcatBin,
hash_type=hcatHashType,
hash_file=hcatHashFile,
session_name=os.path.basename(hcatHashFile),
wordlist=wordlist,
tuning=hcatTuning,
hate_path=hate_path), shell=True)
try:
hcatProcess.wait()
except KeyboardInterrupt:
print('Killing PID {0}...'.format(str(hcatProcess.pid)))
hcatProcess.kill()
hcatProcess = subprocess.Popen(
"{hcatBin} -m {hash_type} {hash_file} --session {session_name} -o {hash_file}.out -a 6 -1 ?s?d {wordlist} "
"?1?1?1?1 {tuning} --potfile-path={hate_path}/hashcat.pot".format(
hcatBin=hcatBin,
hash_type=hcatHashType,
hash_file=hcatHashFile,
session_name=os.path.basename(hcatHashFile),
wordlist=wordlist,
tuning=hcatTuning,
hate_path=hate_path), shell=True)
try:
hcatProcess.wait()
except KeyboardInterrupt:
print('Killing PID {0}...'.format(str(hcatProcess.pid)))
hcatProcess.kill()
hcatProcess = subprocess.Popen(
"{hcatBin} -m {hash_type} {hash_file} --session {session_name} -o {hash_file}.out -a 7 -1 ?s?d ?1?1 {wordlist} "
"{tuning} --potfile-path={hate_path}/hashcat.pot".format(
hcatBin=hcatBin,
hash_type=hcatHashType,
hash_file=hcatHashFile,
session_name=os.path.basename(hcatHashFile),
wordlist=wordlist,
tuning=hcatTuning,
hate_path=hate_path), shell=True)
try:
hcatProcess.wait()
except KeyboardInterrupt:
print('Killing PID {0}...'.format(str(hcatProcess.pid)))
hcatProcess.kill()
hcatProcess = subprocess.Popen(
"{hcatBin} -m {hash_type} {hash_file} --session {session_name} -o {hash_file}.out -a 7 -1 ?s?d ?1?1?1 {wordlist} "
"{tuning} --potfile-path={hate_path}/hashcat.pot".format(
hcatBin=hcatBin,
hash_type=hcatHashType,
hash_file=hcatHashFile,
session_name=os.path.basename(hcatHashFile),
wordlist=wordlist,
tuning=hcatTuning,
hate_path=hate_path), shell=True)
try:
hcatProcess.wait()
except KeyboardInterrupt:
print('Killing PID {0}...'.format(str(hcatProcess.pid)))
hcatProcess.kill()
hcatProcess = subprocess.Popen(
"{hcatBin} -m {hash_type} {hash_file} --session {session_name} -o {hash_file}.out -a 7 -1 ?s?d ?1?1?1?1 {wordlist} "
"{tuning} --potfile-path={hate_path}/hashcat.pot".format(
hcatBin=hcatBin,
hash_type=hcatHashType,
hash_file=hcatHashFile,
session_name=os.path.basename(hcatHashFile),
wordlist=wordlist,
tuning=hcatTuning,
hate_path=hate_path), shell=True)
try:
hcatProcess.wait()
except KeyboardInterrupt:
print('Killing PID {0}...'.format(str(hcatProcess.pid)))
hcatProcess.kill()
hcatHybridCount = lineCount(hcatHashFile + ".out") - hcatHashCracked
# YOLO Combination Attack
def hcatYoloCombination(hcatHashType, hcatHashFile):
global hcatProcess
try:
while 1:
hcatLeft = random.choice(os.listdir(hcatOptimizedWordlists))
hcatRight = random.choice(os.listdir(hcatOptimizedWordlists))
hcatProcess = subprocess.Popen(
"{hcatBin} -m {hash_type} {hash_file} --session {session_name} -o {hash_file}.out -a 1 {optimized_lists}/{left} "
"{optimized_lists}/{right} {tuning} --potfile-path={hate_path}/hashcat.pot".format(
hcatBin=hcatBin,
hash_type=hcatHashType,
hash_file=hcatHashFile,
session_name=os.path.basename(hcatHashFile),
word_lists=hcatWordlists,
optimized_lists=hcatOptimizedWordlists,
tuning=hcatTuning,
left=hcatLeft,
right=hcatRight,
hate_path=hate_path), shell=True)
try:
hcatProcess.wait()
except KeyboardInterrupt:
print('Killing PID {0}...'.format(str(hcatProcess.pid)))
hcatProcess.kill()
raise
except KeyboardInterrupt:
pass
# Bandrel methodlogy
def hcatBandrel(hcatHashType, hcatHashFile):
global hcatProcess
basewords = []
while True:
company_name = input('What is the company name (Enter multiples comma separated)? ')
if company_name:
break
for name in company_name.split(','):
basewords.append(name)
for word in bandrelbasewords.split(','):
basewords.append(word)
for name in basewords:
mask1 = '-1{0}{1}'.format(name[0].lower(),name[0].upper())
mask2 = ' ?1{0}'.format(name[1:])
for x in range(6):
mask2 += '?a'
hcatProcess = subprocess.Popen(
"{hcatBin} -m {hash_type} -a 3 --session {session_name} -o {hash_file}.out "
"{tuning} --potfile-path={hate_path}/hashcat.pot --runtime {maxruntime} -i {hcmask1} {hash_file} {hcmask2}".format(
hcatBin=hcatBin,
hash_type=hcatHashType,
hash_file=hcatHashFile,
session_name=os.path.basename(hcatHashFile),
tuning=hcatTuning,
hcmask1=mask1,
hcmask2=mask2,
maxruntime=maxruntime,
hate_path=hate_path), shell=True)
try:
hcatProcess.wait()
except KeyboardInterrupt:
print('Killing PID {0}...'.format(str(hcatProcess.pid)))
hcatProcess.kill()
print('Checking passwords against pipal for top {0} passwords and basewords'.format(pipal_count))
pipal_basewords = pipal()
for word in pipal_basewords:
mask1 = '-1={0}{1}'.format(word[0].lower(),word[0].upper())
mask2 = ' ?1{0}'.format(word[1:])
for x in range(6):
mask2 += '?a'
hcatProcess = subprocess.Popen(
"{hcatBin} -m {hash_type} -a 3 --session {session_name} -o {hash_file}.out "
"{tuning} --potfile-path={hate_path}/hashcat.pot --runtime {maxruntime} -i {hcmask1} {hash_file} {hcmask2}".format(
hcatBin=hcatBin,
hash_type=hcatHashType,
hash_file=hcatHashFile,
session_name=os.path.basename(hcatHashFile),
tuning=hcatTuning,
hcmask1=mask1,
hcmask2=mask2,
maxruntime=maxruntime,
hate_path=hate_path), shell=True)
try:
hcatProcess.wait()
except KeyboardInterrupt:
print('Killing PID {0}...'.format(str(hcatProcess.pid)))
hcatProcess.kill()
# Middle fast Combinator Attack
def hcatMiddleCombinator(hcatHashType, hcatHashFile):
global hcatProcess
masks = hcatMiddleCombinatorMasks
# Added support for multiple character masks
new_masks = []
for mask in masks:
tmp = []
if len(mask) > 1:
for character in mask:
tmp.append(character)
new_masks.append('$' + '$'.join(tmp))
else:
new_masks.append('$'+mask)
masks = new_masks
try:
for x in range(len(masks)):
hcatProcess = subprocess.Popen(
"{hcatBin} -m {hash_type} {hash_file} --session {session_name} -o {hash_file}.out -a 1 -j '${middle_mask}' {left} "
"{right} --potfile-path={hate_path}/hashcat.pot".format(
hcatBin=hcatBin,
hash_type=hcatHashType,
hash_file=hcatHashFile,
session_name=os.path.basename(hcatHashFile),
left=hcatMiddleBaseList,
right=hcatMiddleBaseList,
tuning=hcatTuning,
middle_mask=masks[x],
hate_path=hate_path),
shell=True)
try:
hcatProcess.wait()
except KeyboardInterrupt:
print('Killing PID {0}...'.format(str(hcatProcess.pid)))
hcatProcess.kill()
raise
except KeyboardInterrupt:
pass
# Middle thorough Combinator Attack
def hcatThoroughCombinator(hcatHashType, hcatHashFile):
global hcatProcess
masks = hcatThoroughCombinatorMasks
# Added support for multiple character masks
new_masks = []
for mask in masks:
tmp = []
if len(mask) > 1:
for character in mask:
tmp.append(character)
new_masks.append('$' + '$'.join(tmp))
else:
new_masks.append('$'+mask)
masks = new_masks
hcatProcess = subprocess.Popen(
"{hcatBin} -m {hash_type} {hash_file} --session {session_name} -o {hash_file}.out -a 1 {left} "
"{right} {tuning} --potfile-path={hate_path}/hashcat.pot".format(
hcatBin=hcatBin,
hash_type=hcatHashType,
hash_file=hcatHashFile,
session_name=os.path.basename(hcatHashFile),
left=hcatThoroughBaseList,
right=hcatThoroughBaseList,
word_lists=hcatWordlists,
tuning=hcatTuning,
hate_path=hate_path),
shell=True)
try:
hcatProcess.wait()
except KeyboardInterrupt:
print('Killing PID {0}...'.format(str(hcatProcess.pid)))
hcatProcess.kill()
try:
for x in range(len(masks)):
hcatProcess = subprocess.Popen(
"{hcatBin} -m {hash_type} {hash_file} --session {session_name} -o {hash_file}.out -a 1 "
"-j '${middle_mask}' {left} {right} --potfile-path={hate_path}/hashcat.pot".format(
hcatBin=hcatBin,
hash_type=hcatHashType,
hash_file=hcatHashFile,
session_name=os.path.basename(hcatHashFile),
left=hcatThoroughBaseList,
right=hcatThoroughBaseList,
word_lists=hcatWordlists,
tuning=hcatTuning,
middle_mask=masks[x],
hate_path=hate_path),
shell=True)
try:
hcatProcess.wait()
except KeyboardInterrupt:
print('Killing PID {0}...'.format(str(hcatProcess.pid)))
hcatProcess.kill()
raise
except KeyboardInterrupt:
pass
try:
for x in range(len(masks)):
hcatProcess = subprocess.Popen(
"{hcatBin} -m {hash_type} {hash_file} --session {session_name} -o {hash_file}.out -a 1 "
"-k '${end_mask}' {left} {right} {tuning} --potfile-path={hate_path}/hashcat.pot".format(
hcatBin=hcatBin,
hash_type=hcatHashType,
hash_file=hcatHashFile,
session_name=os.path.basename(hcatHashFile),
left=hcatThoroughBaseList,
right=hcatThoroughBaseList,
word_lists=hcatWordlists,
tuning=hcatTuning,
end_mask=masks[x],
hate_path=hate_path),
shell=True)
try:
hcatProcess.wait()
except KeyboardInterrupt:
print('Killing PID {0}...'.format(str(hcatProcess.pid)))
hcatProcess.kill()
raise
except KeyboardInterrupt:
pass
try:
for x in range(len(masks)):
hcatProcess = subprocess.Popen(
"{hcatBin} -m {hash_type} {hash_file} --session {session_name} -o {hash_file}.out -a 1 "
"-j '${middle_mask}' -k '${end_mask}' {left} {right} {tuning} --potfile-path={hate_path}/hashcat.pot".format(
hcatBin=hcatBin,
hash_type=hcatHashType,
hash_file=hcatHashFile,
session_name=os.path.basename(hcatHashFile),
left=hcatThoroughBaseList,
right=hcatThoroughBaseList,
word_lists=hcatWordlists,
tuning=hcatTuning,
middle_mask=masks[x],
end_mask=masks[x],
hate_path=hate_path),
shell=True)
hcatProcess.wait()
except KeyboardInterrupt:
print('Killing PID {0}...'.format(str(hcatProcess.pid)))
hcatProcess.kill()
# Pathwell Mask Brute Force Attack
def hcatPathwellBruteForce(hcatHashType, hcatHashFile):
global hcatProcess
hcatProcess = subprocess.Popen(
"{hcatBin} -m {hash_type} {hash_file} --session {session_name} -o {hash_file}.out -a 3 {hate_path}/masks/pathwell.hcmask "
"{tuning} --potfile-path={hate_path}/hashcat.pot".format(
hcatBin=hcatBin,
hash_type=hcatHashType,
hash_file=hcatHashFile,
session_name=os.path.basename(hcatHashFile),
tuning=hcatTuning,
hate_path=hate_path), shell=True)
try:
hcatProcess.wait()
except KeyboardInterrupt:
print('Killing PID {0}...'.format(str(hcatProcess.pid)))
hcatProcess.kill()
# PRINCE Attack
def hcatPrince(hcatHashType, hcatHashFile):
global hcatProcess
hcatHashCracked = lineCount(hcatHashFile + ".out")
hcatProcess = subprocess.Popen(
"{hate_path}/princeprocessor/{prince_bin} --case-permute --elem-cnt-min=1 --elem-cnt-max=16 -c < "
"{hcatPrinceBaseList} | {hcatBin} -m {hash_type} {hash_file} --session {session_name} -o {hash_file}.out "
"-r {hate_path}/princeprocessor/rules/prince_optimized.rule {tuning} --potfile-path={hate_path}/hashcat.pot".format(
hcatBin=hcatBin,
prince_bin=hcatPrinceBin,
hash_type=hcatHashType,
hash_file=hcatHashFile,
session_name=os.path.basename(hcatHashFile),
hcatPrinceBaseList=hcatPrinceBaseList,
tuning=hcatTuning,
hate_path=hate_path), shell=True)
try:
hcatProcess.wait()
except KeyboardInterrupt:
print('Killing PID {0}...'.format(str(hcatProcess.pid)))
hcatProcess.kill()
# Extra - Good Measure
def hcatGoodMeasure(hcatHashType, hcatHashFile):
global hcatExtraCount
global hcatProcess
hcatProcess = subprocess.Popen(
"{hcatBin} -m {hash_type} {hash_file} --session {session_name} -o {hash_file}.out -r {hcatPath}/rules/combinator.rule "
"-r {hcatPath}/rules/InsidePro-PasswordsPro.rule {hcatGoodMeasureBaseList} {tuning} "
"--potfile-path={hate_path}/hashcat.pot".format(
hcatPath=hcatPath,
hcatBin=hcatBin,
hash_type=hcatHashType,
hash_file=hcatHashFile,
hcatGoodMeasureBaseList=hcatGoodMeasureBaseList,
session_name=os.path.basename(hcatHashFile),
word_lists=hcatWordlists,
tuning=hcatTuning,
hate_path=hate_path), shell=True)
try:
hcatProcess.wait()
except KeyboardInterrupt:
print('Killing PID {0}...'.format(str(hcatProcess.pid)))
hcatProcess.kill()
hcatExtraCount = lineCount(hcatHashFile + ".out") - hcatHashCracked
# LanMan to NT Attack
def hcatLMtoNT():
global hcatProcess
hcatProcess = subprocess.Popen(
"{hcatBin} --show --potfile-path={hate_path}/hashcat.pot -m 3000 {hash_file}.lm > {hash_file}.lm.cracked".format(
hcatBin=hcatBin,
hash_file=hcatHashFile,
hate_path=hate_path), shell=True)
try:
hcatProcess.wait()
except KeyboardInterrupt:
print('Killing PID {0}...'.format(str(hcatProcess.pid)))
hcatProcess.kill()
hcatProcess = subprocess.Popen(
"{hcatBin} -m 3000 {hash_file}.lm --session {session_name} -o {hash_file}.lm.cracked -1 ?u?d?s --increment -a 3 ?1?1?1?1?1?1?1 "
"{tuning} --potfile-path={hate_path}/hashcat.pot".format(
hcatBin=hcatBin,
hash_file=hcatHashFile,
session_name=os.path.basename(hcatHashFile),
tuning=hcatTuning,
hate_path=hate_path), shell=True)
try:
hcatProcess.wait()
except KeyboardInterrupt:
hcatProcess.kill()
subprocess.Popen("cat {hash_file}.lm.cracked | cut -d : -f 2 > {hash_file}.working".format(
hash_file=hcatHashFile), shell=True).wait()
converted = convert_hex("{hash_file}.working".format(hash_file=hcatHashFile))
with open("{hash_file}.working".format(hash_file=hcatHashFile),mode='w') as working:
working.writelines('\n'.join(converted))
hcatProcess = subprocess.Popen(
"{hate_path}/hashcat-utils/bin/{combine_bin} {hash_file}.working {hash_file}.working | sort -u > {hash_file}.combined".format(
combine_bin=hcatCombinatorBin,
hcatBin=hcatBin,
hash_file=hcatHashFile,
tuning=hcatTuning,
hate_path=hate_path), shell=True)
try:
hcatProcess.wait()
except KeyboardInterrupt:
print('Killing PID {0}...'.format(str(hcatProcess.pid)))
hcatProcess.kill()
hcatProcess = subprocess.Popen(
"{hcatBin} --show --potfile-path={hate_path}/hashcat.pot -m 1000 {hash_file}.nt > {hash_file}.nt.out".format(
hcatBin=hcatBin,
hash_file=hcatHashFile,
tuning=hcatTuning,
hate_path=hate_path), shell=True)
try:
hcatProcess.wait()
except KeyboardInterrupt:
print('Killing PID {0}...'.format(str(hcatProcess.pid)))
hcatProcess.kill()
hcatProcess = subprocess.Popen(
"{hcatBin} -m 1000 {hash_file}.nt --session {session_name} -o {hash_file}.nt.out {hash_file}.combined "
"-r {hate_path}/rules/toggles-lm-ntlm.rule {tuning} --potfile-path={hate_path}/hashcat.pot".format(
hcatBin=hcatBin,
hash_file=hcatHashFile,
session_name=os.path.basename(hcatHashFile),
tuning=hcatTuning,
hate_path=hate_path), shell=True)
try:
hcatProcess.wait()
except KeyboardInterrupt:
print('Killing PID {0}...'.format(str(hcatProcess.pid)))
hcatProcess.kill()
# toggle-lm-ntlm.rule by Didier Stevens https://blog.didierstevens.com/2016/07/16/tool-to-generate-hashcat-toggle-rules/
# Recycle Cracked Passwords
def hcatRecycle(hcatHashType, hcatHashFile, hcatNewPasswords):
global hcatProcess
working_file = hcatHashFile + '.working'
if hcatNewPasswords > 0:
hcatProcess = subprocess.Popen("cat {hash_file}.out | cut -d : -f 2 > {working_file}".format(
hash_file=hcatHashFile, working_file=working_file), shell=True)
try:
hcatProcess.wait()
except KeyboardInterrupt:
print('Killing PID {0}...'.format(str(hcatProcess.pid)))
hcatProcess.kill()
converted = convert_hex(working_file)
# Overwrite working file with updated converted words
with open(working_file, 'w') as f:
f.write("\n".join(converted))
for rule in hcatRules:
hcatProcess = subprocess.Popen(
"{hcatBin} -m {hash_type} {hash_file} --session {session_name} -o {hash_file}.out {hash_file}.working "
"-r {hcatPath}/rules/{rule} {tuning} --potfile-path={hate_path}/hashcat.pot".format(
rule=rule,
hcatBin=hcatBin,
hash_type=hcatHashType,
hash_file=hcatHashFile,
session_name=os.path.basename(hcatHashFile),
hcatPath=hcatPath,
tuning=hcatTuning,
hate_path=hate_path), shell=True)
try:
hcatProcess.wait()
except KeyboardInterrupt:
hcatProcess.kill()
def check_potfile():
print("Checking POT file for already cracked hashes...")
subprocess.Popen(
"{hcatBin} --show --potfile-path={hate_path}/hashcat.pot -m {hash_type} {hash_file} > {hash_file}.out".format(
hcatBin=hcatBin,
hash_type=hcatHashType,
hash_file=hcatHashFile,
hate_path=hate_path), shell=True)
hcatHashCracked = lineCount(hcatHashFile + ".out")
if hcatHashCracked > 0:
print("Found %d hashes already cracked.\nCopied hashes to %s.out" % (hcatHashCracked, hcatHashFile))
else:
print("No hashes found in POT file.")
# creating the combined output for pwdformat + cleartext
def combine_ntlm_output():
hashes = {}
check_potfile()
with open(hcatHashFile + ".out", "r") as hcatCrackedFile:
for crackedLine in hcatCrackedFile:
hash, password = crackedLine.split(':')
hashes[hash] = password.rstrip()
with open(hcatHashFileOrig + ".out", "w+") as hcatCombinedHashes:
with open(hcatHashFileOrig, "r") as hcatOrigFile:
for origLine in hcatOrigFile:
if origLine.split(':')[3] in hashes:
password = hashes[origLine.split(':')[3]]
hcatCombinedHashes.write(origLine.strip()+password+'\n')
# Cleanup Temp Files
def cleanup():
global pwdump_format
global hcatHashFileOrig
try:
if hcatHashType == "1000" and pwdump_format:
print("\nComparing cracked hashes to original file...")
combine_ntlm_output()
print("\nCracked passwords combined with original hashes in %s" % (hcatHashFileOrig + ".out"))
print('\nCleaning up temporary files...')
if os.path.exists(hcatHashFile + ".masks"):
os.remove(hcatHashFile + ".masks")
if os.path.exists(hcatHashFile + ".working"):
os.remove(hcatHashFile + ".working")
if os.path.exists(hcatHashFile + ".expanded"):
os.remove(hcatHashFile + ".expanded")
if os.path.exists(hcatHashFileOrig + ".combined"):
os.remove(hcatHashFileOrig + ".combined")
if os.path.exists(hcatHashFileOrig + ".lm"):
os.remove(hcatHashFileOrig + ".lm")
if os.path.exists(hcatHashFileOrig + ".lm.cracked"):
os.remove(hcatHashFileOrig + ".lm.cracked")
if os.path.exists(hcatHashFileOrig + ".working"):
os.remove(hcatHashFileOrig + ".working")
if os.path.exists(hcatHashFileOrig + ".passwords"):
os.remove(hcatHashFileOrig + ".passwords")
except KeyboardInterrupt:
#incase someone mashes the Control+C it will still cleanup
cleanup()
# Hashview Integration
class HashviewAPI:
"""Upload files to Hashview API"""
FILE_FORMATS = {
'pwdump': 0,
'netntlm': 1,
'kerberos': 2,
'shadow': 3,
'user:hash': 4,
'hash_only': 5,
}
def __init__(self, base_url, api_key):
self.base_url = base_url.rstrip('/')
self.api_key = api_key
self.agent_uuid = None
self.session = requests.Session()
self.session.cookies.set('uuid', api_key)
# Disable SSL certificate verification for self-signed certificates
self.session.verify = False
# Suppress SSL warnings
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
def use_agent_mode(self):
"""Switch to using agent UUID for operations that require it"""
if not self.agent_uuid:
raise Exception("No agent registered. Call register_agent() first.")
# Switch session to use agent UUID
self.session = self.agent_session
def upload_wordlist(self, file_path, wordlist_name=None):
if wordlist_name is None:
wordlist_name = os.path.basename(file_path)
with open(file_path, 'rb') as f:
file_content = f.read()
url = f"{self.base_url}/v1/wordlists/add/{wordlist_name}"
headers = {'Content-Type': 'text/plain'}
print(f"Uploading wordlist: {os.path.basename(file_path)} -> {wordlist_name}")
response = self.session.post(url, data=file_content, headers=headers)
response.raise_for_status()
return response.json()
def upload_hashfile(self, file_path, customer_id, hash_type, file_format=5, hashfile_name=None):
if hashfile_name is None:
hashfile_name = os.path.basename(file_path)
with open(file_path, 'rb') as f:
file_content = f.read()
url = (
f"{self.base_url}/v1/hashfiles/upload/"
f"{customer_id}/{file_format}/{hash_type}/{hashfile_name}"
)
headers = {'Content-Type': 'text/plain'}
print(f"Uploading hashfile: {os.path.basename(file_path)} -> {hashfile_name}")
response = self.session.post(url, data=file_content, headers=headers)
response.raise_for_status()
return response.json()
def upload_cracked_hashes(self, file_path, hash_type=1000):
# Read and convert file - API expects hex-encoded plaintext (uppercase)
print(f"Importing cracked hashes: {os.path.basename(file_path)}")
print(f" Converting plaintext to hex encoding...")
converted_lines = []
line_count = 0
with open(file_path, 'r', encoding='utf-8', errors='ignore') as f:
for line in f:
line = line.strip()
if not line or ':' not in line:
continue
parts = line.split(':', 1)
if len(parts) != 2:
continue
hash_value = parts[0].strip()
plaintext = parts[1].strip()
# Convert plaintext to hex (uppercase as API expects)
plaintext_hex = plaintext.encode('utf-8').hex().upper()
converted_lines.append(f"{hash_value}:{plaintext_hex}")
line_count += 1
converted_content = '\n'.join(converted_lines)
print(f" Processed {line_count} hash:plaintext pairs")
# Use the actual endpoint from api_routes.py
url = f"{self.base_url}/v1/uploadCrackFile/{hash_type}"
# API expects JSON with 'file' field
payload = {
"file": converted_content
}
headers = {'Content-Type': 'application/json'}
print(f"\n === REQUEST DETAILS ===")
print(f" URL: {url}")
print(f" Method: POST")
print(f" Headers: {headers}")
print(f" Cookies: {dict(self.session.cookies)}")
print(f" Hash type: {hash_type}")
print(f" Payload preview (first 500 chars):")
print(converted_content[:500])
print(f" Uploading...")
response = self.session.post(url, json=payload, headers=headers)
# Debug: print response details
print(f"\n === RESPONSE DETAILS ===")
print(f" Status code: {response.status_code}")
print(f" Response headers: {dict(response.headers)}")
print(f" Response content: {response.text[:500]}")
response.raise_for_status()
# Check if response is JSON error
try:
json_response = response.json()
if 'type' in json_response and json_response['type'] == 'Error':
raise Exception(f"Hashview API Error: {json_response.get('msg', 'Unknown error')}")
return json_response
except (json.JSONDecodeError, ValueError) as e:
# Not valid JSON
raise Exception(f"Invalid API response: {response.text[:200]}")
def list_customers(self):
url = f"{self.base_url}/v1/customers"
print("Fetching customer list...")
response = self.session.get(url)
response.raise_for_status()
data = response.json()
# Parse the 'users' JSON string into a list
if 'users' in data:
customers = json.loads(data['users'])
return {'customers': customers}
return data
def create_customer(self, name, description=""):
url = f"{self.base_url}/v1/customers/add"
headers = {'Content-Type': 'application/json'}
data = {"name": name, "description": description}
print(f"Creating customer: {name}")
response = self.session.post(url, json=data, headers=headers)
response.raise_for_status()
return response.json()
def create_job(self, name, hashfile_id, customer_id, limit_recovered=False, notify_email=True):
url = f"{self.base_url}/v1/jobs/add"
headers = {'Content-Type': 'application/json'}
data = {
"name": name,
"hashfile_id": hashfile_id,
"customer_id": customer_id,
"limit_recovered": limit_recovered,
"notify_email": notify_email,
"notify_pushover": False
}
print(f"Creating job: {name}")
response = self.session.post(url, json=data, headers=headers)
response.raise_for_status()
return response.json()
def start_job(self, job_id):
url = f"{self.base_url}/v1/jobs/start/{job_id}"
print(f"Starting job ID: {job_id}")
response = self.session.post(url)
response.raise_for_status()
return response.json()
def list_jobs(self, customer_id=None):
# The API doesn't have a filter by customer endpoint, get all jobs
url = f"{self.base_url}/v1/jobs"
if customer_id:
print(f"Fetching jobs for customer ID {customer_id}...")
else:
print("Fetching all jobs...")
response = self.session.get(url)
response.raise_for_status()
data = response.json()
# Parse the response - may return 'jobs' as JSON string
if 'jobs' in data and isinstance(data['jobs'], str):
jobs = json.loads(data['jobs'])
# Filter by customer_id if provided
if customer_id:
jobs = [job for job in jobs if job.get('customer_id') == customer_id]
return {'jobs': jobs}
return data
def download_left_hashes(self, customer_id, hashfile_id, output_file=None):
# Use the proper API v1 endpoint for downloading hashfiles (left only)
url = f"{self.base_url}/v1/hashfiles/{hashfile_id}"
print(f"Downloading left hashes...")
print(f" Customer ID: {customer_id}")
print(f" Hashfile ID: {hashfile_id}")
response = self.session.get(url)
# Check if we got HTML (login page) instead of hash data
if response.content.startswith(b'<!DOCTYPE') or response.content.startswith(b'<html'):
raise Exception("Authentication failed - received HTML login page instead of hash data.")
response.raise_for_status()
# Check if response is JSON error message
try:
json_response = response.json()
if 'type' in json_response and json_response['type'] == 'Error':
raise Exception(f"Hashview API Error: {json_response.get('msg', 'Unknown error')}")
except (json.JSONDecodeError, ValueError):
# Not JSON, assume it's the actual hash file content
pass
# If no output file specified, generate one
if output_file is None:
output_file = f"left_{customer_id}_{hashfile_id}.txt"
# Write the content to file
with open(output_file, 'wb') as f:
f.write(response.content)
file_size = len(response.content)
print(f"✓ Downloaded {file_size} bytes to {output_file}")
return {'output_file': output_file, 'size': file_size}
def hashview_upload():
"""Upload data to Hashview API"""
global hcatHashFile, hcatHashType
if not REQUESTS_AVAILABLE:
print("\nError: 'requests' module not found.")
print("Install it with: pip install requests")
return
print("\n" + "="*60)
print("Hashview Integration")
print("="*60)
# Get Hashview connection details from config
if not hashview_api_key:
print("\nError: Hashview API key not configured.")
print("Please set 'hashview_api_key' in config.json")
return
print(f"\nConnecting to Hashview at: {hashview_url}")
try:
uploader = HashviewAPI(hashview_url, hashview_api_key)
while True:
print("\n" + "="*60)
print("What would you like to do?")
print("="*60)
print("\t(1) Upload Cracked Hashes from current session")
print("\t(2) Upload Wordlist")
print("\t(3) Upload Hashfile and Create Job")
print("\t(4) List Customers")
print("\t(5) Create Customer")
print("\t(6) Download Left Hashes")
print("\t(9) Back to Main Menu")
choice = input("\nSelect an option: ")
if choice == '1':
# Upload cracked hashes
print("\n" + "-"*60)
print("Upload Cracked Hashes")
print("-"*60)
# Check if we're in an active session
cracked_file = None
session_file = None
try:
if 'hcatHashFile' in globals() and hcatHashFile:
potential_file = hcatHashFile + ".out"
if os.path.exists(potential_file):
session_file = potential_file
print(f"Found session file: {session_file}")
except:
pass
# Prompt for file
if session_file:
use_session = input(f"Use this file? (Y/n): ").strip().lower()
if use_session != 'n':
cracked_file = session_file
if not cracked_file:
cracked_file = input("Enter path to cracked hashes file (.out format): ").strip()
# Validate file exists
if not os.path.exists(cracked_file):
print(f"✗ Error: File not found: {cracked_file}")
continue
# Show file info
file_size = os.path.getsize(cracked_file)
with open(cracked_file, 'r') as f:
line_count = sum(1 for _ in f)
print(f"File: {cracked_file}")
print(f"Size: {file_size} bytes")
print(f"Lines: {line_count}")
# Hash type is always 1000 (NTLM) for import endpoint
hash_type = 1000
# Check if agent is registered
if not uploader.agent_uuid:
print("\n⚠ Warning: Upload cracked hashes requires agent authorization")
print("You must first:")
print(" 1. Select option (7) to register as an agent")
print(" 2. Authorize the agent in Hashview web UI")
print(" 3. Then come back and upload")
continue
# Switch to agent mode for upload
uploader.use_agent_mode()
# Upload
print(f"\nUploading to Hashview (hash type: {hash_type})...")
try:
result = uploader.upload_cracked_hashes(cracked_file, hash_type)
print(f"\n✓ Success: {result.get('msg', 'Cracked hashes uploaded')}")
if 'count' in result:
print(f" Imported: {result['count']} hashes")
except Exception as e:
print(f"\n✗ Error: {str(e)}")
import traceback
print("\nFull error details:")
traceback.print_exc()
elif choice == '2':
# Upload wordlist
wordlist_path = input("\nEnter path to wordlist file: ")
if not os.path.exists(wordlist_path):
print(f"Error: File not found: {wordlist_path}")
continue
wordlist_name = input(f"Enter wordlist name (default: {os.path.basename(wordlist_path)}): ") or None
try:
result = uploader.upload_wordlist(wordlist_path, wordlist_name)
print(f"\n✓ Success: {result.get('msg', 'Wordlist uploaded')}")
if 'wordlist_id' in result:
print(f" Wordlist ID: {result['wordlist_id']}")
except Exception as e:
print(f"\n✗ Error uploading wordlist: {str(e)}")
elif choice == '3':
# Upload hashfile and create job
hashfile_path = input("\nEnter path to hashfile: ")
if not os.path.exists(hashfile_path):
print(f"Error: File not found: {hashfile_path}")
continue
customer_id = int(input("Enter customer ID: "))
hash_type = int(input(f"Enter hash type (default: {hcatHashType}): ") or hcatHashType)
print("\nFile formats:")
print(" 0 = pwdump, 1 = NetNTLM, 2 = kerberos")
print(" 3 = shadow, 4 = user:hash, 5 = hash_only")
file_format = int(input("Enter file format (default: 5): ") or 5)
hashfile_name = input(f"Enter hashfile name (default: {os.path.basename(hashfile_path)}): ") or None
try:
result = uploader.upload_hashfile(
hashfile_path, customer_id, hash_type, file_format, hashfile_name
)
print(f"\n✓ Success: {result.get('msg', 'Hashfile uploaded')}")
if 'hashfile_id' in result:
print(f" Hashfile ID: {result['hashfile_id']}")
print(f" Hash count: {result.get('hash_count', 'N/A')}")
print(f" Insta-cracked: {result.get('instacracked', 0)}")
# Offer to create a job
create_job = input("\nWould you like to create a job for this hashfile? (Y/n): ") or "Y"
if create_job.upper() == 'Y':
job_name = input("Enter job name: ")
limit_recovered = input("Limit to recovered hashes only? (y/N): ").upper() == 'Y'
notify_email = input("Send email notifications? (Y/n): ").upper() != 'N'
try:
job_result = uploader.create_job(
job_name, result['hashfile_id'], customer_id,
limit_recovered, notify_email
)
print(f"\n✓ Success: {job_result.get('msg', 'Job created')}")
if 'job_id' in job_result:
print(f" Job ID: {job_result['job_id']}")
# Offer to start the job
start_now = input("\nStart the job now? (Y/n): ") or "Y"
if start_now.upper() == 'Y':
start_result = uploader.start_job(job_result['job_id'])
print(f"\n✓ Success: {start_result.get('msg', 'Job started')}")
except Exception as e:
print(f"\n✗ Error creating job: {str(e)}")
except Exception as e:
print(f"\n✗ Error uploading hashfile: {str(e)}")
elif choice == '4':
# List customers
try:
result = uploader.list_customers()
if 'customers' in result and result['customers']:
print("\n" + "="*60)
print("Customers:")
print("="*60)
print(f"{'ID':<10} {'Name':<30} {'Description'}")
print("-" * 60)
for customer in result['customers']:
cust_id = customer.get('id', 'N/A')
cust_name = customer.get('name', 'N/A')
cust_desc = customer.get('description', '')
print(f"{cust_id:<10} {cust_name:<30} {cust_desc}")
else:
print("\nNo customers found.")
except Exception as e:
print(f"\n✗ Error fetching customers: {str(e)}")
elif choice == '5':
# Create customer
customer_name = input("\nEnter customer name: ")
customer_desc = input("Enter customer description (optional): ")
try:
result = uploader.create_customer(customer_name, customer_desc)
print(f"\n✓ Success: {result.get('msg', 'Customer created')}")
if 'customer_id' in result:
print(f" Customer ID: {result['customer_id']}")
except Exception as e:
print(f"\n✗ Error creating customer: {str(e)}")
elif choice == '6':
# Download left hashes
try:
# First, list customers to help user select
result = uploader.list_customers()
if 'customers' in result and result['customers']:
print("\n" + "="*60)
print("Available Customers:")
print("="*60)
print(f"{'ID':<10} {'Name':<30}")
print("-" * 60)
for customer in result['customers']:
cust_id = customer.get('id', 'N/A')
cust_name = customer.get('name', 'N/A')
print(f"{cust_id:<10} {cust_name:<30}")
# Get customer ID and hashfile ID directly
customer_id = int(input("\nEnter customer ID: "))
# Note: API doesn't provide hashfile listing
print("\nNote: To find the hashfile ID, visit the Hashview web interface:")
print(f" {hashview_url}/hashfiles")
print(" Look for hashfiles belonging to the selected customer.")
hashfile_id = int(input("\nEnter hashfile ID: "))
# Set output filename automatically
output_file = f"left_{customer_id}_{hashfile_id}.txt"
# Download the left hashes
download_result = uploader.download_left_hashes(
customer_id, hashfile_id, output_file
)
print(f"\n✓ Success: Downloaded {download_result['size']} bytes")
print(f" File: {download_result['output_file']}")
except ValueError:
print("\n✗ Error: Invalid ID entered. Please enter a numeric ID.")
except Exception as e:
print(f"\n✗ Error downloading hashes: {str(e)}")
elif choice == '9':
break
else:
print("Invalid option. Please try again.")
except KeyboardInterrupt:
print("\n\nHashview upload canceled.")
except Exception as e:
print(f"\nError connecting to Hashview: {str(e)}")
# Quick Dictionary Attack with Optional Chained Rules
def quick_crack():
# Rules Attack
wordlist_choice = None
rule_choice = None
selected_hcatRules = []
wordlist_files = sorted(os.listdir(hcatWordlists))
print("\nWordlists:")
for i, file in enumerate(wordlist_files, start=1):
print(f"{i}. {file}")
while wordlist_choice is None:
try:
raw_choice = input("\nEnter path of wordlist or wordlist directory.\n"
"Press Enter for default optimized wordlists [{0}]: ".format(hcatOptimizedWordlists))
if raw_choice == '':
wordlist_choice = hcatOptimizedWordlists
elif os.path.exists(raw_choice):
wordlist_choice = raw_choice
elif 1 <= int(raw_choice) <= len(wordlist_files):
if os.path.exists(hcatWordlists + '/' + wordlist_files[int(raw_choice) - 1]):
wordlist_choice = hcatWordlists + '/' + wordlist_files[int(raw_choice) - 1]
print(wordlist_choice)
else:
wordlist_choice = None
print('Please enter a valid wordlist or wordlist directory.')
except ValueError:
print("Please enter a valid number.")
rule_files = sorted(os.listdir(hcatPath + '/rules'))
print("\nWhich rule(s) would you like to run?")
print('0. To run without any rules')
for i, file in enumerate(rule_files, start=1):
print(f"{i}. {file}")
print('99. YOLO...run all of the rules')
while rule_choice is None:
raw_choice = input('Enter Comma separated list of rules you would like to run. To run rules chained use the + symbol.\n'
'For example 1+1 will run {0} chained twice and 1,2 would run {0} and then {1} sequentially.\n'
'Choose wisely: '.format(rule_files[0], rule_files[1]))
if raw_choice != '':
rule_choice = raw_choice.split(',')
if '99' in rule_choice:
for rule in rule_files:
selected_hcatRules.append('-r {hcatPath}/rules/{selected_rule}'.format(selected_rule=rule, hcatPath=hcatPath))
elif '0' in rule_choice:
selected_hcatRules = ['']
else:
for choice in rule_choice:
if '+' in choice:
combined_choice = ''
choices = choice.split('+')
for rule in choices:
try:
combined_choice = '{0} {1}'.format(combined_choice, '-r {hcatPath}/rules/{selected_rule}'.format(selected_rule=rule_files[int(rule) - 1],
hcatPath=hcatPath))
except:
continue
selected_hcatRules.append(combined_choice)
else:
try:
selected_hcatRules.append('-r {hcatPath}/rules/{selected_rule}'.format(selected_rule=rule_files[int(choice) - 1],hcatPath=hcatPath))
except IndexError:
continue
#Run Quick Crack with each selected rule
for chain in selected_hcatRules:
hcatQuickDictionary(hcatHashType, hcatHashFile, chain, wordlist_choice)
# Extensive Pure_Hate Methodology
def extensive_crack():
# Brute Force Attack
hcatBruteForce(hcatHashType, hcatHashFile, "1", "7")
# Recycle Cracked Passwords
hcatRecycle(hcatHashType, hcatHashFile, hcatBruteCount)
# Dictionary Attack
hcatDictionary(hcatHashType, hcatHashFile)
# Recycle Cracked Passwords
hcatRecycle(hcatHashType, hcatHashFile, hcatDictionaryCount)
# Top Mask Attack
hcatTargetTime = 4 * 60 * 60 # 4 Hours
hcatTopMask(hcatHashType, hcatHashFile, hcatTargetTime)
# Recycle Cracked Passwords
hcatRecycle(hcatHashType, hcatHashFile, hcatMaskCount)
# Fingerprint Attack
hcatFingerprint(hcatHashType, hcatHashFile)
# Recycle Cracked Passwords
hcatRecycle(hcatHashType, hcatHashFile, hcatFingerprintCount)
# Combination Attack
hcatCombination(hcatHashType, hcatHashFile)
# Recycle Cracked Passwords
hcatRecycle(hcatHashType, hcatHashFile, hcatCombinationCount)
# Hybrid Attack
hcatHybrid(hcatHashType, hcatHashFile)
# Recycle Cracked Passwords
hcatRecycle(hcatHashType, hcatHashFile, hcatHybridCount)
# Extra - Just For Good Measure
hcatGoodMeasure(hcatHashType, hcatHashFile)
# Recycle Cracked Passwords
hcatRecycle(hcatHashType, hcatHashFile, hcatExtraCount)
# Brute Force
def brute_force_crack():
hcatMinLen = int(input("\nEnter the minimum password length to brute force (1): ") or 1)
hcatMaxLen = int(input("\nEnter the maximum password length to brute force (7): ") or 7)
hcatBruteForce(hcatHashType, hcatHashFile, hcatMinLen, hcatMaxLen)
# Top Mask
def top_mask_crack():
hcatTargetTime = int(input("\nEnter a target time for completion in hours (4): ") or 4)
hcatTargetTime = hcatTargetTime * 60 * 60
hcatTopMask(hcatHashType, hcatHashFile, hcatTargetTime)
# Fingerprint
def fingerprint_crack():
hcatFingerprint(hcatHashType, hcatHashFile)
# Combinator
def combinator_crack():
hcatCombination(hcatHashType, hcatHashFile)
# Hybrid
def hybrid_crack():
hcatHybrid(hcatHashType, hcatHashFile)
# Pathwell Top 100 Bruteforce Mask
def pathwell_crack():
# Bruteforce Mask Attack
hcatPathwellBruteForce(hcatHashType, hcatHashFile)
# PRINCE Attack
def prince_attack():
hcatPrince(hcatHashType, hcatHashFile)
# YOLO Combination
def yolo_combination():
hcatYoloCombination(hcatHashType, hcatHashFile)
# Thorough Combinator
def thorough_combinator():
hcatThoroughCombinator(hcatHashType, hcatHashFile)
# Middle Combinator
def middle_combinator():
hcatMiddleCombinator(hcatHashType, hcatHashFile)
# Bandrel Methodology
def bandrel_method():
hcatBandrel(hcatHashType, hcatHashFile)
# convert hex words for recycling
def convert_hex(working_file):
processed_words = []
regex = r'^\$HEX\[(\S+)\]'
with open(working_file, 'r') as f:
for line in f:
match = re.search(regex, line.rstrip('\n'))
if match:
try:
processed_words.append(binascii.unhexlify(match.group(1)).decode('iso-8859-9'))
except UnicodeDecodeError:
pass
else:
processed_words.append(line.rstrip('\n'))
return processed_words
# Display Cracked Hashes
def show_results():
if os.path.isfile(hcatHashFile + ".out"):
with open(hcatHashFile + ".out") as hcatOutput:
for cracked_hash in hcatOutput:
print(cracked_hash.strip())
else:
print("No hashes were cracked :(")
# Analyze Hashes with Pipal
def pipal():
hcatHashFilePipal = hcatHashFile
if hcatHashType == "1000":
combine_ntlm_output()
hcatHashFilePipal = hcatHashFileOrig
if os.path.isfile(pipalPath):
if os.path.isfile(hcatHashFilePipal + ".out"):
pipalFile = open(hcatHashFilePipal + ".passwords", 'w')
with open(hcatHashFilePipal + ".out") as hcatOutput:
for cracked_hash in hcatOutput:
password = cracked_hash.split(':')
clearTextPass = password[-1]
match = re.search(r'^\$HEX\[(\S+)\]', clearTextPass)
if match:
clearTextPass = binascii.unhexlify(match.group(1)).decode('iso-8859-9')
pipalFile.write(clearTextPass)
pipalFile.close()
pipalProcess = subprocess.Popen(
"{pipal_path} {pipal_file} -t {pipal_count} --output {pipal_out}".format(
pipal_path=pipalPath,
pipal_file=hcatHashFilePipal + ".passwords",
pipal_out=hcatHashFilePipal + ".pipal",
pipal_count=pipal_count),
shell=True)
try:
pipalProcess.wait()
except KeyboardInterrupt:
print('Killing PID {0}...'.format(str(pipalProcess.pid)))
pipalProcess.kill()
print("Pipal file is at " + hcatHashFilePipal + ".pipal\n")
with open(hcatHashFilePipal + ".pipal") as pipalfile:
pipal_content = pipalfile.readlines()
raw_pipal = '\n'.join(pipal_content)
raw_pipal = re.sub('\n+', '\n', raw_pipal)
raw_regex = r'Top [0-9]+ base words\n'
for word in range(pipal_count):
raw_regex += r'(\S+).*\n'
basewords_re = re.compile(raw_regex)
results = re.search(basewords_re,raw_pipal)
top_basewords = []
if results:
for i in range(1, results.lastindex + 1):
top_basewords.append(results.group(i))
return top_basewords
else:
return []
else:
print("No hashes were cracked :(")
return []
else:
print("The path to pipal.rb is either not set, or is incorrect.")
return
# Exports output to excel file
def export_excel():
# Check for openyxl dependancy for export
try:
import openpyxl
except:
sys.stderr.write('You must install openpyxl first using \'pip install openpyxl\' or \'pip3 install openpyxl\'\n')
return
if hcatHashType == "1000":
combine_ntlm_output()
output = openpyxl.Workbook()
current_ws = output.create_sheet(title='hate_crack output', index=0)
current_row = 2
current_ws['A1'] = 'Username'
current_ws['B1'] = 'SID'
current_ws['C1'] = 'LM Hash'
current_ws['D1'] = 'NTLM Hash'
current_ws['E1'] = 'Clear-Text Password'
with open(hcatHashFileOrig+'.out') as input_file:
for line in input_file:
matches = re.match(r'(^[^:]+):([0-9]+):([a-z0-9A-Z]{32}):([a-z0-9A-Z]{32}):::(.*)',line.rstrip('\r\n'))
if not matches:
continue
username = matches.group(1)
sid = matches.group(2)
lm = matches.group(3)
ntlm = matches.group(4)
try:
clear_text = matches.group(5)
match = re.search(r'^\$HEX\[(\S+)\]', clear_text)
if match:
clear_text = binascii.unhexlify(match.group(1)).decode('iso-8859-9')
except:
clear_text = ''
current_ws['A' + str(current_row)] = username
current_ws['B' + str(current_row)] = sid
current_ws['C' + str(current_row)] = lm
current_ws['D' + str(current_row)] = ntlm
current_ws['E' + str(current_row)] = clear_text
current_row += 1
output.save(hcatHashFile+'.xlsx')
print("Output exported succesfully to {0}".format(hcatHashFile+'.xlsx'))
else:
sys.stderr.write('Excel output only supported for pwdformat for NTLM hashes')
return
# Show README
def show_readme():
with open(hate_path + "/readme.md") as hcatReadme:
print(hcatReadme.read())
# Exit Program
def quit_hc():
cleanup()
sys.exit(0)
# The Main Guts
def main():
global pwdump_format
global hcatHashFile
global hcatHashType
global hcatHashFileOrig
global lmHashesFound
try:
hcatHashFile = sys.argv[1]
hcatHashType = sys.argv[2]
except IndexError:
# No arguments provided - show menu
ascii_art()
print("\n" + "="*60)
print("No hash file provided. What would you like to do?")
print("="*60)
print("\t(1) Download hashes from Hashview")
print("\t(2) Show usage information")
print("\t(3) Exit")
choice = input("\nSelect an option: ")
if choice == '1':
# Download from Hashview
if not REQUESTS_AVAILABLE:
print("\nError: 'requests' module not found.")
print("Install it with: pip install requests")
sys.exit(1)
if not hashview_api_key:
print("\nError: Hashview API key not configured.")
print("Please set 'hashview_api_key' in config.json")
sys.exit(1)
try:
uploader = HashviewAPI(hashview_url, hashview_api_key)
# List customers
result = uploader.list_customers()
if 'customers' in result and result['customers']:
print("\n" + "="*60)
print("Available Customers:")
print("="*60)
print(f"{'ID':<10} {'Name':<30}")
print("-" * 60)
for customer in result['customers']:
cust_id = customer.get('id', 'N/A')
cust_name = customer.get('name', 'N/A')
print(f"{cust_id:<10} {cust_name:<30}")
# Get customer ID
customer_id = int(input("\nEnter customer ID: "))
# Note: API doesn't provide hashfile listing
print("\nNote: To find the hashfile ID, visit the Hashview web interface:")
print(f" {hashview_url}/hashfiles")
print(" Look for hashfiles belonging to the selected customer.")
# Prompt directly for hashfile ID
hashfile_id = int(input("\nEnter hashfile ID: "))
# Get hash type
print("\nEnter hash type (e.g., 1000 for NTLM, 0 for MD5)")
print("See hashcat --help for hash type reference")
hcatHashType = input("Hash type: ")
# Set output filename automatically
output_file = f"left_{customer_id}_{hashfile_id}.txt"
# Download the left hashes
download_result = uploader.download_left_hashes(
customer_id, hashfile_id, output_file
)
print(f"\n✓ Success: Downloaded {download_result['size']} bytes")
print(f" File: {download_result['output_file']}")
# Set the hash file for processing
hcatHashFile = download_result['output_file']
print(f"\nNow starting hate_crack with:")
print(f" Hash file: {hcatHashFile}")
print(f" Hash type: {hcatHashType}")
except ValueError:
print("\n✗ Error: Invalid ID entered. Please enter a numeric ID.")
sys.exit(1)
except Exception as e:
print(f"\n✗ Error downloading hashes: {str(e)}")
sys.exit(1)
elif choice == '2':
usage()
sys.exit(0)
else:
sys.exit(0)
hcatHashFileOrig = hcatHashFile
ascii_art()
# Get Initial Input Hash Count
hcatHashCount = lineCount(hcatHashFile)
# If LM or NT Mode Selected and pwdump Format Detected, Prompt For LM to NT Attack
if hcatHashType == "1000":
lmHashesFound = False
pwdump_format = False
hcatHashFileLine = open(hcatHashFile, "r").readline()
if re.search(r"[a-f0-9A-F]{32}:[a-f0-9A-F]{32}:::", hcatHashFileLine):
pwdump_format = True
print("PWDUMP format detected...")
print("Parsing NT hashes...")
subprocess.Popen(
"cat {hash_file} | cut -d : -f 4 |sort -u > {hash_file}.nt".format(hash_file=hcatHashFile),
shell=True).wait()
print("Parsing LM hashes...")
subprocess.Popen("cat {hash_file} | cut -d : -f 3 |sort -u > {hash_file}.lm".format(hash_file=hcatHashFile),
shell=True).wait()
if ((lineCount(hcatHashFile + ".lm") == 1) and (
hcatHashFileLine.split(":")[2].lower() != "aad3b435b51404eeaad3b435b51404ee")) or (
lineCount(hcatHashFile + ".lm") > 1):
lmHashesFound = True
lmChoice = input("LM hashes identified. Would you like to brute force the LM hashes first? (Y) ") or "Y"
if lmChoice.upper() == 'Y':
hcatLMtoNT()
hcatHashFileOrig = hcatHashFile
hcatHashFile = hcatHashFile + ".nt"
elif re.search(r"^[a-f0-9A-F]{32}$", hcatHashFileLine):
pwdump_format = False
print("PWDUMP format was not detected...")
print("Hash only detected")
elif re.search(r"^.+:[a-f0-9A-F]{32}$", hcatHashFileLine):
pwdump_format = False
print("PWDUMP format was not detected...")
print("username with Hash detected")
subprocess.Popen(
"cat {hash_file} | cut -d : -f 2 |sort -u > {hash_file}.nt".format(hash_file=hcatHashFile),
shell=True).wait()
hcatHashFileOrig = hcatHashFile
hcatHashFile = hcatHashFile + ".nt"
else:
print("unknown format....does it have usernames?")
exit(1)
# Check POT File for Already Cracked Hashes
if not os.path.isfile(hcatHashFile + ".out"):
hcatOutput = open(hcatHashFile + ".out", "w+")
hcatOutput.close()
print("Checking POT file for already cracked hashes...")
subprocess.Popen(
"{hcatBin} --show --potfile-path={hate_path}/hashcat.pot -m {hash_type} {hash_file} > {hash_file}.out".format(
hcatBin=hcatBin,
hash_type=hcatHashType,
hash_file=hcatHashFile,
hate_path=hate_path), shell=True).wait()
hcatHashCracked = lineCount(hcatHashFile + ".out")
if hcatHashCracked > 0:
print("Found %d hashes already cracked.\nCopied hashes to %s.out" % (hcatHashCracked, hcatHashFile))
else:
print("No hashes found in POT file.")
# Display Options
try:
while 1:
print("\n\t(1) Quick Crack")
print("\t(2) Extensive Pure_Hate Methodology Crack")
print("\t(3) Brute Force Attack")
print("\t(4) Top Mask Attack")
print("\t(5) Fingerprint Attack")
print("\t(6) Combinator Attack")
print("\t(7) Hybrid Attack")
print("\t(8) Pathwell Top 100 Mask Brute Force Crack")
print("\t(9) PRINCE Attack")
print("\t(10) YOLO Combinator Attack")
print("\t(11) Middle Combinator Attack")
print("\t(12) Thorough Combinator Attack")
print("\t(13) Bandrel Methodology")
print("\n\t(94) Upload to Hashview")
print("\t(95) Analyze hashes with Pipal")
print("\t(96) Export Output to Excel Format")
print("\t(97) Display Cracked Hashes")
print("\t(98) Display README")
print("\t(99) Quit")
options = {"1": quick_crack,
"2": extensive_crack,
"3": brute_force_crack,
"4": top_mask_crack,
"5": fingerprint_crack,
"6": combinator_crack,
"7": hybrid_crack,
"8": pathwell_crack,
"9": prince_attack,
"10": yolo_combination,
"11": middle_combinator,
"12": thorough_combinator,
"13": bandrel_method,
"94": hashview_upload,
"95": pipal,
"96": export_excel,
"97": show_results,
"98": show_readme,
"99": quit_hc
}
try:
task = input("\nSelect a task: ")
options[task]()
except KeyError:
pass
except KeyboardInterrupt:
quit_hc()
# Boilerplate
if __name__ == '__main__':
main()