Offensive Security · Study Project · Monash Bootcamp

Password Cracking
with Hashcat

📅 2024 🏫 Monash University Cybersecurity Bootcamp 💻 Kali Linux · Python · Bash 🏫 Presented at Bootcamp Demo Day

Demonstrated brute-force and dictionary-based password cracking using Hashcat with Python and Bash automation as part of a structured lab exercise at the Monash University Cybersecurity Bootcamp. Practised cracking MD5, NTLM, SHA-256, and bcrypt hashes to understand how attackers exploit weak password policies — and to build stronger defensive intuitions. Presented findings at the bootcamp's final conference, illustrating real-world implications for organisational password hygiene.

Hashcat Python Bash Brute Force Dictionary Attack MD5 NTLM bcrypt Password Security
View on GitHub Back to Projects

Why Practise Password Cracking?

The goal of this lab exercise was to understand, from an attacker's perspective, how password hashes are cracked when a credential database is exposed. By practising offensive techniques in a controlled environment, I could identify exactly which hashing algorithms and password policies are dangerously weak — and articulate concrete defensive controls for organisations to adopt.

All cracking was performed on intentionally weak, self-generated test hashes in a local, isolated lab. No real user data or live systems were involved at any point.

Hash Types & Relative Cracking Times

Four hash algorithms were tested with identical password sets to directly compare their resistance to offline cracking attacks on consumer hardware (single GPU, RTX 3060).

MD5 (-m 0)
< 30 sec
8-char mixed-case + digits cracked near instantly. Billions of hashes/sec.
NTLM (-m 1000)
< 2 min
Faster than MD5 on GPU. 6-char passwords cracked in seconds. Common in AD environments.
SHA-256 (-m 1400)
5–15 min
Faster GPU throughput than bcrypt. Weak/short passwords still cracked quickly without salting.
bcrypt (-m 3200)
Days–Weeks
Intentionally slow. Cost factor 12 limits GPU to ~1,000 hashes/sec. Significant resistance demonstrated.

Three Attack Modes Practised

1 — Dictionary Attack (Attack Mode 0)

Used the rockyou.txt wordlist (14.3 million entries) against a set of MD5 and NTLM hashes. The majority of "realistic" weak passwords in the test set were recovered within the first pass.

# Dictionary attack — MD5 hashes, rockyou wordlist
hashcat -m 0 -a 0 hashes_md5.txt /usr/share/wordlists/rockyou.txt

# Dictionary attack — NTLM hashes
hashcat -m 1000 -a 0 hashes_ntlm.txt /usr/share/wordlists/rockyou.txt \
    --status --status-timer=10

Session.........: hashcat
Status..........: Running
Hash.Mode.......: 1000 (NTLM)
Guess.Base......: File (/usr/share/wordlists/rockyou.txt)
Speed.#1........: 4823.4 MH/s (14.21ms)
Progress........: 14344385/14344385 (100.00%)
Recovered.......: 18/20 (90.00%) Digests

2 — Brute Force / Mask Attack (Attack Mode 3)

Used Hashcat mask syntax to brute-force all 6-character passwords matching a lowercase+digit pattern. Demonstrated how short, predictable character-set passwords fall rapidly.

# Mask attack — all 6-char lowercase+digit combinations
hashcat -m 0 -a 3 hashes_md5.txt ?l?l?l?d?d?d

# Increment mode — try lengths 4 through 8
hashcat -m 0 -a 3 hashes_md5.txt ?a?a?a?a --increment \
    --increment-min=4 --increment-max=8

Mask......: ?l?l?l?d?d?d [6]
Recovered.: 5/5 (100.00%) Digests
Time.Est..: 0 secs (completed)

3 — Rule-Based Attack (Attack Mode 0 + Rules)

Applied Hashcat's built-in best64.rule and dive.rule to transform wordlist entries with common leet-speak substitutions, capitalisation, and number appending — patterns users commonly apply thinking their password is "unique".

# Rule-based attack — rockyou + best64 rules (NTLM)
hashcat -m 1000 -a 0 hashes_ntlm.txt rockyou.txt \
    -r /usr/share/hashcat/rules/best64.rule

# Stacked rules — dive.rule for deeper mutations
hashcat -m 1000 -a 0 hashes_ntlm.txt rockyou.txt \
    -r /usr/share/hashcat/rules/dive.rule --outfile cracked.txt

Added rule mutations: 64 (best64) / 99076 (dive)
Recovered additional: 3/20 previously uncovered hashes
Rule "p@$$w0rd" variant cracked: "password123" -> "p@$$w0rd123"

Python: Hash Generation & Results Parser

A Python script automated hash generation from a test wordlist and parsed Hashcat's potfile output to produce a summary report — practising the kind of scripting a SOC analyst might use to automate bulk credential-checking tasks.

#!/usr/bin/env python3
# hash_gen_parse.py — lab study script
# Generates MD5/NTLM test hashes from a wordlist, then parses cracked output

import hashlib, binascii, os, argparse

def make_md5(plaintext: str) -> str:
    return hashlib.md5(plaintext.encode()).hexdigest()

def make_ntlm(plaintext: str) -> str:
    return hashlib.new(
        'md4', plaintext.encode('utf-16le')
    ).hexdigest()

def generate_hashes(wordlist_path: str, algo: str) -> list[str]:
    hashes = []
    with open(wordlist_path) as f:
        for line in f:
            pw = line.strip()
            if algo == 'md5':
                hashes.append(make_md5(pw))
            elif algo == 'ntlm':
                hashes.append(make_ntlm(pw))
    return hashes

def parse_potfile(potfile: str) -> dict:
    """Return {hash: plaintext} from hashcat .potfile"""
    recovered = {}
    with open(potfile) as f:
        for line in f:
            parts = line.strip().split(':')
            if len(parts) >= 2:
                recovered[parts[0]] = ':'.join(parts[1:])
    return recovered


# --- Results summary ---
Total hashes generated : 500
Recovered (MD5)        : 478 / 500  (95.6%)
Recovered (NTLM)       : 491 / 500  (98.2%)
Recovered (SHA-256)    : 312 / 500  (62.4%)
Recovered (bcrypt-12)  :   4 / 500  ( 0.8%)

Longest plaintext found: "iloveyou2009"
Most common pattern    : [word]+[2-digit year]

Bash: Multi-Mode Attack Wrapper

A Bash wrapper script ran all three attack modes sequentially and logged timestamped results — practising automation patterns useful for lab documentation and reproducible testing.

#!/usr/bin/env bash
# run_attacks.sh — lab study wrapper
# Runs dictionary, mask, and rule-based attacks; logs with timestamps

HASHFILE="${1:-hashes_ntlm.txt}"
WORDLIST="/usr/share/wordlists/rockyou.txt"
RULES_DIR="/usr/share/hashcat/rules"
LOGFILE="results_$(date +%Y%m%d_%H%M%S).log"
MODE=1000  # NTLM

log() { echo "[$(date '+%H:%M:%S')] $*" | tee -a "$LOGFILE"; }

log "=== Phase 1: Dictionary attack ==="
hashcat -m $MODE -a 0 "$HASHFILE" "$WORDLIST" \
    --potfile-path=./hashcat.pot --quiet
log "Recovered so far: $(wc -l < ./hashcat.pot)"

log "=== Phase 2: Mask attack (6-char ?l?d combos) ==="
hashcat -m $MODE -a 3 "$HASHFILE" "?l?l?l?d?d?d" \
    --potfile-path=./hashcat.pot --quiet
log "Recovered after mask: $(wc -l < ./hashcat.pot)"

log "=== Phase 3: Rule-based (best64) ==="
hashcat -m $MODE -a 0 "$HASHFILE" "$WORDLIST" \
    -r "$RULES_DIR/best64.rule" \
    --potfile-path=./hashcat.pot --quiet
log "Final recovered: $(wc -l < ./hashcat.pot)"
log "Full log written to: $LOGFILE"


[09:12:03] === Phase 1: Dictionary attack ===
[09:14:31] Recovered so far: 18
[09:14:31] === Phase 2: Mask attack (6-char ?l?d combos) ===
[09:14:35] Recovered after mask: 21
[09:14:35] === Phase 3: Rule-based (best64) ===
[09:16:47] Final recovered: 24
[09:16:47] Full log written to: results_20240315_091203.log

What the Lab Demonstrated

FINDING-01 — MD5 & NTLM offer negligible protection MD5 hashes for common passwords were cracked in under 30 seconds. NTLM, still in use in many Active Directory environments, was fully cracked within 2 minutes. Neither algorithm uses salting or work factors, making them trivially parallelisable on GPU hardware.
FINDING-02 — 6-character passwords fall in seconds regardless of algorithm A brute-force mask attack exhausted all 6-character lowercase+digit combinations in under 10 seconds for MD5. Even SHA-256 hashes of 6-character passwords were cracked quickly. Password length has a larger impact on security than character complexity alone.
FINDING-03 — Rule-based attacks break "clever" substitutions Common transformations — p@$$word, P@ssw0rd, pass123! — are enumerated by standard Hashcat rule files. Users believe these substitutions make passwords unique; in practice they are well-known mutation patterns.
FINDING-04 — bcrypt (cost 12) demonstrated meaningful resistance Only 4 of 500 bcrypt-hashed test passwords were cracked in the available lab time. GPU throughput dropped to approximately 1,000 hashes/sec — a reduction of six orders of magnitude compared to MD5. Work-factor algorithms change the economics of cracking fundamentally.

Monash Bootcamp Conference Presentation

The findings from this study project were presented at the Monash University Cybersecurity Bootcamp's final demo-day conference. The presentation covered the attack methodology, live Hashcat demonstrations (on self-generated test hashes), and — most importantly — the defensive controls that organisations can implement to make offline cracking attacks economically infeasible.

The audience included bootcamp peers, instructors, and industry representatives. Presenting technical offensive findings to a mixed audience reinforced the importance of framing attack knowledge in terms of concrete, actionable defence.

How Organisations Should Respond

This is the most operationally relevant section. Understanding how attackers crack passwords directly informs the controls a SOC or IT security team should advocate for.

CONTROL-01 — Replace MD5 / NTLM with bcrypt or Argon2 Any application storing MD5 or unsalted SHA-256 hashes should migrate to bcrypt (cost ≥ 12) or Argon2id immediately. NTLM in Active Directory should be supplemented with Credential Guard and LAPS to limit exposure.
CONTROL-02 — Enforce minimum 12-character passphrases Length is the most cost-effective complexity control. A 12-character passphrase increases brute-force time by orders of magnitude even against fast algorithms. Use passphrase policies over complexity rules that encourage predictable substitutions.
CONTROL-03 — Implement account lockout and rate limiting Offline cracking is only possible after a hash database is exfiltrated. However, online attacks (credential stuffing, password spraying) require rate limiting, CAPTCHA, and account lockout policies at the authentication layer. Configure lockout after 5–10 failed attempts.
CONTROL-04 — Monitor failed authentications in SIEM Alert on spikes in failed login events (Windows Event ID 4625, Linux /var/log/auth.log). Password-spray attacks use low-frequency, high-breadth patterns to evade per-account lockout. Correlation rules should flag >50 failures across >10 unique accounts within a 10-minute window.
CONTROL-05 — Check credentials against breach databases Integrate Have I Been Pwned's Pwned Passwords API (k-anonymity model) into your identity platform's registration and password-change flows. Block passwords that appear in known breach dumps regardless of their complexity.