密码学
哈希破解
掌握哈希值破解技术与常用工具,了解哈希安全加固方法
学习时间: 60分钟
挑战数量: 4个
难度级别: 中级
哈希破解概述
哈希破解是指通过各种技术手段,从哈希值反向推导出原始输入的过程。由于哈希函数的单向性,理论上无法直接逆向计算,但在实际应用中,存在多种方法可能导致哈希被破解。
为什么哈希可以被破解?
虽然哈希函数本身具有单向性,但哈希破解成功的原因主要有:
- 哈希算法弱点:如MD5、SHA-1等存在碰撞攻击漏洞
- 弱密码使用:用户使用简单、常见的密码
- 不安全的存储方式:未使用盐值或使用了弱加盐方法
- 计算能力提升:GPU、专用ASIC等硬件加速计算能力
- 实现漏洞:哈希算法实现或集成方式存在问题
哈希破解过程的基本原理与流程
常见哈希破解技术
1. 字典攻击
字典攻击利用预先准备的常用密码列表,计算每个密码的哈希值并与目标哈希进行比对。
- 原理:对字典中的每个单词计算哈希值,与目标哈希比较
- 优势:破解常用密码效率高,实现简单
- 局限性:无法破解不在字典中的密码
Python - 简单字典攻击示例
import hashlib
def dictionary_attack(target_hash, dictionary_file, hash_type='md5'):
"""
使用字典攻击破解哈希值
:param target_hash: 目标哈希值(十六进制字符串)
:param dictionary_file: 密码字典文件路径
:param hash_type: 哈希算法类型,默认为MD5
:return: 若破解成功返回原始密码,否则返回None
"""
# 确保目标哈希为小写
target_hash = target_hash.lower()
# 打开字典文件
with open(dictionary_file, 'r', encoding='utf-8', errors='ignore') as f:
for line in f:
# 去除每行末尾的换行符
password = line.strip()
# 计算当前密码的哈希值
if hash_type == 'md5':
password_hash = hashlib.md5(password.encode()).hexdigest()
elif hash_type == 'sha1':
password_hash = hashlib.sha1(password.encode()).hexdigest()
elif hash_type == 'sha256':
password_hash = hashlib.sha256(password.encode()).hexdigest()
else:
raise ValueError(f"不支持的哈希类型: {hash_type}")
# 比较哈希值
if password_hash == target_hash:
return password
# 未在字典中找到匹配项
return None
# 使用示例
if __name__ == "__main__":
# MD5("password123") = 482c811da5d5b4bc6d497ffa98491e38
target = "482c811da5d5b4bc6d497ffa98491e38"
result = dictionary_attack(target, "passwords.txt", "md5")
if result:
print(f"破解成功! 原始密码是: {result}")
else:
print("破解失败,密码不在字典中")
2. 彩虹表攻击
彩虹表是一种时间-空间平衡的技术,预先计算并存储大量哈希值和对应原始值的链,以加速查找过程。
- 原理:使用预计算的哈希链表,通过查表快速破解哈希
- 优势:比暴力破解快,比完整查找表节省空间
- 局限性:
- 无法处理加盐哈希
- 需要大量存储空间
- 只能破解表中包含的密码范围
3. 暴力破解
暴力破解通过尝试所有可能的输入组合,直到找到匹配的哈希值。
- 原理:系统地尝试所有可能的字符组合
- 优势:理论上能破解任何密码
- 局限性:计算量庞大,破解时间可能非常长
Python - 简单暴力破解示例
import hashlib
import itertools
import string
import time
def brute_force_attack(target_hash, max_length=4, char_set=None, hash_type='md5'):
"""
使用暴力破解方法破解哈希值
:param target_hash: 目标哈希值(十六进制字符串)
:param max_length: 尝试的最大密码长度
:param char_set: 字符集,默认为小写字母+数字
:param hash_type: 哈希算法类型,默认为MD5
:return: 若破解成功返回原始密码,否则返回None
"""
# 确保目标哈希为小写
target_hash = target_hash.lower()
# 默认字符集为小写字母和数字
if char_set is None:
char_set = string.ascii_lowercase + string.digits
# 从长度1开始尝试所有可能的组合
start_time = time.time()
for length in range(1, max_length + 1):
print(f"尝试长度为 {length} 的密码...")
# 生成当前长度的所有可能组合
combinations = itertools.product(char_set, repeat=length)
for combo in combinations:
password = ''.join(combo)
# 计算当前密码的哈希值
if hash_type == 'md5':
password_hash = hashlib.md5(password.encode()).hexdigest()
elif hash_type == 'sha1':
password_hash = hashlib.sha1(password.encode()).hexdigest()
elif hash_type == 'sha256':
password_hash = hashlib.sha256(password.encode()).hexdigest()
else:
raise ValueError(f"不支持的哈希类型: {hash_type}")
# 比较哈希值
if password_hash == target_hash:
end_time = time.time()
print(f"破解耗时: {end_time - start_time:.2f} 秒")
return password
# 未找到匹配项
end_time = time.time()
print(f"破解耗时: {end_time - start_time:.2f} 秒")
return None
# 使用示例
if __name__ == "__main__":
# MD5("a2c") = "9d4d30c1025f533138a1b608df6cbb2c"
target = "9d4d30c1025f533138a1b608df6cbb2c"
result = brute_force_attack(target, max_length=3)
if result:
print(f"破解成功! 原始密码是: {result}")
else:
print("破解失败,可能密码长度超过限制或使用了不同的字符集")
4. 查询在线哈希数据库
利用现有的在线哈希数据库快速查找已知哈希值对应的原始输入。
- 常用服务:
- CrackStation
- MD5Online
- HashToolkit
- Hashes.com
- 优势:速度极快,无需本地计算资源
- 局限性:仅限于数据库中存在的哈希值
专业哈希破解工具
1. Hashcat
Hashcat是当前世界上最快的密码破解工具,支持多种哈希类型和破解模式。
- 特点:
- 支持GPU加速
- 支持100多种哈希算法
- 提供多种攻击模式(字典、掩码、组合、规则等)
- 跨平台支持
- 常用命令:
Hashcat - 常用命令示例
# 字典攻击 MD5 哈希
hashcat -m 0 -a 0 hash.txt wordlist.txt
# 掩码攻击(暴力破解指定模式)
hashcat -m 0 -a 3 hash.txt ?l?l?l?l?l?l
# 规则攻击(使用规则转换字典)
hashcat -m 0 -a 0 hash.txt wordlist.txt -r rules/best64.rule
# 组合攻击(组合两个字典)
hashcat -m 0 -a 1 hash.txt wordlist1.txt wordlist2.txt
# 显示已破解的哈希
hashcat -m 0 hash.txt --show
# 哈希类型速查
# -m 0 : MD5
# -m 100 : SHA1
# -m 1400: SHA2-256
# -m 1700: SHA2-512
# -m 3200: BCRYPT
# -m 1000: NTLM
2. John the Ripper
John the Ripper是一款开源的密码破解工具,设计用于检测弱密码。
- 特点:
- 支持多种密码哈希和加密格式
- 自动检测哈希类型
- 提供丰富的字符集和规则设置
- 支持增量模式(自动调整尝试范围)
- 常用命令:
John the Ripper - 常用命令示例
# 基本用法
john hash.txt
# 指定字典
john --wordlist=wordlist.txt hash.txt
# 增量模式(暴力破解)
john --incremental hash.txt
# 使用特定哈希格式
john --format=md5 hash.txt
# 显示已破解的密码
john --show hash.txt
# 应用规则
john --rules --wordlist=wordlist.txt hash.txt
3. Hydra
虽然Hydra主要是在线服务密码破解工具,但对于某些场景也可用于哈希破解。
- 适用场景:
- HTTP(S)身份验证
- FTP, SSH等服务的密码破解
- 表单提交破解
哈希破解防御措施
1. 使用强哈希算法
选择设计用于密码存储的现代哈希算法:
- 推荐算法:
- Argon2(推荐首选)
- bcrypt
- PBKDF2
- scrypt
- 避免使用:MD5、SHA-1、SHA-256/512(未经专门设计)
2. 盐值与密钥拉伸
Python - Bcrypt加盐哈希示例
import bcrypt
def hash_password(password):
"""使用bcrypt生成加盐密码哈希"""
# 生成随机盐值并哈希密码(自动处理盐的存储)
password_bytes = password.encode('utf-8')
salt = bcrypt.gensalt(rounds=12) # 计算强度因子
hashed = bcrypt.hashpw(password_bytes, salt)
return hashed.decode('utf-8') # 返回字符串形式
def verify_password(stored_hash, provided_password):
"""验证密码是否匹配存储的哈希"""
password_bytes = provided_password.encode('utf-8')
stored_hash_bytes = stored_hash.encode('utf-8')
return bcrypt.checkpw(password_bytes, stored_hash_bytes)
# 示例用法
if __name__ == "__main__":
# 哈希密码
password = "SecurePassword123"
hashed_password = hash_password(password)
print(f"哈希结果: {hashed_password}")
# 验证密码
is_correct = verify_password(hashed_password, password)
print(f"密码验证结果: {is_correct}")
# 验证错误密码
is_correct = verify_password(hashed_password, "WrongPassword")
print(f"错误密码验证结果: {is_correct}")
3. 加强密码策略
- 强制使用强密码(长度、复杂性、混合字符等)
- 定期更改密码
- 禁止使用常见密码和历史密码
- 实施密码强度检测
4. 增加破解成本
- 增加哈希函数的迭代次数/工作因子
- 使用内存密集型哈希函数(如Argon2, scrypt)
- 实施速率限制和失败尝试锁定
Python - Argon2 示例
from argon2 import PasswordHasher
from argon2.exceptions import VerifyMismatchError
def hash_with_argon2(password):
"""使用Argon2id算法哈希密码"""
ph = PasswordHasher(
time_cost=3, # 迭代次数
memory_cost=65536, # 内存成本(KB)
parallelism=4, # 并行度
hash_len=32, # 哈希长度
salt_len=16 # 盐值长度
)
return ph.hash(password)
def verify_with_argon2(stored_hash, password):
"""验证密码与Argon2哈希是否匹配"""
ph = PasswordHasher()
try:
ph.verify(stored_hash, password)
return True
except VerifyMismatchError:
return False
# 示例用法
if __name__ == "__main__":
password = "VerySecurePassword!123"
# 哈希密码
hashed = hash_with_argon2(password)
print(f"Argon2哈希: {hashed}")
# 验证密码
is_valid = verify_with_argon2(hashed, password)
print(f"正确密码验证: {is_valid}")
# 验证错误密码
is_valid = verify_with_argon2(hashed, "WrongPassword")
print(f"错误密码验证: {is_valid}")
CTF中的哈希破解挑战
在CTF比赛中,哈希破解是常见的加密挑战类型,通常包括:
常见挑战类型
- 经典哈希破解:提供一个哈希值,要求找出原始输入
- 格式化哈希破解:破解后的原文需符合特定格式(如flag{xxx})
- 哈希链破解:多重哈希嵌套,需逐层破解
- 自定义哈希算法:需要先分析算法特性再进行破解
- 破解后再处理:哈希破解只是获取下一步线索
CTF哈希破解策略
- 首先识别哈希类型(长度、格式、字符分布等)
- 检查是否为常见哈希或弱密码(在线查询)
- 尝试基于题目提示的定向破解(如使用特定字典)
- 分析其他上下文线索,缩小可能范围
- 利用题目特征(如破解后格式flag{xxx})构建掩码攻击
CTF哈希破解示例
# Hashcat 针对CTF的特殊破解模式
# 假设我们知道flag格式为"flag{...}",其中...是5个小写字母
# 创建掩码攻击配置
echo "flag{?l?l?l?l?l}" > pattern.txt
# 使用掩码攻击破解SHA256哈希
hashcat -m 1400 -a 3 target_hash.txt pattern.txt
# 对多重哈希的处理示例(Python)
import hashlib
def double_md5(input_str):
"""对输入进行两次MD5哈希"""
first_hash = hashlib.md5(input_str.encode()).hexdigest()
return hashlib.md5(first_hash.encode()).hexdigest()
# 暴力破解双重MD5
target = "553d1851dfed0c7e464d70607fe455b9" # 双重MD5哈希值
charset = "abcdefghijklmnopqrstuvwxyz"
for c1 in charset:
for c2 in charset:
for c3 in charset:
test_str = f"flag{{{c1}{c2}{c3}}}"
if double_md5(test_str) == target:
print(f"找到匹配: {test_str}")
break