MD5 换行符哈希破解
命令:
echo password | md5sum
计算的不是 md5("password"),而是:
md5("password\n")
因为 echo 默认会在末尾追加换行符 0x0a。如果数据库或脚本里保存的是这种哈希,普通 hashcat -m 0 或 john --format=raw-md5 直接跑字典可能找不到结果。
示例哈希
07e2a8ac8bd28bc3a0ffc4fab3145b5b
验证:
echo zombie666 | md5sum
echo -n zombie666 | md5sum
结果:
07e2a8ac8bd28bc3a0ffc4fab3145b5b -
a5218badee7a2892e087bead2f71bfa9 -
也就是说:
07e2a8ac8bd28bc3a0ffc4fab3145b5b = md5("zombie666\n")
a5218badee7a2892e087bead2f71bfa9 = md5("zombie666")
准备 hash 文件
echo '07e2a8ac8bd28bc3a0ffc4fab3145b5b' > /tmp/hash.txt
方案 A:Python 实现(Rsscross 实战路线)
Rsscross 里用 Python 直接确认这个知识点。关键不是换更大的字典,而是对每个候选词计算 md5(word + "\n"),也就是把真实的 0x0a 换行字节一起参与哈希。
这条路线不依赖 Hashcat / John 的规则语法和后端支持,适合靶场快速复现。下面脚本同时兼容 Kali / Ubuntu 常见的 rockyou.txt.gz 和已解压的 rockyou.txt:
#!/usr/bin/env python3
import gzip
import hashlib
from pathlib import Path
target = "07e2a8ac8bd28bc3a0ffc4fab3145b5b"
wordlist = Path("/usr/share/wordlists/rockyou.txt.gz")
if not wordlist.exists():
wordlist = Path("/usr/share/wordlists/rockyou.txt")
opener = gzip.open if wordlist.suffix == ".gz" else open
with opener(wordlist, "rt", encoding="latin-1", errors="replace") as f:
for line in f:
word = line.rstrip("\r\n")
digest = hashlib.md5((word + "\n").encode("latin-1")).hexdigest()
if digest == target:
print(f"CRACKED: {word}")
break
保存为 /tmp/crack_md5_echo_newline.py 后运行:
python3 /tmp/crack_md5_echo_newline.py
输出:
CRACKED: zombie666
方案 B:Hashcat 规则
Hashcat 的规则语言支持 \xNN 十六进制字节写法,可以用规则在候选密码末尾追加 0x0a。这条路线已在 Kali WSL 的 hashcat v7.1.2 中验证通过。
如果 rockyou 还未解压:
sudo gunzip -k /usr/share/wordlists/rockyou.txt.gz
创建规则:
echo '$\x0a' > /tmp/newline.rule
爆破:
hashcat -m 0 -a 0 /tmp/hash.txt /usr/share/wordlists/rockyou.txt -r /tmp/newline.rule --force -O
查看结果:
hashcat -m 0 /tmp/hash.txt --show
如果明文以 $HEX[...] 形式输出,可以解码并去掉最后一个换行字节:
hashcat -m 0 /tmp/hash.txt --show \
| awk -F: '{print $2}' \
| sed 's/\$HEX\[//;s/\]//' \
| xxd -r -p \
| head -c -1
期望输出:
zombie666
Kali WSL 小字典验证时,Hashcat 的 potfile 结果为:
07e2a8ac8bd28bc3a0ffc4fab3145b5b:$HEX[7a6f6d6269653636360a]
其中 7a6f6d6269653636360a 解码后是 zombie666\n,去掉最后的 0a 换行字节就是 zombie666。
方案 C:John the Ripper 规则
创建规则配置:
cat > /tmp/john_newline.conf << 'EOF'
[List.Rules:AppendNewline]
$\x0a
EOF
爆破:
john --format=raw-md5 \
--wordlist=/usr/share/wordlists/rockyou.txt \
--rules=AppendNewline \
--config=/tmp/john_newline.conf \
/tmp/hash.txt
查看结果:
john --show --format=raw-md5 /tmp/hash.txt
防坑点
echo -n password | md5sum才是不带换行的md5(password)。- 如果 Hashcat / John 规则路线失败,先用 Python 脚本确认哈希类型,不要急着换大字典。
- Hashcat 输出
$HEX[...]是正常现象,因为明文中包含不可见换行字节。 - 如果目标脚本使用
printf "%s" "$password" | md5sum,就不应该追加换行。
来源案例
- HackMyVM Rsscross:MySQL
flag.echo表中保存07e2a8ac8bd28bc3a0ffc4fab3145b5b,实际是md5("zombie666\n"),破解后获得zb:zombie666。