跳到主要内容

MD5 换行符哈希破解

命令:

echo password | md5sum

计算的不是 md5("password"),而是:

md5("password\n")

因为 echo 默认会在末尾追加换行符 0x0a。如果数据库或脚本里保存的是这种哈希,普通 hashcat -m 0john --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