

没有棋盘格、没有助记词,只有一串 SHA-256。8 位纯数字意味着候选空间正好 10^8 个,能做的事只有一件:穷举。 这一期共有两个 hash:09:30 发布的是主红包,10:44 那条讨论里又出现了一个——那是后来做实验时替换进去的。

微博正文给的是「8 位纯数字口令的 SHA-256」,配图是一张自制的 429 纪念日海报:背景铺满红色的 Too Many Requests,海报上写着同一串 SHA-256。 所以谜面本身就是解题说明——它明确告诉你口令的形态(8 位、纯数字)和验证方式(自己算一遍 SHA-256 比对)。
#!/usr/bin/env python3
"""穷举 8 位纯数字,撞出给定 SHA-256 的原像。
8 位纯数字只有 10^8 个候选。SHA-256 的「不可反推」挡得住原像攻击,
挡不住候选空间这么小的穷举。
实测:6 进程、纯 Python hashlib(无 GPU、无 SIMD 技巧),
跑完 0~99999999 全空间约 34 秒。
用法:
python brute_sha8.py 3c126f9a0270bd6bbec46d5c1b8774b95407ef8145c1a0a16b5d87a511b9b9b0
python brute_sha8.py <hash1> <hash2> -p 8
"""
import argparse
import hashlib
import multiprocessing as mp
import time
N = 100_000_000
def work(pack):
lo, hi, targets = pack
sha = hashlib.sha256
found = []
for i in range(lo, hi):
d = sha(b"%08d" % i).digest()
if d in targets:
found.append((i, targets[d]))
return found
def main():
ap = argparse.ArgumentParser()
ap.add_argument("hashes", nargs="+", help="一个或多个 SHA-256(十六进制)")
ap.add_argument("-p", "--processes", type=int, default=6)
args = ap.parse_args()
targets = {}
for h in args.hashes:
h = h.strip().lower()
if len(h) != 64:
raise SystemExit(f"✗ 不是 SHA-256(长度 {len(h)}):{h}")
targets[bytes.fromhex(h)] = h
procs = max(1, args.processes)
step = N // procs
packs = [(k * step, N if k == procs - 1 else (k + 1) * step, targets) for k in range(procs)]
t0 = time.time()
hits = []
with mp.Pool(procs) as pool:
for part in pool.imap_unordered(work, packs):
hits.extend(part)
dt = time.time() - t0
print(f"0~{N - 1} 全空间 · {procs} 进程 · 耗时 {dt:.1f}s")
hits.sort()
for i, h in hits:
print(f" {h[:16]}… -> {i:08d}")
for h in targets.values():
if not any(x[1] == h for x in hits):
print(f" {h[:16]}… -> 未命中(候选不在 8 位纯数字里)")
if __name__ == "__main__":
main()8 位纯数字只有 10^8 个候选。SHA-256 是设计成不可反推的,但设计的是一般情况下的原像攻击;候选空间小到这一步,穷举就是最优解。 实测数据:六个 Python 进程、纯 hashlib(无 GPU、无 SIMD 技巧),跑完 0~99999999 全空间耗时 34.3 秒。也就是说,「写脚本和运算需要些时间」这句话里的「些时间」,在今天的普通机器上就是半分钟量级——当年那三分钟的抢空速度,从算力上完全解释了得通。 脚本附在本节下方,直接跑就能复现(会依次报出两个 hash 对应的 8 位数字)。
同一期里出现了两个不同的 SHA-256,容易看混,这里按时间线拆开:
3c126f9a…,对应 12 份红包。4ca61510…,并说红包已经被领完了。10:44 那条是个诱饵。它同时满足两个条件:包含一段可以当谜题破解的 hash,以及一句「红包已经被领完了」。 逻辑是这样的——如果存在一个「看到含口令的微博就自动解题领红包」的机器人,它应该无视「已领完」这句话,照样把新 hash 解出来、去领那个新红包。 结果是没有动静。 他在 12:46 的复盘里给出的结论是:
12 份红包,从第一份被领(09:33:03)到最后一份(09:33:47),历时 44 秒;从微博发出算起不到三分钟。 发布时间是 09:30,第一条领取记录是 09:33:03 —— 中间那三分钟,正好和现在一台普通机器穷举 10^8 个 SHA-256 的时间处在同一量级。
主红包 · 12 份(09:30 那条微博里的 hash)
8 位纯数字,空格与全角都无所谓
实验红包(10:44 讨论微博里替换进去的那个 hash)
8 位纯数字