Password Auditing: Assessing Organizational Password Strength
Learn how to perform password auditing in organizations, including hash extraction, cracking methodology, analysis, and remediation strategies.
The Audit That Found 73% of Passwords in 24 Hours
During a routine security assessment of a mid-size financial firm, a penetration tester extracted NTLM hashes from Active Directory and started cracking. Within 24 hours, 73% of the organization's passwords were recovered. Domain administrators used passwords like "Admin2024!" and "Spring2024." The CEO's password was cracked in under five minutes. This password audit — conducted with authorization — revealed that most enterprise passwords are far weaker than their complexity requirements suggest.
Password auditing is the process of assessing an organization's password strength by analyzing actual password hashes. Unlike malicious cracking, auditing is done with authorization to identify weak passwords and improve security.
Prerequisites
Before performing password auditing, you should understand:
Authorization and Legal Framework
Critical Requirements
# Before starting a password audit:
# 1. Obtain written authorization from system owner
# 2. Define scope (which systems, accounts, timeframes)
# 3. Establish data handling procedures
# 4. Document methodology and reporting format
# 5. Ensure compliance with regulations (GDPR, HIPAA, etc.)
Hash Extraction
Windows Active Directory
# Extract from Domain Controller (requires DA)
secretsdump.py -hashes LMHASH:NTHASH DOMAIN/admin@dc.corp.com
# Extract from local SAM (requires admin)
reg save hklmsam sam.save
reg save hklmsystem system.save
secretsdump.py -sam sam.save -system system.save LOCAL
# Using Mimikatz
mimikatz # lsadump::sam
mimikatz # lsadump::dcsync /domain:corp.com /user:krbtgt
Linux Systems
# Extract from /etc/shadow (requires root)
unshadow /etc/passwd /etc/shadow > linux_hashes.txt
# Individual hash extraction
cat /etc/shadow | grep -v "*quot; | grep -v "!quot; > shadow_hashes.txt
# MySQL database hashes
mysql -u root -p -e "SELECT user, authentication_string FROM mysql.user;"
# PostgreSQL
psql -c "SELECT usename, passwd FROM pg_shadow;"
Web Application Databases
# Extract from common frameworks
# WordPress: wp_users table (user_pass column)
mysql -u root -p wordpress_db -e "SELECT user_login, user_pass FROM wp_users;"
# Django: auth_user table (password column)
# Drupal: users table (pass column)
# Joomla: jos_users table (password column)
Cracking Methodology
Progressive Cracking Strategy
#!/bin/bash
# password-audit.sh — Progressive password audit
HASHES=$1
OUTPUT_DIR="audit_$(date +%Y%m%d)"
mkdir -p "$OUTPUT_DIR"
echo "[*] Starting password audit"
echo ""
# Phase 1: Quick wins (common passwords, no rules)
echo "=== Phase 1: Quick Wins ==="
hashcat -m 1000 "$HASHES" /usr/share/wordlists/rockyou.txt --potfile-path="$OUTPUT_DIR/potfile" -o "$OUTPUT_DIR/phase1_cracked.txt"
# Phase 2: Rules-based cracking
echo "=== Phase 2: Rules-Based ==="
hashcat -m 1000 "$HASHES" /usr/share/wordlists/rockyou.txt -r /usr/share/hashcat/rules/best64.rule --potfile-path="$OUTPUT_DIR/potfile" -o "$OUTPUT_DIR/phase2_cracked.txt"
# Phase 3: Targeted wordlists
echo "=== Phase 3: Targeted ==="
hashcat -m 1000 "$HASHES" company_wordlist.txt -r /usr/share/hashcat/rules/d3ad0ne.rule --potfile-path="$OUTPUT_DIR/potfile" -o "$OUTPUT_DIR/phase3_cracked.txt"
# Phase 4: Mask attack (short passwords)
echo "=== Phase 4: Mask Attack ==="
hashcat -m 1000 "$HASHES" -a 3 ?a?a?a?a?a?a?a?a --increment --potfile-path="$OUTPUT_DIR/potfile" -o "$OUTPUT_DIR/phase4_cracked.txt"
echo "[*] Audit complete!"
echo "Total cracked: $(wc -l < "$OUTPUT_DIR"/phase*_cracked.txt 2>/dev/null || echo 0)"
Cracking Prioritization
# Crack in order of risk impact:
# 1. Domain Admin accounts (highest risk)
# 2. Service accounts with privileged access
# 3. Regular user accounts
# 4. Disabled accounts (lowest priority)
# Extract specific account types
grep -i "admin" hashes.txt > admin_hashes.txt
grep -i "svc_" hashes.txt > service_hashes.txt
grep -i "sql|backup|monitor" hashes.txt > critical_service_hashes.txt
Analysis and Reporting
Password Strength Assessment
#!/usr/bin/env python3
# analyze-password-audit.py
import json
from collections import Counter
class PasswordAuditAnalyzer:
def __init__(self, cracked_file, hash_file):
self.cracked = self.load_cracked(cracked_file)
self.total_hashes = sum(1 for _ in open(hash_file))
self.cracked_count = len(self.cracked)
def load_cracked(self, filename):
results = {}
with open(filename) as f:
for line in f:
if ':' in line:
hash_val, password = line.strip().split(':', 1)
results[hash_val] = password
return results
def analyze(self):
analysis = {
'total_users': self.total_hashes,
'cracked_count': self.cracked_count,
'crack_rate': round(self.cracked_count / self.total_hashes * 100, 1),
'weak_passwords': self.find_weak_passwords(),
'common_patterns': self.find_common_patterns(),
'password_lengths': self.get_length_distribution(),
'domain_admin_weak': self.find_admin_weak(),
}
return analysis
def find_weak_passwords(self):
weak = []
for hash_val, password in self.cracked.items():
reasons = []
if password.lower() in ['password', '123456', 'admin']:
reasons.append('Common password')
if len(password) < 8:
reasons.append('Too short')
if password.lower() in self.get_common_list():
reasons.append('In breach database')
if reasons:
weak.append({'hash': hash_val, 'password': password, 'reasons': reasons})
return weak
def get_length_distribution(self):
lengths = Counter(len(p) for p in self.cracked.values())
return dict(sorted(lengths.items()))
def find_common_patterns(self):
patterns = Counter()
for password in self.cracked.values():
if password[0:1].isupper():
patterns['Capitalized'] += 1
if any(c.isdigit() for c in password):
patterns['Contains number'] += 1
if any(c in '!@#$%^&*' for c in password):
patterns['Contains special'] += 1
if password[-4:].isdigit() and int(password[-4:]) in range(1990, 2027):
patterns['Ends with year'] += 1
return dict(patterns.most_common())
def find_admin_weak(self):
return [h for h, p in self.cracked.items() if 'admin' in h.lower()]
# Usage
analyzer = PasswordAuditAnalyzer('cracked.txt', 'hashes.txt')
report = analyzer.analyze()
print(json.dumps(report, indent=2))
Report Template
# Password Audit Report Structure
# Executive Summary
# - Total accounts audited
# - Percentage cracked
# - Risk level
# - Critical findings
# Detailed Findings
# - Weak passwords found
# - Password length distribution
# - Common patterns
# - Department/role analysis
# Risk Categorization
# - Critical: Domain Admin, Service Accounts
# - High: Administrative users
# - Medium: Standard users
# - Low: Disabled accounts
# Recommendations
# - Immediate: Force password changes for weak accounts
# - Short-term: Policy improvements, MFA deployment
# - Long-term: Password manager adoption, passwordless auth
Remediation Strategies
Immediate Actions
# Force password reset for compromised accounts (PowerShell)
$weakUsers = Import-Csv weak_passwords.csv
foreach ($user in $weakUsers) {
Set-ADAccountPassword -Identity $user.Username -Reset -NewPassword (ConvertTo-SecureString "TemporaryReset2026!" -AsPlainText -Force)
Set-ADUser -Identity $user.Username -ChangePasswordAtLogon $true
}
Policy Improvements
# Modern password policy (Windows GPO)
# - Minimum length: 14 characters
# - Complexity: Optional (length is more important)
# - No rotation requirement (NIST SP 800-63)
# - Breach checks enabled
# - Block common passwords
# PowerShell to set policy
Import-Module GroupPolicy
Set-GPPasswordPolicy -Domain corp.com `
-MinimumPasswordLength 14 `
-PasswordHistoryCount 24 `
-MinimumPasswordAge 1 `
-MaximumPasswordAge 365
Real-World Examples
Penetration Test Case Study: During a financial services audit, the assessor cracked 73% of NTLM hashes within 24 hours. 40% were cracked in the first 5 minutes using RockYou + best64 rules. Domain admin accounts were among the weakest, with passwords matching seasonal patterns.
Common Mistakes
Not enough time allocated: Proper audits need 1-4 weeks depending on hash count and hash type.
Ignoring privileged accounts: Focus on admin and service accounts first.
No deduplication: Multiple users sharing the same password is a critical finding.
Poor reporting: Raw crack lists without analysis are less valuable than categorized reports.
Best Practices
Related Tools
Related Articles
Summary
Password auditing assesses organizational password strength by extracting and cracking password hashes with authorization. A progressive methodology starting with quick wins and escalating to advanced attacks provides the most efficient results. Clear reporting and actionable recommendations enable organizations to remediate weak passwords.