1. 弱口令问题为何值得专门做一次检测
做运维或者搞安全的同学应该都有这种感受:跑完一轮漏洞扫描、修完一堆CVE,总觉得服务器差不多稳了,但实际上真正容易被拿下的入口,往往不是某个0day,而是一个看起来不起眼的弱口令。攻击者不需要多高深的技术,只要拿到一个能登录SSH的账号,或者搞到一份含密码哈希的shadow文件,剩下的就是用工具慢慢跑字典,跑出来就直接进内网了。
我在实际排查过的一些失陷机器里发现,相当一部分入侵路径都长得差不多:先是某个服务暴露在公网,然后攻击者用常见用户名加弱密码组合尝试登录,成功之后提权、留后门、拉内网。整个过程根本用不着什么复杂漏洞利用,防不住的原因只有一个——口令太弱。
所以定期做一次弱口令自检,是Linux服务器安全里投入产出比非常高的动作。而说到弱口令检测工具,John the Ripper(通常简称John)是我用得最多、也最推荐的一个。它既可以拿来检测本机账号的密码强度,也可以用来分析各种应用服务的口令哈希,配合字典和规则,基本上能把弱口令问题暴露得比较彻底。
这篇文章我就把John从安装、原理到实战排查的完整过程拆开讲一遍,重点是告诉你怎么用它做一次靠谱的Linux弱口令审计,以及整个过程中哪些坑我最常踩、怎么绕过去。内容主要面向有一定Linux基础、想自己动手提升服务器安全水平的读者,如果你是刚接触安全的新手,跟着操作一遍也能理解个大概。
2. John the Ripper的工作机制:破解的本质是"猜"
在动手之前,有必要先把John的原理搞明白。很多人第一次用John,以为它有什么神奇的后门,能直接把密码反推出来。不是这样的。John做的事情本质上就一句话:把字典里的每一个候选密码用同样的算法哈希一遍,然后和你要破解的那个哈希做比对,一致就说明猜中了。
2.1 单向哈希决定了只能"正向试错"
Linux系统里的密码不是明文存储的,而是经过哈希处理之后保存在shadow文件里。哈希算法是单向的——从密码算出哈希很容易,但从哈希反推密码在计算上不可行。这就跟把鸡蛋煎熟了没法再变回生鸡蛋一个道理。
所以唯一的办法就是不停尝试:拿一个词,套用系统相同的哈希算法,得到一个哈希值,再和目标哈希比对。命中了,密码就出来了。这个过程俗称"跑字典",讲究的是效率——单位时间内能试多少个候选密码。
John的强项在于它针对几十种不同的哈希算法做了高度优化,跑起来比你自己写脚本一条条比对要快得多。而且它对CPU多线程支持得很好,机器性能够的话,速度能拉得很高。
2.2 三种破解模式:从省事到烧机
John内置了三种破解模式,我简单归纳一下:
- 字典模式(wordlist):用现成的字典文件逐条尝试。这是日常用得最多的,适合大部分弱口令场景。
- 单模式(single):拿用户名、邮箱前缀等个人信息衍生出候选密码来试。比如用户叫zhangsan,它就会试zhangsan123、zhangsan@2024这类组合。这个模式速度极快,经常能白捡便宜。
- 增量模式(incremental):穷举式的暴力破解,按字符集排列组合硬猜。这个最费时间,我一般只在密码哈希很少、字典也跑不动的情况下才用,而且会限制字符集和长度。
一句话总结:日常弱口令审计,先跑单模式,再跑字典,最后实在没辙了再上增量模式。这个顺序也是效率最高的。
2.3 密码哈希在系统里长什么样
既然要破解,先得知道目标哈希长什么样。Linux用户密码哈希存放在/etc/shadow,每一行对应一个用户,格式如下:
username:$6$salt$hashedpassword:19000:0:99999:7:::这里的$6$表示SHA-512哈希算法,$1$是MD5,$5$是SHA-256,$2y$是bcrypt。John可以通过哈希的前缀自动识别算法类型,不用你手动指定,这一点非常省心。
3. 环境准备与安装:三个来源,各有取舍
John的安装方式有好几种,不同场景下选择不一样。我覆盖三个最常见的来源,你按自己的环境选一个就行。
3.1 系统包管理器安装
在Debian/Ubuntu上,一条命令就能装:
sudo apt install john在CentOS/RHEL系上:
sudo yum install john这是最省事的方式,但是有个比较明显的缺点——系统源里的John版本通常偏老。对于哈希识别、多平台支持和一些新算法的支持会落后一些。如果只是跑跑普通的Linux账号密码,问题不大;如果要搞复杂场景,我建议用下面两个方式。
3.2 从官方Git仓库编译安装
Jumbo版(社区增强版)是功能最全的John发行版,支持超过四百种哈希格式,从数据库口令、Web应用到各类压缩包密码都能跑。从源码编译安装的步骤如下:
git clone https://github.com/openwall/john.git cd john/src ./configure make -j$(nproc)编译完成之后,可执行文件在../run/john。Jumbo版的优势非常明显:内置了大量常用字典和规则、支持GPU加速、还能直接处理各类加密文件。我做弱口令审计基本都用这个版本。
3.3 容器方式运行
如果你不想污染宿主机环境,跑个容器也挺方便:
docker run --rm -it -v /path/to/dict:/dict openwall/john:latest把字典目录挂载进去就行。不过容器方式的性能会稍微打折扣,而且GPU透传比较麻烦,追求极致速度的场景不推荐。
3.4 安装完先验证一次
不管用哪种方式装的,装完先跑一句看是否正常:
john --list=formats | grep -i sha512能看到类似sha512crypt的输出,说明John能识别这种哈希格式,环境基本没问题。
4. 单机实战:破解Linux本地账号密码哈希
这一节是核心实操。目标是将/etc/shadow里的密码哈希交给John,跑出其中的弱口令。
4.1 准备一份合法的测试文件
在做检测之前一定要搞清楚:你只能对你有权审计的系统进行弱口令检测。这里我给的是合法场景的做法——你对自己管理的服务器做安全自查,这是没问题的。
第一步,把passwd和shadow合并成John能直接识别的格式。传统做法是用unshadow工具:
unshadow /etc/passwd /etc/shadow > /tmp/myhashes.txt chmod 600 /tmp/myhashes.txt合并之后,文件里的每一行就是一条包含用户名、哈希和其余字段的记录。之所以要这两个文件,是因为shadow里只有用户名和哈希,而passwd提供了用户的UID、GID等信息,John在识别哈希归属和某些破解模式(比如单模式)时用得上。
4.2 基础字典破解
接着跑自带的字典试试:
john --wordlist=/usr/share/john/password.lst /tmp/myhashes.txt这里password.lst是John自带的常用弱口令字典,里面包含了几千条常见密码。跑的时候屏幕上会滚动显示破解进度,每猜中一个会打印一条。这个过程快则几秒,慢则看哈希算法和字典大小。
SHA-512的哈希速度大概是几十万次/秒(视CPU而定),几千条字典也就是一瞬间的事。所以第一轮下来基本能抓到一批显而易见的弱口令。
4.3 查看已破解的密码
跑完之后,要看结果就用--show,这个参数会列出所有已经猜中的账号和对应的明文密码:
john --show /tmp/myhashes.txt输出类似:
zhangsan:123456:1000:1000::: lisi:password:1001:1001::: 2 password hashes cracked, 3 left如果不想依赖John自己的pot文件(破解记录文件),也可以直接看~/.john/john.pot里的原始内容,但--show的可读性更好。
4.4 破解失败时怎么判断"不是弱口令"
每次跑完,总有几个账号跑不出来。这时候先别急着加大火力,看一眼没跑出来的哈希是什么算法。系统的哈希算法可以这样查:
sudo awk -F: '$2 ~ /^\$/{print $1, $2}' /etc/shadow | head -20$2y$(bcrypt)这类算法的计算速度非常慢,每秒只有几百次到几千次尝试,同样的字典跑起来要慢好几个数量级。如果你的系统用的是这类强哈希,跑不出结果反而是好事——说明口令强度不低。
提示:破解速度和哈希算法强相关。MD5和SHA-512属于快速哈希,每秒能跑几十万次以上;bcrypt和scrypt属于慢速哈希,每秒上限很低。这不是John不行,而是算法设计上就有意限制了暴力破解效率。
5. 破解模式与规则调优:从"能跑"到"跑得快"
John上手容易,但要用好得掌握几个关键技巧。这个部分是我平时用下来价值最高的内容。
5.1 单模式优先,经常白捡
很多新手不知道John有single模式,上来就直接跑大字典,反而错过了不少"送分题"。
john --single /tmp/myhashes.txtsingle模式会结合用户名生成变体密码。比如用户名叫test,它会尝试test、test123、test@123、Test123等等。由于这类口令在真实环境里出现频率非常高,这个模式往往能在几秒内破解掉一批账号。
我跑过一个小型服务器群的审计,18个账号里用single模式一个来回就出来了6个,密码全是用户名和简单数字的组合。这个比例相当震撼。
5.2 字典的正解:不是越大越好,而是要"对症"
关于字典,网上能下到几GB的大字典,看着很唬人,实际跑起来效率并不一定高。我的经验是分场景选:
- 通用弱口令检测:先用几万到几十万条的高质量常用密码集(比如John自带的password.lst、常见top1000/10000弱密码列表),足以覆盖绝大多数低垂果实。
- 针对特定人群:比如员工习惯用姓名拼音、生日、手机号组合的,需要自己按规则生成字典,而不是硬套通用字典。
- 大字典的正确用法:在快速哈希(如MD5、SHA-512)上跑几GB字典还算可行,但遇到bcrypt就非常亏,强烈不建议。
5.3 自定义规则:让一条字典长出几十条变体
这是John最强大的能力之一。所谓规则,就是对字典里的每条词做各种变形后再去试。比如把"admin"变成"Admin"、"admin123"、"admin!"、"admin2024"等。
John自带一批规则集,直接这样用:
john --wordlist=mywords.txt --rules=All /tmp/myhashes.txt--rules=All会套用全部规则,适合精力比较充足的场景。如果想控制强度,可以选择某个单一规则集:
john --list=rules看一下有哪些可用,再挑合适的。规则的本质是对字符串做替换、前后缀添加、大小写变化等操作。跑的时候试密码的总数会呈几十倍的放大——一条password可能衍生出几十条变体,覆盖率提高非常明显。
注意:规则越多,耗时越长。实际使用要掌握节奏——在小字典上开All规则没问题,在大字典上开All规则可能要多花几倍时间,先评估再动手。
5.4 限制增量模式的字符集和长度
当字典和规则都跑完、仍然有几个哈希解不开,而你确定那个账号的口令就是弱口令时,才考虑增量模式。直接跑全量增量很不理智,范围太大。更聪明的做法是限制长度和字符集:
john --incremental=Lowernum --min-length=6 --max-length=8 /tmp/myhashes.txtLowernum是内置的字符集,覆盖小写字母和数字。--min-length=6 --max-length=8则把候选密码限制在6到8位。这样计算量从天文数字降到了可接受的范围。
5.5 并行与后台运行
大的破解任务不要前台傻等,放到后台更妥当:
nohup john --session=crack1 --wordlist=bigdict.txt --rules=All /tmp/myhashes.txt > crack.log 2>&1 &--session是给本次会话起个名字,之后可以随时恢复:
john --restore=crack1就算机器重启了,会话状态也保存在~/.john/john.rec里,恢复之后能接着跑,已破解的结果不会丢失。这对长耗时任务来说极其重要。
6. 扩展场景:从SSH口令扩展到数据库、Web应用和压缩包
John的实用价值不只局限于Linux的系统账号。渗透测试和日常安全工作中,经常遇到以下几种场景,Jumbo版都能处理。这里挑三个最常见的举例。
6.1 MySQL数据库口令哈希
拿到MySQL用户表的哈希之后,存成如下格式:
目标用户:$mysql$*哈希值然后运行:
john --format=mysql-sha1 --wordlist=pass.txt hash.txt前提是哈希的算法要匹配。MySQL老版本常用mysql-sha1,新版本可能是mysql-native-password或sha256crypt。用john --list=formats | grep -i mysql查看支持的格式即可。
6.2 Web应用密码哈希(以PHP应用为例)
PHP应用大量使用bcrypt生成密码哈希。文件里已有的格式类似:
admin:$2y$10$xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx这种哈希的破解速度很慢,每秒只够试几千次,所以要靠好的字典来撬动,而不是硬暴力。命令:
john --format=bcrypt --wordlist=goodpass.txt target_hash.txt有一个实操小技巧:先单独确认哈希格式,再跑,避免John花大量时间在猜测格式上。不确定时可以加--format=auto让它自动识别,但慢一些。
6.3 压缩包密码的弱口令检测
企业内部经常有加密压缩包,密码过于简单同样是个隐患。John可以配合工具把压缩包的加密哈希提取出来。RAR的示例:
rar2john target.rar > rarhash.txt john --wordlist=pass.txt rarhash.txtZIP则是:
zip2john target.zip > ziphash.txt john --wordlist=pass.txt ziphash.txt这两个工具在Jumbo版的run目录下就有。需要注意:ZIP的加密算法比较弱,速度很快;RAR要看你选用的加密版本,RAR5的穷举速度明显更慢。另外特别注意,如果压缩包里文件比较多,提取哈希时要耐心等待,这不是卡住了,是在读文件结构。
6.4 各类场景的格式支持对照
| 场景 | 提取工具 | John格式参数 | 破解速度评估 | 适用性 |
|---|---|---|---|---|
| Linux系统账号(SHA-512) | unshadow | sha512crypt | 几十万次/秒 | 必测 |
| Linux系统账号(bcrypt) | unshadow | bcrypt | 几千次/秒 | 只上小字典 |
| MySQL老版本 | 手动提取 | mysql-sha1 | 很快 | 需数据库权限 |
| PHP应用(bcrypt) | 手动提取 | bcrypt | 很慢 | 需小字典+规则 |
| ZIP压缩包 | zip2john | ZIP | 很快 | 常测 |
| RAR压缩包 | rar2john | RAR | 看版本 | 酌情测 |
| SSH私钥 | ssh2john | SSH | 较快 | 偶测 |
7. 实战中的五个坑:我替你踩过了
用John做审计,看起来就是几条命令,但实际操作中有些细节很影响结果,也很影响心情。下面这几个坑是我在多次实战里遇到的,列出来给你提个醒。
7.1 哈希格式识别失败
有时候文件里哈希格式不规范,或者存在特殊前缀,John会报错"Unrecognized hash format"。处理方法:先用--list=formats确定格式,然后显式指定:
john --format=sha512crypt /tmp/myhashes.txt7.2 权限不足
读/etc/shadow需要root权限,unshadow也一样。如果提示Permission denied,就是当前用户没有执行权限。正确做法是sudo unshadow,而不是su之后忘了切目录,白白多绕一圈。
7.3 破解记录文件导致的"假失败"
John会把已破解的结果存到pot文件里,下次再跑同一个哈希时,即使看到--show里有,屏幕上也不太会输出新信息。如果你希望重新破解某个哈希(比如换新字典再试),要加:
john --pot=/dev/null --show ...或者干脆用一个新的pot文件路径,这样John会忽略之前的破解记录。
7.4 GPU加速的配置问题
Jumbo版支持OpenCL做GPU加速,但不是装好就能用。运行:
john --list=opencl-devices能看到设备列表才算配置好。不少时候驱动是对的,但缺了平台库,步骤就是先确认设备列表,再跑小样例测试。确认没问题再上大任务,不然白等几小时。
7.5 字典编码问题
Windows上编的字典文件经常是GBK编码,Linux下读取会出现乱码。简单处理:
iconv -f GBK -t UTF-8 olddict.txt > newdict.txt另外字典文件末尾最好有换行符,否则最后一条词可能被跳过。这个细节导致漏掉一个弱口令的案例我遇到过两次,虽然概率不大,但成本极低,顺手处理掉。
8. 自动化审计:让弱口令检测运维化
手动跑命令适合突击检查,但如果管理几十台服务器,每次都手动就太累了。我分享一个简单的自动化思路。
8.1 核心脚本
把合并哈希、跑字典、输出结果封装成一个脚本,加上黑白名单机制:
#!/bin/bash # weakpass_audit.sh HOSTNAME=$(hostname) OUTDIR=/var/log/weakpass mkdir -p $OUTDIR unshadow /etc/passwd /etc/shadow > $OUTDIR/hashes.txt 2>/dev/null /usr/local/bin/john --wordlist=/opt/dict/top10k.txt --format=sha512crypt \ $OUTDIR/hashes.txt > $OUTDIR/run.log 2>&1 /usr/local/bin/john --show --format=sha512crypt $OUTDIR/hashes.txt \ > $OUTDIR/result_$(date +%F).txt 2>&18.2 排除"不能动"的账号
有些服务账号(如nologin用户)的密码是锁定的,破解没有意义。在提取哈希时排除掉这些行:
unshadow /etc/passwd /etc/shadow \ | grep -v -E '^(root|daemon|bin|sys|sync|games|man|lp|mail|news|uucp|proxy|nobody|systemd-.*):' \ > $OUTDIR/hashes.txt我只保留了真实登录账号。不然每次结果里都有一堆服务账号,筛查起来很费劲。
8.3 定时任务与最小权限
把这个脚本加进crontab:
30 3 * * 1 root /opt/scripts/weakpass_audit.sh > /dev/null 2>&1每周一凌晨3点半跑一次,不打扰正常业务。收到报告后人工复核再处理,而不是全自动重置密码——自动化只负责发现,决策还是由人来做。
9. 防守视角:检测出弱口令之后,怎么加固才到位
跑出来一批弱口令,千万别只停下发个通告等大家改密码就完事了。很多管理员在这里收手,导致几周后又出现同样的短板。我的建议是按下面这个顺序操作。
9.1 立即处置
- 对被破解的账号立即执行密码过期:
chage -d 0 用户名,强制下次登录改密码。 - 如果怀疑已经被入侵,直接锁定账号:
usermod -L 用户名,清掉相关会话,再排查有没有后门。
9.2 从根源上减少弱口令出现
临时改完密码远远不够,要思考为什么会有弱口令。常见原因有几个:
- 管理员图省事,统一密码
- 入职培训没强调密码强度
- 新员工沿用旧密码
- 系统初始化时用了默认密码,后期没人管
对应策略不外乎三条:
- 配置密码复杂度策略,至少包含大小写字母、数字和特殊字符,长度不低于12位
- 启用密码过期周期(比如90天),缩短弱口令暴露窗口
- 有条件就上SSH密钥认证,禁掉密码登录
9.3 技术性强制
修改/etc/security/pwquality.conf可以控制密码复杂度:
minlen = 12 dcredit = -1 ucredit = -1 lcredit = -1 ocredit = -1这里四项分别要求数字、大写、小写、特殊字符至少各一位。搭配PAM配置,能挡住一批图省事的弱密码。
9.4 给管理员的额外提醒
即使改成复杂密码之后,也值得跑一遍新密码字典。很多"看起来复杂"的密码其实在攻击者的大字典里早就收录了。比如P@ssw0rd、Admin@123这类,复杂度规则全过,但仍然是高危口令。John这类工具的意义就在这儿——不是为难自己人,而是站在攻击者视角替自己找漏洞。
最终要记住一点:弱口令检测不是走过场,也不是吹嘘工具多强。它是把运维工作从"我以为很安全"变成"我已经验证过安全"的手段。每年的大型安全事件里,弱口令依然是高频突破口,这个事实本身就说明自检的必要性。
在真实操作中,我的习惯是每季度对全部生产服务器跑一轮John自检,平时只要有人事变动或服务器交付,也立刻补跑一次。把检测嵌进流程,比想起来才做要有用得多。建议你也从一台测试机开始跑起,把流程走通,再逐步铺开,整个过程半小时之内就能完成。