前几天帮某单位做例行安全巡检,登录测试服务器以后,我习惯性地收集了一波Linux账号口令哈希,丢给John the Ripper跑了一会儿,结果连五分钟都没用到,一个运维账号的弱口令就被直接撞了出来。这种场景在真实环境里几乎每个月都能遇到:系统补丁打得很勤,防火墙规则也足够严密,最后偏偏栽在“口令太简单”这个最基础的短板上。今天想聊的,就是Linux系统安全里绕不开的一个实战课题——John弱口令检测。
John the Ripper是一款在安全圈里流传了很多年的离线密码破解工具,它能对Linux系统里的账号口令哈希做字典攻击、规则变形、增量穷举等操作,从而快速暴露那些“设了等于没设”的弱口令。对做安全运维、等保测评、渗透测试的同行来说,这属于工具箱里的常备品。下面我会从原理、安装、实操、进阶策略到加固建议,完整走一遍检测闭环,希望你看完能直接在自己的测试环境里跑起来。
1. 认清弱口令检测的本质
1.1 内网失守,多数从“口令太简单”开始
很多人对弱口令的危害没有直观感受,觉得“服务器有密码,别人不知道就行了”。但现实是,企业内部网络一旦有某个主机沦陷,攻击者第一件事就是翻它的本地账号和口令哈希,然后拿这批哈希对内网其他机器做横向尝试。如果内部账号普遍使用弱口令,比如运维习惯用“Admin@123”“P@ssw0rd”这种人人都能猜到的组合,攻击者根本不需要什么高级漏洞,只需要跑一轮字典就能批量控制多台服务器。
我在一次真实项目里见过类似的场景:某团队做内部红队演练,入口只是一台暴露了弱口令的测试机,结果短短一个小时内,攻击方利用这台机器上的口令复用现象,横向拿到了六个服务器权限,最后直接从研发内网摸到了生产数据库。事后复盘时发现,真正被利用的漏洞只有一个,但蔓延的关键却是口令太弱、多台机器同口令。弱口令就像是内网里的隐形后门,平时不会响警报,一旦有人去碰,整个防线就像纸糊的一样。
1.2 John the Ripper 在检测链条中的位置
所谓弱口令检测,本质上就是一个“在授权范围内,用攻击者视角去验证口令强度”的过程。而John the Ripper正是这一环节里的核心执行引擎。它支持的哈希类型非常全,从经典的DES、MD5、SHA-256,到Linux常见的sha512crypt、bcrypt、scrypt,再到各种应用系统的哈希,基本上能覆盖日常巡检遇到的场景。检测链条通常是:先获取到口令哈希文件,然后通过字典、规则、掩码等手段尝试还原明文口令,最后把漏洞结果转成整改任务。John做的就是中间这层最脏最累的“尝试还原”工作。
这里要区分一个概念:弱口令检测和暴力破解并不是同义词。John的攻击方式是有策略的,多数场景下靠的是“字典+规则”来模拟人的习惯,而不是毫无章法地从aaaa试到zzzz。举个例子,如果有人把口令设成“Welcome123”,一个精心准备的字典加上基础规则,可能几秒就试出来了,但如果靠纯暴力从8位小写字母加数字开始枚举,可能得跑上几年。John之所以高效,不是因为它算得快(当然它并行能力也很强),而是因为它懂得按人的习惯去猜。
1.3 使用边界与授权前提
每次讲到口令破解,我都要把边界说清楚:John the Ripper是安全检测工具,不是攻击工具。它的正确使用场景包括:对自己负责的主机做口令自检、在授权范围内做等保测评和渗透测试、拿到客户书面授权后做红队演练。没有授权就对自己不控制的系统跑破解,这是法律性质的问题,没有任何商量余地。实战中我会在测试前把授权委托书、测试范围说明都归档好,再开始操作。
另外,即使是自检,也尽量在测试环境或非核心生产环境的副本上进行。因为大规模跑增量模式会消耗不少CPU资源,操作前还要做好评估,避免影响线上业务。工具本身不会惹麻烦,但用它的时机和范围一定要拿捏好。
2. 环境准备与哈希采集
2.1 安装 John:发行版包与源码编译
John the Ripper的安装方式主要看你的系统。在Debian系发行版上,直接一行命令就能装上:
sudo apt update sudo apt install -y john在Red Hat系发行版,可以用dnf或yum:
sudo dnf install -y john不过这里有个细节:很多发行版仓库里默认的是John的老版本或精简版,格式化支持相对有限。如果你打算长期用它做日常巡检,我建议直接用官方发布的jumbo版本,它的功能更全,支持的哈希格式、规则集、掩码模式都更多。源码编译的方式也不复杂,依赖主要是gcc、make和libssl-dev,装好后执行:
git clone https://github.com/openwall/john.git cd john/src ./configure && make编译完成后,主程序在run目录下。有些发行版把二进制命名为john,而jumbo版里能直接用john或john-omp(OpenMP并行版本)。实测下来,jumbo版在处理现代哈希如bcrypt、sha512crypt时,速度和格式识别都比老版本稳得多。如果你是Kali用户,系统里已经预装了John,直接跳到下一步即可。
2.2 用 unshadow 拼出可破解的哈希文件
Linux系统的口令哈希存在/etc/shadow文件里,普通用户看不到,只有root或有sudo权限的账号能读取。拿到权限后,最标准的做法是把/etc/passwd和/etc/shadow合并成一个John能识别的文件,官方工具unshadow就是干这个的:
sudo unshadow /etc/passwd /etc/shadow > /tmp/passwd_hash.txt生成的passwd_hash.txt里,每一行都包含用户名、用户ID、完整口令哈希串和注释信息。John拿到这个文件以后,会自动识别每个账号的哈希类型,不需要你手工区分哪个是sha512crypt哪个是bcrypt。不过要注意,unshadow输出里可能包含系统账号,比如daemon、bin、sys这类没有实际登录能力的账号,它们的口令字段通常是*或!,John会自动跳过,对检测结果没有影响。
如果没有root权限,理论上也可以用其他手段收集哈希,但在合规前提下我不建议绕过权限去做这些操作。正常情况下,弱口令检测都是系统管理员或安全测试人员在明确授权的前提下,第一时间拿到shadow文件再开始分析的。
2.3 字典怎么选,从哪来
字典是弱口令检测里最关键的一环。John自带的字典通常在安装目录下的run/password.lst,里面汇集了大量常见弱口令,可以作为第一轮攻击的基础词库。如果你想要更大规模的高质量词库,社区里最常用的是rockyou.txt,几百万条真实泄露口令清洗出来的字典,覆盖了绝大多数人类取口令的习惯。在很多发行版里它的路径是/usr/share/wordlists/rockyou.txt.gz,先解压再用:
sudo gunzip /usr/share/wordlists/rockyou.txt.gz除了现成的词库,我习惯针对目标环境做一份定制字典。比如把公司名称、业务简称、域名、年份、常见数字组合按照大小写变形、前后缀拼接预先整理成列表。这类定制字典在内部测评中往往比通用大字典命中率更高,因为很多公司内部口令都跟业务信息强相关。不过要提醒一句:字典来源必须合规,别去碰非法的社工库或交易数据,使用公开的泄露口令研究数据集和正经的弱口令清单就够了。
3. 核心实操:一次完整的弱口令检测
3.1 组装目标文件,确认哈希类型
假设我已经在一台测试服务器上拿到了root权限,第一步就是生成合并文件:
sudo unshadow /etc/passwd /etc/shadow > /tmp/accounts.txt然后查看内容长什么样,看看有没有异常字段:
head -20 /tmp/accounts.txt正常情况下,你会看到类似这样的行:
root:$6$rounds=656000$xyzabc...:0:0:root:/root:/bin/bash webadmin:$6$rounds=656000$defghi...:1000:1000::/home/webadmin:/bin/bash开头$6$表示这是SHA-512加密的密码,也就是Linux系统默认的密码哈希算法;如果是$1$则是MD5,$5$是SHA-256,$2y$或$2b$则是bcrypt。John强大的地方在于它通常能自动识别这些格式。如果你希望确认John对该文件的识别情况,可以执行:
john --list=formats | grep -i sha512也可以直接用--format=sha512crypt强制指定格式,这样能跳过自动检测,避免某些特殊哈希识别失败。
3.2 字典攻击执行与参数解读
拿到合并文件之后,第一轮我建议先用系统自带字典或rockyou跑一次:
john --wordlist=/usr/share/wordlists/rockyou.txt /tmp/accounts.txt命令执行后,John会开启默认数量的线程,边跑边把进度打印在终端上。屏幕上会出现当前尝试速度、已破解的账账号数量等信息。如果运气好,几秒钟内就能看到命中提示,比如:
Loaded 8 password hashes with 8 different salts (sha512crypt [SHA512 128/128 SSSE3 2x]) Press 'q' or Ctrl-C to abort, almost any other key for status webadmin (?)这行输出意味着webadmin这个账号的口令已经被字典命中了。这里要留意一下口令策略:Linux的sha512crypt计算比较慢,字典迭代速度取决于CPU性能和哈希轮数。我曾在老款服务器上跑256MB的大字典,速度只有几百KB/s;换到当代多核服务器后速度能提升不少,但还是比MD5一类旧哈希慢得多,所以要有耐心。
3.3 结果输出与 pot 文件解析
John每破解一个口令,除了在屏幕上提示,还会把结果记录到~/.john/john.pot文件里,这个文件的格式很简单:
$6$rounds=656000$xyzabc...:Welcome123后面再跑同一个哈希文件,John会直接从pot文件里读取已知答案,不会重复计算。这个机制对效率提升很有帮助,但也会带来一个现象:第一次跑完再跑第二次,屏幕上可能显示“No password hashes left to crack”,这并不代表结果丢了,只是说明已知的已经破解完,剩下的还没被当前字典覆盖。
想要查看完整结果,用--show就行:
john --show /tmp/accounts.txt输出会列出所有已破解账号和对应口令,同时统计已破解和未破解的数量。我习惯把输出重定向到文件留档:
john --show /tmp/accounts.txt > /tmp/john_results.txt这样后续写报告时直接取数据即可。需要注意的是,--show展示的内容只包括pot文件里已经破解的哈希,未破解的不会出现。如果你想针对未破解账号再跑下一轮,不需要单独过滤,直接换策略继续跑同一个文件就行。
3.4 特殊哈希格式的处理技巧
日常巡检时,除了/etc/shadow里的口令,还可能会遇到别的场景,比如某个应用导出了口令哈希文件,格式不是Linux标准crypt格式。这时候John的--format参数就派上用场了。先列出支持格式:
john --list=formats然后根据哈希前缀判断类型,比如应用里常见的是MD5还是bcrypt,或者某个中间件自成一套的变体。找到对应格式名以后,执行类似:
john --format=bcrypt --wordlist=words.txt ./app_hashes.txt或者是:
john --format=md5crypt --wordlist=words.txt ./app_hashes.txt如果哈希文件里还带着用户名,John也能处理,只要每一行的结构是“用户名:哈希”就行,和unshadow的输出结构一致。对于结构不规整的文件,可以用awk简单整理。我遇到过一个遗留系统导出的哈希格式非常混乱,最后写了个小脚本把字段统一成user:hash形式,再交给John跑,效率高很多。
4. 让检出率翻倍的三种攻击策略
4.1 增量模式:按字符集生成口令
字典模式只能覆盖已有词汇,如果目标口令是由纯数字、生日、电话号码等组成,字典一般覆盖不到。这时可以上增量模式,也就是按指定的字符集,从1位到N位依次穷举。比如检测纯数字口令:
john --incremental=Digits --min-len=1 --max-len=10 /tmp/accounts.txt这里的Digits是John内置字符集,只包含0-9,速度非常快。测试一下,10位纯数字的全量空间是100亿个组合,看起来很多,但对John来说,在多数现代CPU上并不算离谱。如果你设置--max-len=8,那只有一亿个组合,几分钟内就能跑完。除了Digits,John还内置了All、LowerNum、UpperNum等字符集。增量模式下--min-len和--max-len是核心参数,设置合理范围能大幅缩短时间,比如检测6到8位,就不要设成1到12,否则会浪费很多算力。
4.2 规则变形:让字典具备“自进化”能力
规则变形是我最推荐的一个功能,它能把一部小字典变成几十倍甚至上百倍的攻击载荷。原理很简单:对字典里的每个基础词,按规则自动做大小写转换、添加数字后缀、前后缀拼接、替换字母(比如e换成3,a换成@)等操作。John内置了多条规则集,直接用--rules=All就能启用全部规则:
john --wordlist=words.txt --rules=All /tmp/accounts.txt举例来说,字典里有admin这个词,通过规则运行后,John会自动尝试Admin、ADMIN、admin1、admin123、adm1n、Admin@123等变形。这一招对“用户自以为设了复杂口令,但其实只是把常见词做了简单变形”的情况非常有效。我做过一次对比实验:同样一部10万条的小字典,不加规则只跑出3个弱口令,加了规则后跑出了11个,命中率直接翻了三倍多。
不过代价是计算量显著上升,规则模式下的尝试次数可能是原字典的50~100倍。所以在时间有限的情况下,可以先跑一轮不带规则的快速扫描,再针对重要账号跑规则变形。John默认带的规则集种类很多,也可以自定义规则来模拟企业内部常见口令组成习惯,这部分发挥空间很大。
4.3 掩码攻击:基于口令习惯的精准爆破
掩码攻击是John较新的一个功能,也是我实战中最常用的策略之一。它允许你按“位置模板”来生成口令,比如一个大写字母开头、接着四个小写字母、最后两个数字的模板,可以这样写:
john --mask='?u?l?l?l?l?d?d' /tmp/accounts.txt掩码符号都有明确含义:?u表示大写字母,?l表示小写字母,?d表示数字,?s表示特殊符号,?a表示任意可打印字符。这套模板能精准覆盖“首字母大写+末尾数字”这类非常常见的人类取口令习惯。对比纯增量模式,掩码攻击的最大优势是大幅压缩搜索空间。比如8位全数字是1亿次,但如果你知道企业要求口令至少8位且必须有大写字母和数字,猜它是“一个大写+若干小写+若干数字”的结构,空间直接缩小好几个数量级,跑起来非常快。
实践中我把掩码当作字典攻击的补充,等字典和规则都跑完、还没出结果的时候,再针对“拼音+生日”“英文单词+年份”等高频结构来一轮掩码。命中率相当可观。
4.4 性能调优:多进程、内存与全量载荷
John默认就会利用本机所有CPU核心,在jumbo版本里还会自动启用OpenMP并行。如果你有一台多路CPU的机器,还想再压榨一点性能,可以用--fork参数指定进程数:
john --fork=8 --wordlist=words.txt /tmp/accounts.txt但要注意,--fork只在部分模式下有效,而且每个进程会独立加载字典,内存占用会成倍上升。另一个相关参数是--mem,它影响的是部分哈希计算时的缓存大小,对某些算法的速度有一定影响:
john --mem=1024 --fork=4 --wordlist=words.txt /tmp/accounts.txt跑大字典时我习惯先用--status查看当前进度,按任意键也能看到实时的速度和剩余情况。如果一台机器要跑很久,可以把它丢到后台用nohup挂起来,但一定要做好日志和断电恢复的准备。对GPU加速,John也支持OpenCL等后端,但这通常需要单独编译配置,实战中不是必须项。我自己在普通服务器上跑现代哈希,还是靠多进程和策略优化更实在。
5. 常见问题与排查实录
5.1 高频问题速查表
很多第一次用John的人会遇到一些看起来莫名其妙的问题,其实多试几次就能摸到规律。我整理了几个高频场景:
| 现象 | 常见原因 | 解决思路 |
|---|---|---|
| 提示“No password hashes loaded” | 文件里没有John能识别的哈希,或哈希被!*占位符覆盖 | 确认文件格式,使用--format指定类型,检查账号哈希字段是否有效 |
| 自动识别格式错误 | 哈希类型特殊或版本过老 | 用--list=formats筛选匹配类型,再用--format强制指定 |
| 破解速度极其慢 | 哈希轮数高(如bcrypt、sha512crypt),或CPU核心没跑满 | 切换到低轮数哈希测试,启用--fork,或缩小字典范围 |
| 跑了很久屏幕上没有任何命中 | 口令确实较强,或当前策略没覆盖目标模式 | 换规则、换掩码、换字典,先用增量模式试探低位数空间 |
| 第二次跑同一个文件,显示没有剩余哈希 | 结果已经写进pot文件,不会重复显示 | 用--show查看已破解结果,或删除pot文件重跑 |
系统里没有unshadow命令 | 老版本John或极简安装 | 直接手工合并passwd和shadow,按user:hash格式整理 |
这种排查过程很有必要,因为很多人第一次就把时间浪费在跑错格式上,最后怨工具不给力,其实问题完全不在John身上。
5.2 两个容易忽略的细节:快照恢复与结果二次确认
第一个细节是断点恢复。John在执行中途如果被Ctrl-C中断,它会把进度信息存在~/.john/john.rec这样一个会话文件里。下次执行同一条命令,它会提示是否恢复,也可以用--restore参数强制恢复:
john --restore /tmp/accounts.txt这个功能在长周期任务里特别重要。我有一回跑一个大型数据库哈希,预计要十几个小时,中途服务器重启了,如果没有快照恢复机制,前面所有进度都得清零重新来。有了这个机制,重新开机后一条命令就恢复到断点,省了非常多时间。
第二个细节是破解结果的二次确认。John显示已经破解某个账号后,别急着写报告,建议先在目标机器上手工确认一遍,比如用su切换账号或者用SSH登录测试。因为John跑出来的“密码”有可能是一个相同哈希的等价字符串,极少数时候会因为哈希碰撞或编码问题出现偏差。虽然概率很小,但安全意识必须到位:凡是能登录验证的,都顺手验证一下,写进报告里的数据才经得起推敲。
6. 从检测到加固:报告与防线建设
6.1 把破解结果变成一份可落地的报告
弱口令检测的最终价值不是“跑出几个密码”,而是推动整改。所以报告必须清晰、可跟踪。我常用的报告表结构是:
| 主机IP/主机名 | 账号 | 哈希类型 | 原始口令 | 风险等级 | 整改建议 |
|---|---|---|---|---|---|
| 192.0.2.10 | webadmin | sha512crypt | Admin@123 | 高 | 立即改密,加入密码策略管理 |
| 192.0.2.21 | backup_svc | bcrypt | backup2024 | 中 | 改密,禁用SSH口令登录,改用密钥 |
报告里还应该写清楚检测范围、检测时间、使用的字典和规则参数、测试账号授权情况。这样运维同事拿到报告才知道具体怎么修、修哪里,而不是只看一句“你的系统有弱口令”。我通常会在报告末尾附上整改复核清单,把“改密时间”“验证方式”“复测结果”做成表格,方便跟踪闭环。
6.2 密码策略加固与账号管理
检测完弱口令,最重要的事情就是让强口令变成一种制度,而不是一次性的临时动作。在Linux系统上,可以从几个层面下手:一是启用密码复杂度策略,安装并配置libpam-pwquality(Debian系)或pam_pwhistory,强制口令长度、字符类别和轮换周期;二是禁止root直接SSH登录,修改/etc/ssh/sshd_config里的PermitRootLogin no;三是关闭不必要的系统账号,把/etc/shadow里不用的账号口令字段改成!或*,彻底禁用登录能力。
对关键服务器,建议进一步上多因素认证。用PAM模块配合动态令牌,就算口令被泄露,攻击者也很难直接登录。口令管理的核心思路是:让系统不再依赖于“用户自觉”,而是靠策略和技术手段兜底。我见过很多团队改完密码后三个月又出现同样的弱口令,就是因为只是单纯改密码,没有在PAM层做硬性约束。
6.3 常态化弱口令检测机制
John这种工具不应该一个月才想起来跑一次,我建议把弱口令检测放进常规安全巡检清单里,形成固定节奏。比如每个季度对核心资产做一轮字典和规则检测,检测前先用unshadow生成哈希快照,检测后把新增命中项自动录入工单,分配给对应的责任人整改。整改完成后,再重新拉取哈希做一次回归,确认弱口令已消失。
在规模较大的环境里,可以写个小脚本定期批量执行:一组机器自动收集shadow文件、加密传输到跳板机、跑John、把结果格式化推送。整个流程跑起来以后,人只需要盯异常和复核报告。这套机制的收益是持续性的,它不依赖某个人记性好,而是靠流程推动安全水位持续上升。等到下一次等保测评或者内部审计的时候,你手里已经有一堆漂亮的复测记录,说明弱口令治理是真在做,不是临时攒出来的材料。
最后聊几句实战体会
我刚开始用John的时候,也走过一些弯路,总以为字典越大越全,命中率就越高,后来才发现,在时间有限的情况下,规则加掩码的性价比远高于一部超大字典。另一个经验是,弱口令检测永远要和对端系统的风险承受能力挂钩:普通测试服务器可以放开跑,生产核心一定要先在副本上试,确保不会因为高负载影响业务。还有一点,检测工具永远只是发现问题的手段,真正拉开安全水平差距的,是发现问题之后能不能快速推动整改并形成长效机制。建议各位拿到第一份检测报告后,别急着把数据库删了,先顺手验证一两个结果,再推动改密和PAM策略,把这次检测变成一次小小的安全基建升级,一年之后回头看,整个系统的口令安全性绝对会明显不一样。