☰
口令破解实战:hashcat、规则攻击与机器学习如何高效配合
2026/10/17 2:57:53 网站建设 项目流程

简介:面向国科大Web安全技术课程的《口令破解》大作业参考实现,适合选修该课程的学生,也适合对口令安全与密码分析感兴趣的初学者。代码覆盖密码特征提取、特征统计与暴力猜测三个核心环节,并引入机器学习思路对泄露密码库进行建模,帮助理解口令安全分析的基本流程。压缩包共155个文件,约170.54MB,包含txt数据记录、csv数据集、py脚本、sample样本、png可视化图及xlsx统计表等,其中CSDN、Yahoo等数据集被整理为可用的训练样本,目录结构清晰,便于按模块查阅和提取所需内容。目前已有362人学习下载,可据此参考数据处理方法、特征工程思路与猜测策略,快速搭建口令破解实验并完成课程作业,附带的样本、图表与中间结果也能用于撰写实验报告,内容针对性强,适合作为Web安全方向动手实践的实用素材。

1. 口令破解这门大作业:我一开始就押错了方向

如果有人问我 Web 安全技术里哪门课的大作业最容易翻车,我会毫不犹豫说是口令破解。那门课给了一包加密过的口令散列,要求既用传统方法也用机器学习思路尽可能还原明文,最后交一份能把原理讲清楚的报告。我当时把宝全押在“训一个神经网络碾压全场”上,结果真正拉开分数的却是最不起眼的规则攻击,这个结果到现在我都记得。

这篇东西准备写透三件事:一包混杂散列怎么快速理出头绪、传统破解和机器学习各自该怎么分配力气、以及哪些细节会让你的进度一夜归零。正在做同类大作业的学生可以直接把我的流程扒走;想补口令破解底子的熟手,也能看到我从“命令能跑”到“判断依据是什么”的决策过程。文里的命令都在课程提供的模拟环境和授权数据上验证过,原样照着敲就行。

2. 动手前先把题面读透:三条不看必翻车的约定

课程压缩包里通常装着三样东西:一个散列文件、一个口令训练样本集、一份写得比较官方的说明文档。我拿到包的第一反应是解压直接开跑,然后被一个 line-length 报错教了做人。后来老老实实花半天把题面读透,反而省下了后面三个通宵。这半小时花得值,因为后面所有策略都是从这里长出来的。

2.1 散列不是一锅乱炖:先花半小时分类型再动手

散列文件不是一锅乱炖,里面可能混着 MD5、SHA1、SHA256、bcrypt,甚至带盐的格式。hashcat 的-m参数一旦给错,要么不认格式直接跳过,要么把 bcrypt 当 MD5 跑,后者几乎等于拿卡车运蚂蚁,白白烧一个晚上。

我一般先按长度和字符集做第一轮分类:32 位十六进制多为 MD5(若目标来自 Windows dump 则优先怀疑 NTLM);40 位多为 SHA1;64 位多为 SHA256;$2y$或$2b$开头的是 bcrypt,自带盐,设计上就是故意慢。冒号分隔的hash:salt格式不要拆开,原样保留,后面跑的时候直接喂给 hashcat 就行。

import re def guess_hash(line): line = line.strip() if re.fullmatch(r'[0-9a-fA-F]{32}', line): return 'md5 / ntlm', '0 / 1000' if re.fullmatch(r'[0-9a-fA-F]{40}', line): return 'sha1', '100' if re.fullmatch(r'[0-9a-fA-F]{64}', line): return 'sha256', '1400' if line.startswith('$2'): return 'bcrypt', '3200' return '带盐或其他格式,需要看题面', '?' with open('hashes.txt', 'r', encoding='utf-8', errors='ignore') as f: for line in f: line = line.strip() if line: print(line[:40], guess_hash(line))

这个脚本不追求识别率百分百,只要能把“谁是慢类型、谁是快类型”分开。判断逻辑就三条:看长度、看字符集、看前缀。md5 和 ntlm 都是 32 位,区别要看目标来源,我们作业里目标是 Web 登录场景,所以优先按 md5 处理。分类完之后统计数量,你会发现时间预算完全不一样:md5 在 GPU 上是每秒几十亿次的量级,bcrypt 可能只有几万次,同样是三千行散列,策略完全不同。我把这步叫“先分土和石头”,md5 是挖土,bcrypt 是考古,不能一个方案通吃。

2.2 先把授权边界钉死:能打什么、不能碰什么

大作业最常见的坑不是技术,是边界。这次的作业说明写得很清楚:只允许对课程提供的模拟数据包和我们自己起的本地靶机 demo 站点操作,不允许对任何在线系统、他人账号使用。本地靶机上那个 Web 登录表单是特意留了弱口令当题眼,跑通了算分。

真实业务里的口令破解,必须要有书面授权和完整的操作记录,这不是跑通一条命令就完事的事。我当时的做法是每一步都留了日志:什么时候跑的哪个命令、用了什么词库、命中多少,全部记下来。这个习惯后来帮我写报告省了大力气,因为评分的人最怕看到“我也不知道怎么就破了”。另外,报告里绝不能原样贴真实样本里的明文口令,课程要求演示样本做脱敏处理,这也是我后来一直保持的习惯:样本永远只放 hash 前缀,不放完整明文。

2.3 把评分口径拆成指标:破解率、方法多样性和可复现性

题面读完还要读“话外音”。我把评分理解成三块:破解成功率、方法多样性、可复现性。这三块权重不一样,但互相影响,我的策略是先把成功率做上去,再谈多样性,最后用可复现性兜底。

评分关注点我的理解对应动作
破解成功率还原出的明文数量 / 总散列数先跑字典+规则拿基础分
方法多样性是否用了至少两种不同思路传统攻击 + 机器学习候选生成
可复现性别人照报告能否重跑一遍固化命令、日志、参数说明

时间分配上,我用了一周:前 40% 做传统破解拿稳基础分,中间 30% 做机器学习部分,最后 30% 写报告和整理复现命令。这里有个容易被忽略的点:机器学习的模型再好,如果报告里说不清数据集怎么来的、候选怎么生成的,分数一样上不去。所以我把“可复现”当成第一优先级的指标,后面每个策略都写成能一键跑的脚本,而不是在命令行里敲一堆记不住的东西。

3. 传统破解三板斧:字典、掩码、规则怎么串起来用

传统方法看着简单,但能不能拉开差距,全看顺序和预处理。我的经验是三板斧按“单位时间命中率”排序:先字典,再规则,最后掩码。很多人一上来就怼大掩码,结果一个小空间跑一夜,不如先把字典和规则的便宜占完。

3.1 字典攻击:rockyou 拿到手别直接用,先做两道预处理

rockyou 词库是经典公开词库,量大但脏:有重复行、超长行、还有大量老掉牙的口令。直接扔给 hashcat 不是不行,只是会多花无谓的时间。我一般先做两道预处理:去重,然后按长度截断。

# 去重 sort -u rockyou.txt -o rockyou_uniq.txt # 只保留 16 位以内的短口令,长口令既慢命中率又低 awk 'length($0) <= 16' rockyou_uniq.txt > rockyou_short.txt

第一轮字典攻击用正规命令跑:

hashcat -m 0 -a 0 hashes.txt rockyou_uniq.txt -w 3 -O --status --status-timer=60

参数含义:-m 0是 MD5 类型,-a 0是字典模式,-w 3把显卡负载拉满,-O走优化内核,--status每 60 秒打印一次进度。跑完用--show看战果:

hashcat -m 0 --show hashes.txt

命中后的明文会存在 hashcat 的 potfile 里,这个文件就是你的“账本”。第一轮字典攻击通常能吃掉弱口令里的大部分,我这边大概清了三分之一。剩下的散列单独存一份,别让后续攻击每次都重跑同一批目标。

3.2 掩码攻击:8 位纯数字是最低垂的果实

字典跑完一圈,剩下的目标里最甜的是纯数字短口令。注册规则往往只要求“至少 8 位”,于是大把用户就设成 8 位纯数字,这类目标对掩码攻击几乎不设防。

hashcat -m 0 -a 3 hashes_left.txt '?d?d?d?d?d?d?d?d' --increment --increment-min 6

-a 3是掩码模式,?d表示数字 0-9,?l表示小写字母,?u大写,?s特殊符号,?a全字符集。--increment的意思是让长度从 6 位开始递增,而不是死磕 8 位。用掩码前一定要先算 keyspace:

hashcat -m 0 -a 3 --keyspace '?l?l?l?l?d?d?d?d'

keyspace 就是空间大小。我常用的几个空间量级大致是这样:

掩码空间大小直观感受
8 位纯数字10^8 ≈ 1 亿显卡上秒级到分钟级
8 位小写字母26^8 ≈ 2 × 10^11可接受,几十分钟到几小时
8 位小写+数字36^8 ≈ 2.8 × 10^12开始吃紧,要看显卡
10 位全字符集95^10 ≈ 6 × 10^19不要跑,这是玄学级

跑之前用 keyspace 除以你的实测速度,得到预估时间。预估超过几个小时的掩码,我一般直接放弃,转而换成更定向的模式,比如“首字母大写 + 小写 + 两位年份”这类带语义的掩码。怕的不是跑得慢,是跑了十几个小时最后发现空间没封顶,这种“无底洞”掩码我在作业里见过太多人踩。

3.3 规则攻击:把一本字典当一万本用

真正帮我拉开分数的是规则攻击。规则就是给字典里的每条口令做变形:追加两位数字、首字母大写、把 a 换成 @、大小写交替。一个 best64.rule 自带 64 条常用规则,等于把词库原地放大几十倍。

# 有条件的话拆一个规则文件,追加常见年份后缀 cat my_rules.rule # 内容示例: $2$0$2$4 $2$0$2$3 c

规则文件里$2$0$2$4表示在末尾追加字符串 2024,c表示首字母大写。跑的时候直接指定:

hashcat -m 0 -a 0 hashes_left.txt rockyou_short.txt -r my_rules.rule -w 3 -O

想确认规则效果,先用--stdout预览,别稀里糊涂跑完才发现规则写得有问题:

echo "admin" | hashcat --stdout -r my_rules.rule | head -n 20

输出里能看到admin2024、Admin2024、admin首字母大写等变体。规则攻击的回报率在传统三板斧里是最高的,因为大多数人的“自创密码”其实就是常用词加个年份或符号,规则攻击恰好精准覆盖这一类。我这次作业里,规则攻击的命中量接近字典攻击的两倍,这也是我一开始没料到的。

3.4 顺序定死:字典、规则、掩码,别上来就冲着夕阳跑

三者的顺序不只是习惯问题,是数学问题。字典攻击单位时间命中率最高,因为它是真实历史口令的分布;规则攻击其次,因为它顺着人类变形习惯走;掩码攻击空间最大、命中靠运气,所以排最后。

还有两个配套习惯:一是把已经破解的 hash 单独摘出去,二是每次换策略前先看 potfile 汇总。摘出已破解目标用--show加cut就行:

hashcat -m 0 --show hashes.txt | cut -d: -f1 > cracked_hashes.txt

然后用编程方式做差集,剩下的写回 hashes_left.txt。这一步看着机械,但能让每一轮攻击都跑在“未破解子集”上,速度感和命中率反馈都清楚得多。别小看这个习惯,它直接决定你熬夜是对着进度条发呆,还是看着命中数一路涨。

4. 机器学习那部分:从马尔可夫到 LSTM 的落地对比

大作业必须用机器学习思路,这是题面里写死的。我一开始以为这是压轴戏,做完才发现它更像是“报告亮点工程”:传统方法已经把好啃的骨头啃完了,机器学习负责把字典覆盖不到的漏网之鱼捡回来。方向没搞错,分数就稳了。

4.1 为什么非要上机器学习:字典的盲区在哪

字典和规则的本质是“见过的才打得中”,但真实口令里有一类是“风格统一但内容从没见过”——比如机构内部喜欢的编号规律,像部门缩写加工号反转,这种模式字典里不可能有,规则也编不出来。机器学习的价值在于从训练样本里学概率分布,然后按这个分布生成“像用户会设置的但字典里没有的”候选。

大作业要求至少两种思路,其实就在考这个:能不能把训练集里的统计规律提取出来,转化为可执行的破解步骤。需要注意的是,机器学习生成的候选是给 hashcat 当词库用的,不是让你写个模型直接猜 hash。模型只负责产生候选口令,算 hash 对比这种苦力活还是交给 hashcat。

4.2 二阶马尔可夫:半小时能跑通,且能讲清原理

马尔可夫模型的思路很直白:口令里字符不是独立出现的,前一个或前两个字符决定了下一个字符的概率分布。统计训练集得到“前两个字符 → 下一个字符”的转移概率,然后顺着概率走,就能生成大量“读起来像人设的”候选。

import random from collections import Counter, defaultdict def train(words, order=2): """统计转移概率:前 order 个字符 -> 下一字符分布""" freq = defaultdict(Counter) start = Counter() for w in words: seq = '^' * order + w + '$' start[seq[:order]] += 1 for i in range(order, len(seq)): ctx = seq[i - order:i] freq[ctx][seq[i]] += 1 return start, freq def pick(dist): """按权重随机取一个字符""" total = sum(dist.values()) r = random.random() * total for k, v in dist.items(): r -= v if r <= 0: return k def generate(start, freq, order=2, max_len=24, count=50000): res = [] for _ in range(count): ctx = pick(start) pwd = '' while len(pwd) < max_len: ch = pick(freq[ctx]) if ch == '$': break pwd += ch ctx = (ctx + ch)[-order:] if pwd: res.append(pwd) return res if __name__ == '__main__': with open('train_samples.txt', encoding='utf-8', errors='ignore') as f: samples = [l.strip() for l in f if l.strip()] s, fq = train(samples, order=2) with open('ml_candidates.txt', 'w') as out: for pwd in generate(s, fq, order=2, count=50000): out.write(pwd + '\n')

这里order=2表示依赖前两个字符,^和$是口令的开始和结束标记。训练数据用的是课程提供的模拟泄露样本,几万条就能跑。生成五万条候选后,先sort -u去重,再丢给 hashcat 当字典跑:

sort -u ml_candidates.txt -o ml_uniq.txt hashcat -m 0 -a 0 hashes_left.txt ml_uniq.txt -w 3 -O

马尔可夫模型的优势是成本极低、原理好讲、报告里能画转移图。缺点是 stable 生成的候选容易集中在高频片段,比如大量123、abc变体,所以去重特别重要。我当时生成五万条,去重后剩下不到四万条。

4.3 LSTM 生成候选:高级方案,但有自己的脾气

LSTM 是拿来撑报告底气的部分。核心思路是把口令当成字符序列,模型在训练集上学习“看到前几个字符,下一个字符该是什么”,生成时用温度参数控制冒险程度。

import torch from torch import nn class PasswordLSTM(nn.Module): def __init__(self, vocab_size, emb_dim=64, hidden=128, layers=2): super().__init__() self.emb = nn.Embedding(vocab_size, emb_dim) self.lstm = nn.LSTM(emb_dim, hidden, layers, batch_first=True) self.fc = nn.Linear(hidden, vocab_size) def forward(self, x): out, _ = self.lstm(self.emb(x)) return self.fc(out) # 每个位置的字符概率 logits def sample_char(logits, temperature=0.6): logits = logits / temperature probs = torch.softmax(logits, dim=-1) return torch.multinomial(probs, 1).item()

训练时把口令做成字符序列,开头和结尾加特殊标记,用交叉熵损失训几个 epoch 就行。temperature是采样时的关键参数:太低,生成的全是高频重复串;太高,生成一堆无意义乱码。我试下来 0.5 到 0.7 之间效果最好,生成二三十万条,去重后按概率截断,只留前若干万条喂给 hashcat。

实际教训是:训练样本少于一万条时,LSTM 表现还不如马尔可夫,属于“吃着最贵的饭,操着最碎的心”。所以我把 LSTM 定位成报告里的“方法多样性”加分项,不指望它贡献主要命中量。这一点想通之后,机器学习这部分就不再焦虑了。

4.4 效果的真相:ML 不神,但能把分数补齐

我把四种方法在“剩余未破解目标”上的表现做了个对比,结论很真实:

方法准备成本候选量在剩余目标中的命中一句话结论
字典低1400 万级高(第一批)基础分来源
字典 + 规则低等效数亿级最高主力攻击
定向掩码中可控空间中,靠定向补漏专用
马尔可夫中5-10 万中性价比高
LSTM高20-30 万中偏低报告亮点

我这次作业里,马尔可夫和 LSTM 生成的口令合计贡献了约 10% 到 15% 的破解量,不算多,但恰好是字典和规则都覆盖不到的那部分。报告里写“两种思路互补”时,这段数据特别有说服力:没说机器学习无敌,但讲清楚了它补的是什么盲区、代价是什么。

5. 避坑指南:五个让破解进度归零的细节

这一章是我熬夜换来的血泪经验,每一条都让我的进度条当场归零或者白跑一整夜。按“现象 → 原因 → 解决”列出来,照着检查能省几个通宵。

5.1 hashcat 报 line-length exception:词库里有脏数据

现象:跑字典攻击不到一分钟,hashcat 直接报Line-length exception退出,后面全没跑。原因:词库里有超长行、空行,或者文件带 BOM 头,hashcat 对格式很敏感。解决:先把词库清洗一遍,再开跑。

awk 'length($0) >= 1 && length($0) <= 16' rockyou_uniq.txt | sort -u > clean.txt # 顺便去掉可能的 BOM sed -i '1s/^\xEF\xBB\xBF//' clean.txt

这个坑的根源是“拿到词库直接用”,破解工具不是人,不会自动忽略脏行。从那以后,我所有词库文件都走同一套清洗管线,再也没有被这个报错打断。

5.2 keyspace 没算,掩码跑了一夜白给

现象:有个同学跑-a 3 '?a?a?a?a?a?a?a?a?a?a',挂了一整夜,进度条几乎没动。原因:10 位全字符集空间是 95^10,约 6 × 10^19,这个量级不是一夜能跑完的。解决:开跑前先算 keyspace 和预估时间。

hashcat -m 0 -a 3 --keyspace '?a?a?a?a?a?a?a?a?a?a'

预估超过两小时的掩码,直接砍掉或改成定向模式。进入掩码环节前,我会先问自己三个问题:最短能接受多长?字符集能不能收窄?能不能拆成字典加后缀的混合模式?这步叫“给掩码上锁”,没上锁就跑等于裸奔。

5.3 ML 候选一堆重复,hashcat 等于白跑

现象:马尔可夫生成五万条,喂给 hashcat 后命中率惨淡,一看文件里全是abc123和password的微变形,重复率极高。原因:模型按频率采样,高频片段被反复生成,低概率的优质候选被淹没。解决:生成端去重加截断,耗时不长但效果立竿见影。

sort -u ml_candidates.txt -o ml_uniq.txt # 按长度过滤,筛掉明显不合理的 awk 'length($0) >= 6 && length($0) <= 16' ml_uniq.txt > ml_final.txt

另外,如果训练集太小,生成的候选会大量退化成“高频片段拼接体”,这时候别硬调模型,直接换回马尔可夫或者干脆加大传统方法的投入。机器学习不是越贵越好,合适的才是。

5.4 带盐 hash 当无盐跑,全军覆没

现象:有一批格式看起来是 40 位 hex 的散列,按 SHA1 跑了一整天零命中。原因:文件里实际是hash:salt格式,盐没参与运算,跑法完全不对。解决:先看题面或文件说明,确认是否带盐;带盐的话保留hash:salt原样喂给 hashcat,工具会自动拆开处理。

判断方法很简单:同一批目标里,如果长度一致但前缀明显不同,或者文件里有冒号分隔,十有八九带盐。另外,bcrypt 这类自带盐的格式本身就慢,跑之前分清“考古型”和“挖掘型”目标,别把宝贵的显卡时间花在无谓的计算上。

5.5 报告里出现过真实样本明文,差点翻车

现象:写报告时想展示“某条 hash 对应弱口令”作为破解证据,直接复制了明文进去。原因:偷懒,没考虑样本本身的敏感性。解决:所有截图和示例都用课程模拟数据,真实样本只保留 hash 前几位,明文一律不出现。

这个习惯后来被我一直保留:凡涉及口令样本的交付物,默认只放 hash 片段,明文只在本地日志里存。不是自己吓自己,是这行的基本素养——破解能力和样本管理是两回事,前者体现技术,后者体现职业底线。

6. 交作业前的一小时:把破解流程从“玄学”变成“可复现”

最后这一小时,我做的事不是补跑几个漏网目标,而是把整个破解过程压缩成一张能复现的流程单。这套东西后来我每次做口令相关的工作都会复用,效果稳定得不像玄学。

流程固定为四步:先分类散列并拆目标子集,再字典加规则清主战场,然后机器学习候选补盲区,最后定向掩码扫尾。每一步都配一条命令脚本,输出统一落盘,靠 potfile 做增量。这就是我交作业前反复检查的“破解流水线”,每一步都有输入、输出和日志。

支撑这条流水线的是一个具体习惯:动手前先用十分钟写一张“破解计划单”,把四件事钉死在上面。

计划项我的填写示例
散列类型统计MD5 2200 行、SHA1 600 行、bcrypt 200 行
词库清单rockyou_uniq、rockyou_short、ml_candidates
每步时间预算字典 30 分钟、规则 2 小时、ML 1 小时、掩码 1 小时
日志与结果路径logs/ 目录,potfile 统一备份

这张单子的价值在于:它逼我在开跑前就想清楚“这一步到底跑什么、跑多久、跑完看哪个文件”,而不是对着黑匣子一样的哈希文件瞎猜。计划单写完之后,剩下的执行就变成填空题,每一轮结果都能对上计划里的预算,偏差大了立刻知道哪里出了问题。

从那以后,我每次做口令破解相关的工作,都强制走一遍“先写计划单再开跑”的流程,哪怕只是校内模拟环境也不跳步。这十分钟的投入,换来的是一整周不用熬夜试错,也让我交出去的东西经得起别人照着复现。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询