ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Web口令破解全链路:哈希识别、字典攻击与机器学习弱口令评估

Web口令破解全链路:哈希识别、字典攻击与机器学习弱口令评估 简介面向国科大“Web安全技术”口令破解大作业的实践资源适合选修该课程的学生以及对密码安全、机器学习结合应用感兴趣的初学者。包内围绕密码特征提取、特征统计与暴力猜测三个模块组织每个模块均有对应脚本与输出提供真实泄露口令样本、特征分析结果和可视化图表通过train.csv等训练数据以及str_analysis开头的统计结果可以直观理解口令长度、字符组成、重复模式等特征如何影响自动猜测的成功率。资源共155个文件以txt、csv、py为主另有sample样本、png可视化图、xlsx统计表、Markdown说明等压缩包约170.54MB目录结构兼顾原始数据、分析脚本、运行结果与图表便于按模块快速定位。目前已有360人学习下载既能辅助完成大作业也可作为口令安全小项目或相关课题研究的基础素材。1. 口令破解大作业从Web登录页到弱口令库的一条完整链路国科大的Web安全技术课期末大作业十有八九会落在口令破解上给你一个本地还原的Web登录系统再丢一份哈希文件让你把弱口令翻出来并解释为什么能破、怎么防。这不是一门“跑个字典”的课它真正想让你看清楚的是口令从用户脑子的明文到服务器数据库里的哈希再到攻击者手里可以变现的那条链路。很多同学第一次做这道题会卡在三件事上字典从哪里来、哈希怎么识别、爆破参数怎么设才能不把自己机器跑死。这篇笔记把整份大作业拆成可复现的流程先说清楚哈希和Web登录机制的薄弱点再落地到字典生成、Hashcat/John跑离线破解最后用机器学习做一轮口令强度评估把“会破”升级成“知道为什么能破”。适合刚上手Web安全的研一学生也适合想在企业内网做口令基线检查的运维照着步骤走完基本就能交付一份有数据、有截图、有模型分析的作业报告。2. 口令破解的原理准备哈希算法、登录环节与实验环境选型2.1 口令的三种存储姿势MD5、加盐哈希和自适应哈希口令在服务端很少存明文绝大多数“破解”其实是拿到哈希值之后做离线碰撞。先分清三种存储层次最原始的是无盐MD5或SHA-1同一个口令的哈希值永远一样查彩虹表或直接跑字典就能命中好一点的是加盐哈希每个用户随机一个盐值和口令拼在一起再算哈希导致相同口令的哈希结果也完全不同彩虹表失效再往前一步是自适应哈希算法比如bcrypt、scrypt、Argon2它们故意设计成慢哈希每次计算要牺牲几十毫秒到几百毫秒把GPU的并行优势压下去。大作业里给的哈希文件通常不会只有一种算法可能混着MD5、SHA-256和少量bcrypt。判断算法可以先看哈希长度和前缀32位十六进制大概率是MD540位是SHA-164位是SHA-256而bcrypt以$2a$开头。常见做法是先用hashid或Hashcat自带的--example-hashes做一次试探不要上来就默认MD5否则后面字典跑得再快也是白费。2.2 Web登录链路里最容易被拿下的两个环节在线爆破Web登录和离线破解哈希是两条完全不同的路径。在线攻击的目标是登录接口本身核心在“请求重复”和“绕过限制”。一个典型的登录表单包含用户名、口令、可能有的验证码或Token前端把数据POST到某个接口服务端校验后返回会话Cookie。最薄弱的第一环是接口没有限流攻击者可以无限提交第二环是验证码校验逻辑疏忽例如验证码在后端只在Session里存一次校验通过之后没有销毁导致同一个验证码可以反复使用。做作业时不要一上来就写爆破脚本先抓包分析请求结构。我一般用Burp Suite的Repeater手动提交几次确认表单的参数名、是否加密传输、返回报文里有没有统一错误提示。如果返回的是“用户名或口令错误”这类的合并提示说明后端没有暴露用户名枚举爆破时就不需要区分用户名的存在性如果提示“用户不存在”则可以先枚举用户名再针对特定用户名跑口令字典。2.3 实验环境选型为什么本地靶机是最不折腾的选择在线爆破和脆弱代码扫描都必须控制在一个可控环境里作业通常在导师指定的靶场或本地虚拟机中完成。没给靶场的话推荐自己搭一个轻量靶机DVWA或一个简单的Flask登录应用都可以。DVWA的优点是自带不同安全等级日志、数据库结构都看得见适合录制实验过程Flask版本的优势是源码可控你可以在登录函数里刻意去掉验证码和限流制造一个“安全行为”的对照组和一个“不安全行为”的实验组。我建议用Docker起DVWA干净、可随手销毁docker run -d -p 8080:80 vulnerables/web-dvwa注意DVWA默认初始状态数据库未初始化浏览器打开首页会跳转到安装页面点击“Create / Reset Database”即可完成初始化。此命令仅用于本地教学靶机任何针对非授权目标的爆破都属于违规操作。环境选本地虚拟机而不是云服务器的原因也很实在爆破类工具会被云厂商的防火墙标记而且租用GPU云主机跑Hashcat成本完全没必要。本地一台带CUDA的N卡就足够应付作业里的中小规模字典。3. 字料预处理与字典生成把rockyou变成能打的词表3.1 口令样本的清洗与频率排序拿到哈希文件之后要先有一个高质量的候选口令集。Kali自带的rockyou.txt是最常用的起步词表但它的原始格式有很多噪声空行、全角字符、带首尾空格的口令这些都会干扰破解效率。第一步是清洗把UTF-8编码统一、去重、按行整理干净# 解压rockyou词表过滤空行和首尾空格再按字符数排序 gzip -dc /usr/share/wordlists/rockyou.txt.gz | \ sed s/^[[:space:]]*//; s/[[:space:]]*$// | \ grep -v ^$ | \ sort -u /tmp/rockyou_clean.txt # 统计词表规模确认清洗后没有大量重复 wc -l /tmp/rockyou_clean.txt这段命令里sed负责去除每行的前导和尾部空格grep -v ^$过滤空行sort -u同时完成排序和去重。很多人忽略的一点是编码rockyou.txt.gz 本身是UTF-8编码但Windows环境下用记事本打开再另存可能会变成带BOM的UTF-8BOM字符会被当成口令的一部分导致哈希永远匹配不上。清洗完可以用file /tmp/rockyou_clean.txt检查编码格式。清洗之后不要急着跑先做一次频率分析。真实用户的口令分布高度倾斜前1万条口令能覆盖非常高的命中率。用sort加uniq -c统计词频文件再把最高频的5000条截取出来作为“高频优先字典”# 假设已有带次数的口令记录 sort -t -k1,1nr /tmp/rockyou_with_count.txt | head -5000 | cut -d -f2- /tmp/top5000.txtsort -k1,1nr按第一列数字从大到小排head -5000取前5000cut去掉计数字段只保留口令本身。这样得到的词表兼顾了覆盖率和体积离线破解时可以先跑它再慢慢扩到全量字典。3.2 规则变异leet替换、连续数字与年份后缀纯字典只能覆盖已泄露的口令作业里要求的口令规律挖掘需要通过规则引擎把基础字典“变异”成更大的候选集。Hashcat和John the Ripper都支持规则语法。以Hashcat为例内置的best64.rule是一组常用变形规则包含大小写变化、数字追加$1$2$123、字母替换a变s变$等。hashcat -a 0 -m 0 /tmp/hashes_md5.txt /tmp/rockyou_clean.txt \ -r /usr/share/hashcat/rules/best64.rule \ --outfile /tmp/cracked_md5.txt --outfile-format2 \ --status --status-timer10参数含义逐个说明-a 0指定直方攻击模式也就是纯字典加规则-m 0声明哈希类型为MD5-r加载规则文件--outfile-format2把输出格式设为“哈希:明文”方便后面提交结果--status-timer10每10秒打印一次实时速度。值得注意的参数是-O它开启内核优化能显著提升GPU利用率但代价是可能改变掩码的处理行为对新手来说确认结果一致后再开-O更稳妥。3.3 Mask攻击把键盘路径和年份写进生成规则规则变异适合处理已有口令但线上靶机的口令不一定是历史泄露口令更可能是 “某中文姓名拼音出生年份” 或 “键盘斜对角路径”。这时候要用掩码攻击。掩码里的?l代表小写字母?d代表数字?s代表特殊符号。例如要生成8位以内、首字母大写、后面跟两个数字加3个小写字母的口令写法是hashcat -a 3 -m 0 /tmp/hashes_md5.txt ?u?l?l?l?l?d?d?s \ -i --increment-min6 --increment-max8 \ --outfile/tmp/cracked_mask.txt-a 3是掩码攻击模式-i开启增量--increment-min6表示从6位开始尝试--increment-max8最多尝试到8位。需要注意的是掩码攻击的候选数量级很容易失控6位全小写加数字是几十亿级普通笔记本GPU可能要跑几天。所以先做一次估算把掩码里每个字符位置的字符集大小相乘超过1亿就先收缩范围比如只跑?l?l?l?l?d?d把学生作业中最常见的“拼音数字”拿下来。我习惯把这一步和字典攻击做串联字典跑完一遍再上小范围掩码规则生成的字典则作为第三梯队。作业报告里可以截图三次攻击的速度和命中数量对比出“口令规律”的实际分布这部分数据比单纯贴出破解口令更有分析价值。4. 机器学习口令强度评估用分类器定位弱口令池4.1 特征工程长度、字符类别、键盘路径和泄露频率口令破解到一定阶段导师通常还会追加一个要求用机器学习方法评估口令强度并解释哪些维度使口令变得脆弱。这里把口令转成特征向量。比起直接用词向量手工构造特征更可控也更符合“安全分析”的表达习惯。我用到的基本特征有六类口令长度、字符类别数量是否同时包含大小写/数字/特殊符号、数字比例、连续字符长度例如“123456”含有长度为6的连续自然数、泄露特征口令是否出现在rockyou前10000条中、键盘路径特征是否匹配“qwerty”、“asdfgh”这类连续斜向路径。不要忽视年份特征——大量真实口令以“19xx/20xx”结尾用正则抽出来做一个布尔值。4.2 训练一个轻量口令评分器随机森林 特征向量以sklearn的随机森林为例完全可以在笔记本上几分钟内完成训练。代码核心分三步特征提取、标记生成、训练与交叉验证。import re import pandas as pd from sklearn.ensemble import RandomForestClassifier from sklearn.model_selection import cross_val_score def extract_features(pw): 把单个口令转成特征向量特征顺序要和训练时一致 feats [] feats.append(len(pw)) # 长度 char_categories 0 if re.search(r[a-z], pw): char_categories 1 if re.search(r[A-Z], pw): char_categories 1 if re.search(r[0-9], pw): char_categories 1 if re.search(r[^a-zA-Z0-9], pw): char_categories 1 feats.append(char_categories) # 字符类别数 digit_ratio sum(c.isdigit() for c in pw) / max(len(pw), 1) feats.append(digit_ratio) # 数字占比 feats.append(1 if re.search(r(19|20)\d{2}, pw) else 0) # 年份特征 keyboard_paths [qwerty, asdfgh, zxcvbn] feats.append(1 if any(kp in pw.lower() for kp in keyboard_paths) else 0) return feats # 假设已有样本集df包含password列和label列label1表示弱口令 features df[password].apply(lambda x: extract_features(x)) X pd.DataFrame(features.tolist(), columns[len, char_cat, digit_ratio, year_flag, keyboard_flag]) y df[label] model RandomForestClassifier(n_estimators200, max_depth8, random_state42) scores cross_val_score(model, X, y, cv5, scoringf1) print(cross_val F1:, scores.mean())这段代码里extract_features的返回值顺序一旦固定训练和推理必须保持一致如果后面加了一个特征旧模型缓存就不能再复用。cross_val_score用5折交叉验证返回F1值比单独划训练集和测试集更稳。注意这里的“标签”怎么定最简单的方法是使用权威的弱口令列表做正样本非弱口令随机采样做负样本也可以用Hashcat破解掉的口令当正样本没破出来的当负样本但这个做法会把“字典覆盖”和“口令弱强度”混在一起模型会偏向字典形态这点在作业答辩时要讲清楚。4.3 把模型输出接回破解流程筛选高命中率候选集模型的直接产出是一个0到1的弱口令概率值。与其只写一个准确率数字不如把这个概率值接回字典攻击流程形成“机器学习辅助字典生成”的完整闭环。# 对候选口令打分并截取概率最高的前N条作为新的攻击字典 import joblib model joblib.load(/tmp/password_rf.joblib) candidate_dict /tmp/rockyou_clean.txt top_n 20000 with open(candidate_dict, encodingutf-8, errorsignore) as f: candidates [line.strip() for line in f if line.strip()] scored [(pw, model.predict_proba([extract_features(pw)])[0][1]) for pw in candidates] scored.sort(keylambda x: x[1], reverseTrue) with open(/tmp/ml_weakpool.txt, w, encodingutf-8) as f: for pw, prob in scored[:top_n]: f.write(pw \n)joblib.load读取之前训练好的模型predict_proba返回每个类别的概率取索引为1的列就是“弱口令”概率。按概率降序排截取前20000条。这样做的意义是原始rockyou有1400万条纯字典跑可能半天但按模型概率排序后高命中段几乎集中在前面后续跑Hashcat或在线爆破时就能大幅压缩时间。我就是靠这个步骤把原本要跑两小时的在线字典爆破压缩到十几分钟并且命中口令的数量反而更多。5. 常见问题排查爆破速度、误报与防封禁的边界5.1 字典跑了半天零命中哈希类型识别错现象用hashcat -a 0 -m 0跑MD5字典跑完所有词表一个哈希都没解开。原因哈希类型判断错误文件里实际可能是NTLM哈希32位十六进制但算法完全不一样或者带盐的格式被当成了无盐MD5。解决先用hashid或hashcat的--identify功能识别拿到哈希文件后先取前几行看长度和特殊前缀再翻作业说明确认哈希类型如果作业给的是shadow文件或者包含多个字段需要用:分割提取真正的哈希字段后再破解。5.2 GPU跑不满但风扇狂转字典里有重复项和超长口令现象Hashcat显示速度不到几十万H/s但GPU占用率很高速度波动很大。原因字典里有大量重复口令和超过90字节的超长口令。超长口令会触发Hashcat的慢路径单条哈希计算时间成倍增加重复项则会拖慢内核调度。解决跑之前强制sort -u去重再用awk length($0)32过滤掉超长口令或在Hashcat里加--pw-min 4 --pw-max 32限定口令长度范围另外把字典文件放在SSD上避免机械硬盘读取成为瓶颈。5.3 在线爆破被限流爆破到一半IP被禁现象用Hydra或自写脚本爆破登录接口跑到几百次请求之后服务器开始返回429再往后直接拒绝连接。原因靶机虽然没在应用层做限制但前置Nginx或WAF检测到了高频请求。解决把线程调低-t 4改成-t 1加-w 2设置每次请求延迟2秒如果作业允许换用代理池轮换出口IP但更重要是先确认靶机有没有反自动化保护机制。用Burp的Throttle功能做延迟会比脚本里硬sleep更接近真实用户的行为曲线。5.4 机器学习模型准确率很高但实际筛选效果很差现象随机森林训练F1到了0.95但拿它筛完字典再去爆破命中率反而比原字典更低了。原因训练标签有问题。如果正样本全部来自rockyou泄露的口令模型学到的是“和rockyou相似的就是弱口令”而不是“不安全的口令”。最终筛选结果让候选集越来越像rockyou的子集失去了泛化能力。解决正负样本的构造要混合来源正样本除了泄露口令库还要包含从靶机爆破实验中实际命中过的口令负样本除了随机生成强口令也要加入“看似复杂但不一定安全”的口令。同时在报告中用独立测试集评估不要只汇报训练集交叉验证分数。5.5 作业报告截图和日志被当成“攻击记录”现象提交报告时只贴爆破成功的截图和命令行被评审质疑“没有授权测试依据”。原因没有在报告开头说明实验环境的边界、所用靶机的地址、以及作业允许范围也没有保存工具输出的完整日志。解决报告里明确写“实验仅在本地DVWA靶机/导师指定虚拟机完成目标IP为127.0.0.1或内网测试地址”所有爆破截图必须包含靶机地址和当前时间戳Hashcat日志用--logfile-disable关掉无关调试输出只保留状态进度和时间戳最后把所有命令和参数写进附录便于复核。6. 验证与收尾用本地靶机把整套流程跑出一个可复现结果6.1 用Flask搭一个最小登录接口做在线爆破验证前面的离线破解可以随时用哈希文件验证但在线爆破需要一个可控的登录接口。下面这个Flask应用刻意不限制请求频率专供验证爆破脚本from flask import Flask, request, session, redirect, url_for app Flask(__name__) app.secret_key local-test-secret VALID_USER admin VALID_PASS Ww123456! app.route(/login, methods[POST]) def login(): username request.form.get(username, ) password request.form.get(password, ) if username VALID_USER and password VALID_PASS: session[logged_in] True return login success return invalid credentials, 401 if __name__ __main__: app.run(host127.0.0.1, port5000, debugFalse)这段代码里host127.0.0.1是关键只监听本机避免公网访问。你可以把它当成在线爆破的目标验证Hydra的-C组合字典能否命中Ww123456!。6.2 用模型筛选后的词表做一轮最终爆破把第4章生成的ml_weakpool.txt用于在线爆破和原始rockyou各跑一遍记录同一目标下的命中时间和命中口令数量对比# 使用魔改后的词表单线程爆破本地靶机 hydra -l admin -P /tmp/ml_weakpool.txt 127.0.0.1 http-post-form \ /login:username^USER^password^PASS^:invalid credentials \ -t 1 -w 2 -f # 跑原始rockyou前20000条做对照 hydra -l admin -P /tmp/rockyou_top20000.txt 127.0.0.1 http-post-form \ /login:username^USER^password^PASS^:invalid credentials \ -t 1 -w 2 -fhttp-post-form后面的三个字段是靶机路径、POST体模板和失败标识。^USER^和^PASS^是Hydra的占位符失败标识必须和Flask返回的报文完全一致写错一个词就会把成功当失败、失败当成功。注意-f参数表示找到第一个正确口令后立即停止验证速度时也可以不加这个参数让字典跑完看总耗时。6.3 最终交付作业报告应该包含的数据维度口令破解大作业的实验数据要覆盖四个方面环境说明靶机地址、工具版本、GPU型号、破解过程日志命令、参数、运行时长、破解成功率、口令分布分析长度分布、字符类别分布、年份占比、防御建议升级哈希算法、加盐、限流、验证码一次性校验。把ML模型的特征重要性排序放到附录用model.feature_importances_导出一份表格能直观说明哪些特征对“弱口令识别”贡献最大。之前有一版作业我只贴了成功破解的口令列表被导师打回要求补充“失败尝试”的分析。从那以后我每次做口令评估都会强制跑一遍“对照组”原始字典、规则增强字典、模型筛选字典各跑一次记录三条链路的耗时和命中数这个习惯帮我发现了模型筛选出的词表并不适合所有靶机——有些靶机口令是随机生成的字典再优化也没用这时掩码攻击才是正解。口令破解的工业价值不在于能把多少口令还原成明文而在于你能通过实验证明哪一类用户习惯才是最脆弱的然后在报告里写清楚对应的防御优先级。希望这份笔记能帮你把大作业做成一份真正可复现的安全分析报告。本文还有配套的精品资源点击获取
返回列表