Linux 密码破解:原理、工具与实战经验全记录
先说一句大实话:我在Linux上踩过的第一个大坑,就是把自己的root密码忘了。当时满脑子想的不是重装系统,而是怎么把密码找回来。后来做运维、做安全测试,密码破解这件事就成了家常便饭——不是用来干坏事,而是用来恢复服务器访问、验证密码策略强度、做授权渗透测试。可以说,Linux密码破解是每个运维和安全工程师都绕不开的基本功。
这篇不整那些虚的,从底层存储原理、工具实操到忘记密码的恢复姿势,一步步拆给你看。内容包括:/etc/shadow里的密码到底是怎么存的、john和hashcat怎么用、字典该去哪弄、忘记密码有哪几种可靠的恢复方法、破解失败的常见原因怎么排查。适合想学Linux安全的小白,也适合被服务器密码折磨过的运维老哥参考。
1. 先搞清楚:Linux的密码到底藏在哪里
1.1 从/etc/passwd到/etc/shadow的演变
往前倒十几年,Linux系统里所有用户的密码哈希是直接存放在/etc/passwd文件里的,第二个字段就是那串加密后的字符串。这个文件所有用户都有权限读取,你可以执行cat /etc/passwd看看,每一行代表一个用户账户,格式大致如下:
root:x:0:0:root:/root:/bin/bash早期版本那个x的位置其实填的是一长串哈希,但这有个致命问题:任何人拿到/etc/passwd就能把哈希复制走,然后随便用字典跑离线破解。于是后来把密码哈希挪到了/etc/shadow,这个文件默认只有root能读,普通用户看不了。这就是为什么你现在看/etc/passwd,第二个字段永远是个x——真正的秘密已经转移了。
/etc/shadow里每行对应一个用户,一行由9个冒号分隔的字段组成:
username:$6$salt$hashedpassword:18000:0:99999:7:::- 第1个字段:用户名
- 第2个字段:加密后的密码哈希,格式为
$算法ID$盐值$哈希值 - 第3个字段:上次修改密码距1970年1月1日的天数
- 第4个字段:两次修改密码之间的最小天数
- 第5个字段:密码有效天数
- 第6个字段:密码过期前几天警告
- 第7个字段:密码过期后多少天禁用账户
- 第8个字段:账户失效日期
- 第9个字段:保留字段
第2个字段开头那个$数字是算法标识符,这个特别关键。$1$是MD5,$5$是SHA-256,$6$是SHA-512,$y$是较新的yescrypt算法,$2y$是bcrypt。跑哈希的时候,你告诉工具“这是SHA-512”,它就知道该用哪种模式去算,弄错了就算到天亮也出不来结果。
1.2 为什么说“破解”其实是在“猜”
很多人有个误解,以为破解密码是对哈希做逆运算,把密文还原成明文。这是不行的。哈希函数是单向的,设计出来的目的就是让你几乎不可能从输出反推输入。所以实际上的破解思路只有一个:拿一个候选明文,用同样的算法和盐值算一遍哈希,然后和目标的哈希比对,相同就说明猜中了。
这就像你去试一把锁,不是把锁芯拆开倒推钥匙,而是一把一把试钥匙。密码长度短、字符集小,试完所有组合的时间就短;密码里有大小写、数字、符号,组合空间暴涨,破解时间就会指数级上升。理解这个逻辑,你就能明白为什么“密码强度”在哈希面前如此重要,也能明白为什么字典比纯暴力更实用——大多数人的密码都是常用单词、键盘序列、日期变体,字典里大概率都有。
盐值(salt)这个东西也要重点说说。它是随机生成的字符串,会拼进明文一起参与哈希计算。盐值每个用户都不同,所以就算两个人密码都是123456,在shadow文件里看到的哈希串也是不一样的。盐值的作用主要是防彩虹表——预先算好海量密码和哈希对应关系的巨型查表,没有盐的话,查表一秒就能“破解”所有用户的弱密码。
2. 拿到哈希是第一步:读取shadow的合法路径与提权常识
2.1 权限与读取方式
破解密码的第一步永远是需要拿到密码哈希。在授权环境里,你确实可以sudo cat /etc/shadow直接看,但更多时候你接管的是一个被遗忘的服务器或测试靶机,手里只有一个普通用户的Shell权限,那就得想办法“提升权限”到root才能读shadow。这里强调一遍:所有操作必须在你自己拥有或获得明确授权的环境中进行,未经授权查看他人系统密码哈希属于违法行为,这点没有任何讨论余地。
在合法测试中,常见的提权手段包括:检查当前用户是否有sudo权限(sudo -l)、寻找有SUID位的可执行文件(find / -perm -4000)、查看是否有脆弱的服务以root运行、查找web目录下的配置文件里是否写了数据库密码或密钥等。这些都属于常规权限提升思路,真实渗透测试报告里都会有。
只要拿到了root权限,执行这两条命令就够了:
cat /etc/passwd cat /etc/shadow2.2 unshadow:把两个文件合并成john能吃的格式
手动从两个文件里拼出哈希很麻烦,john工具包里自带一个叫unshadow的小工具,能把passwd和shadow合并成统一的破解输入格式。
unshadow /etc/passwd /etc/shadow > /tmp/hashes.txt cat /tmp/hashes.txt合并后的每一行会是这样:
root:$6$abcdefg$hashvalue:0:0:root:/root:/bin/bashjohn直接识别这个格式,省去自己拼接的功夫。在Kali Linux里unshadow是自带的,其他发行版装了john也会带。如果你用的是hashcat,那就不需要passwd,直接从shadow里抠出用户名和哈希部分,填到一个文本文件里就行,因为hashcat的目标只是哈希本身,不关心账户的shell和家目录信息。
这里提醒一下:保存哈希文件的目录要注意权限,别把它放到一个任何用户都能读的web目录里。我见过有人把/tmp/root.txt放了一周没管,结果被别的管理员看到,闹了个尴尬。
2.3 哈希的本地离线破解 vs 在线爆破
拿到哈希后,破解分两种路线:离线破解和在线爆破。离线破解是指把哈希复制到本地机器,用自己的CPU/GPU跑字典或暴力枚举,速度快、不依赖目标机器负载,这也是主流。在线爆破是登录SSH、Web后台时反复尝试密码,每次都触发一次完整认证流程,速度慢、容易触发锁号或登录日志告警,还会留下大量痕迹。熟练的渗透工程师都优先抓哈希做离线破解,很少去做在线爆破——效率太低,风险太高。
3. 核心实操:用john和hashcat完成一次完整破解
3.1 工具安装与基本用法
john the ripper是老牌CPU破解工具,兼容性好,对新手的提示也比hashcat友好。在Kali里它默认就有,Ubuntu/Debian系用:
sudo apt install john -y拿到哈希文件后,最简用法只需要一条命令:
john /tmp/hashes.txtjohn会自己识别哈希类型,然后自动加载默认字典开始跑。默认字典不大,很快就能跑完,如果没跑出来,可以用指定字典重新跑:
john --wordlist=/usr/share/wordlists/rockyou.txt /tmp/hashes.txt注意rockyou.txt这个字典在Kali里是个压缩包,需要先解压:
sudo tar -zxvf /usr/share/wordlists/rockyou.txt.tar.gz -C /usr/share/wordlists/跑完之后,用john --show /tmp/hashes.txt就能看到已经破解出来的账户密码。我一开始不知道有这个命令,以为跑完就没了,其实破解结果都会缓存到这个文件里。
3.2 用hashcat跑GPU破解:效率不是一个量级
hashcat是GPU破解工具,利用显卡的并行计算能力,速度能甩开CPU几百倍。比如SHA-512哈希,用CPU单核算大概每秒几百到几千次,用一张中高端显卡能跑到每秒几千万甚至上亿次。这个差距在日常使用中非常明显。
hashcat的使用要先指定哈希类型和攻击模式。Linux的SHA-512对应hashcat的-m 1800,字典攻击对应-a 0,基本命令是:
hashcat -m 1800 -a 0 shadow.txt /usr/share/wordlists/rockyou.txt如果你不确定哈希类型,可以先跑一个--identify或参考hashcat example hashes页面。判断错了会出两种情况:要么报错说格式不匹配,要么跑出来一堆乱七八糟的结果。我在刚用hashcat的时候,把MD5的shadow哈希当成SHA-512跑,跑了两天一无所获,后来用hashcat --identify一看才发现类型搞错了,白瞎了一堆电费。
3.3 掩码攻击:没有字典时的高效打法
字典跑不出结果,不代表没有希望。很多人设密码是有“规律”的,比如名字首字母+生日、键盘相邻键、常见词尾加数字。hashcat的掩码攻击就是针对这类规律设计的。
掩码规则:
?l表示小写字母?u表示大写字母?d表示数字?s表示特殊符号?a表示所有可打印字符
比如你想猜一个“8位全数字”的密码,命令是:
hashcat -m 1800 -a 3 shadow.txt '?d?d?d?d?d?d?d?d'想猜“6位小写字母+4位数字”的组合,可以写:
hashcat -m 1800 -a 3 shadow.txt '?l?l?l?l?l?l?d?d?d?d'掩码攻击的核心是目标明确、字符集小。位数超过10位且字符集又大的话,组合数会爆炸,不建议硬上。现实场景里最常见的弱密码其实就是admin@123、test123456、password123这类组合,基本都在rockyou和类似的公开字典里。
3.4 规则变形:让一份字典变成几亿条
高级玩法是“规则”。规则是对字典里每个词做变形——大小写转换、尾部加数字、前后拼接、字母替换(比如把o换成0、e换成3)、重复词尾等。john默认带了很多规则集,使用方式:
john --wordlist=rockyou.txt --rules=All /tmp/hashes.txthashcat用同样的思路,但要用-r指定规则文件,Kali里规则文件放在/usr/share/hashcat/rules/,最常用的是best64.rule和rockyou-30000.rule:
hashcat -m 1800 -a 0 shadow.txt rockyou.txt -r /usr/share/hashcat/rules/best64.rule规则变形的威力在于,一份一万词的字典,经过规则扩充后可以变成上百万条有效候选。比如用户拿admin当基础词,变形成Admin、admin1、Admin123、admin@123、aadmin这种,规则的覆盖能力远超原始字典。
3.5 字典的获取与自制:Python脚本快速生成
字典是破解的弹药,没有好字典就等于空枪。公开字典有很多:Kali自带的rockyou.txt是最常用的,还有SecLists项目里的Passwords目录、crackstation的百万级密码表等。GitHub上都有现成仓库,下载后丢进/usr/share/wordlists/即可。
实际测试中我经常发现目标公司的密码规律和公开字典对不上,这时候就需要定制字典。用Python写个简单脚本,按业务规律生成候选密码,比如“公司名缩写+年份”、“拼音+特殊符号”的组合。之前我在授权渗透测试中,通过公开信息收集到目标系统的默认密码规则,写了一个两百行的生成脚本,最终成功恢复了测试账号的密码——这种方法比盲目跑rockyou高效得多。
Python脚本生成自定义字典核心逻辑示例:
import itertools base_words = ['admin', 'test', 'ops', 'dev'] years = ['2021', '2022', '2023', '2024'] symbols = ['!', '@', '#', '$'] with open('custom_dict.txt', 'w', encoding='utf-8') as f: for base in base_words: for year in years: for sym in symbols: f.write(f"{base}{year}{sym}\n") f.write(f"{base.capitalize()}{year}{sym}\n") f.write(f"{base}{sym}{year}\n")写完跑一下,几秒钟就能生成几百条候选。这种定制字典在真实场景里很实用,远好过大海捞针式的纯暴力。
4. 忘记密码的正确恢复姿势:几种实用方案
4.1 单用户模式重置root密码
破解哈希是一回事,但很多运维朋友的刚需其实是“我忘了自己服务器的root密码”,这时候不需要破解,直接重置就行。最经典的办法是开机进单用户模式,以root身份直接改密码。
传统SysV init时代的做法是开机时在GRUB菜单按e编辑内核启动项,在linux那一行末尾加一个single,然后按Ctrl+x启动,进入单用户Shell后直接:
passwd root重启即可。但现代系统用的是systemd,单用户模式未必直接给root Shell,通常需要在linux行末尾加上:
systemd.unit=rescue.target启动后如果是只读环境,先重新挂载根文件系统:
mount -o remount,rw / passwd root4.2 用init=/bin/bash绕过并修改密码
如果上面方法不管用,还有一招更直接的:在内核启动参数里指定一个Shell作为init进程。GRUB编辑界面里,把linux那行末尾改为:
init=/bin/bash系统启动后会直接进入一个root权限的bash,而不挂载任何服务。但此时根文件系统是只读的,所以要先重新挂载:
mount -o remount,rw / passwd root如果用户密码需要加盐策略或者要修改普通用户密码,同样用passwd 用户名即可。改完执行exec /sbin/init或者直接重启就生效了。
4.3 rd.break方式:应对加密根文件系统
现在很多系统使用了全盘加密(LUKS),单纯改启动参数会卡在解锁加密卷那一步。这时候可以改用rd.break参数:
rd.break启动后系统会进入一个早期用户空间的Shell,此时根文件系统被挂载在/sysroot(或/sysroot/)下面,并且可能是只读的。先重新挂载并chroot进去:
mount -o remount,rw /sysroot chroot /sysroot passwd root修改密码后执行exit退出chroot,再exit退出initramfs的Shell,系统会继续启动到登录界面,用新密码就能进去了。rd.break的好处是它绕过了磁盘解锁阶段,对LUKS加密系统的密码恢复特别有效,前提是你物理能接触到机器且BIOS/GRUB没有被额外加密保护。
4.4 修改shadow文件直接替换哈希
最后一种办法是编辑shadow文件本身,用你知道密码的另一个用户哈希去覆盖root的哈希。步骤稍微繁琐,但思路最透明。
首先用上面任一种方式拿到root Shell,然后把root的密码换成你自己的:
mount -o remount,rw / cat /etc/shadow复制一个你能登录的用户的哈希字段,替换到root那一行。更简单的方法是直接用openssl生成一个新的哈希:
openssl passwd -6 -salt mysalt '新密码'把输出的一整串粘贴到/etc/shadow里root用户的第二个字段,重启后用新密码登录。这个方法还有个妙用:如果目标系统不允许root直接SSH登录(PermitRootLogin no),你也可以用同样的方式重置一个普通用户的密码,再通过su切换。
4.5 恢复后千万别忽略的安全检查
密码恢复成功之后,还有几件事要立刻做。首先是确认有没有被别有用心的人登录过,执行last和journalctl -u sshd翻一下登录日志,看有没有陌生IP。其次是检查/etc/shadow的权限是否正常,正常应该只有root能读能写:
ls -l /etc/shadow如果权限变成了-rw-r--r--,说明系统配置有问题,任何用户都能拿走哈希去离线破解了。恢复服务器访问之后也应该顺手做一遍history检查,看看有没有可疑命令残留。曾有一次我恢复了被遗忘密码的测试服务器,结果发现上一次管理员留下的后门脚本还躺在/tmp里,要不是翻了一下cron任务根本发现不了。
5. 破解失败的排查与提速技巧实测
5.1 最常踩的四个坑
破解跑不出结果,90%不是密码太强,而是操作姿势不对。我整理了一下自己踩过和帮别人排查过的常见问题:
| 问题 | 症状 | 原因 | 解决办法 |
|---|---|---|---|
| 哈希类型识别错误 | john和hashcat跑出来全乱码 | 没有指定算法类型 | 用john --show=types或hashcat --identify确认 |
| 字典文件格式不对 | 进度条跑得飞快但结果为零 | 字典里有空格、CRLF或空行 | 用dos2unix处理,或tr -d '\r'清理 |
| shadow文件带特殊字符 | 报错提示“No password hashes loaded” | 复制时把反斜杠或换行丢了 | 用unshadow重新生成,别手动复制黏贴 |
| 规则太过激进 | 运行时间过长,内存暴涨 | 规则集过大导致候选数亿级 | 先用小字典验证再上大规则,或限制长度 |
5.2 拆解一个实际案例:从报错到出结果的完整流程
有一回我帮朋友恢复一台Debian旧服务器的root密码,从已知线索推断密码可能是“公司英文名+年份”。我先从shadow里把hash提取出来,用hashcat --identify确认是$y$开头的yescrypt算法,hashcat里对应模式组是-m 23500(对于独立密码文件)或对shadow整行用-m 23500也可以,具体取决于格式。
接着我写了个Python脚本,用公司名和几个可能的年份、特殊符号做成字典。命令如下:
hashcat -m 23500 -a 0 shadow_aut.txt custom_dict.txt第一次跑的时候报错说“line-length exception”,检查了一下发现shadow文件是从Windows下复制过来的,行尾带着^M字符。我用sed -i 's/\r$//' shadow_aut.txt清理之后重新跑,几十秒就出了结果——密码就是CompanyName@2021。整个过程几分钟,比想象中顺利。
5.3 提速技巧:预算有限时怎么选
破解的物理速度由硬件决定,但同样硬件也有优化的空间。如果你手里有NVIDIA显卡,hashcat会默认使用CUDA,速度是CPU的几百倍。如果你的机器只有CPU,那就用john的--fork开多进程,或让hashcat使用OpenCL跑CPU模式(虽然慢但能榨干多核)。
另外还有一点很多人忽略:可以先跑一遍最小字符集和掩码,比如先跑纯数字的10位以内组合,再上字典。因为现实中一部分密码就是纯数字,这个组合用GPU几分钟就能扫完,没必要一上来就开大字典。
5.4 给密码策略的建议:怎么让破解者看到你就emo
反过来从防御角度看,密码破解的难度主要取决于密码熵。实测下来,纯数字8位密码,GPU破解最多几个小时;小写字母10位密码,可能要几天;大小写+数字+符号12位密码,理论上要算到宇宙热寂。对企业内部系统,强制12位以上混合密码,加上密码过期策略,就已经能挡住绝大多数离线破解了。
还有关键的一点:不要在不同的服务器上复用同一个密码。我在授权测试中经常发现,一台测试机上的密码和线上生产机相同,一旦测试机的哈希泄露,等于线上机器也裸奔了。密码管理器是解决这个问题的好东西,成本比改密码策略低多了。
6. 写在最后的几点大实话
我做了几年运维和安全,密码破解从最早的John跑一天出不来几个,到现在GPU几分钟扫完一个大字典,工具的进步肉眼可见。但有一点从来不变:破解只是手段,不是目的。真正专业的工程师会在破解前先想清楚任务边界——这台机器是不是我的?有没有授权?破解成功之后要怎么处理?这些问题的答案比任何一条命令都重要。
我自己在学习和测试流程中,习惯专门搭一台虚拟机做靶机演练,用的工具就是Kali Linux自带的整套环境,这样既能完全复现实际场景,又不会碰到真实系统。你在实验时也建议这么干,虚拟机的快照功能还能让你随时回到初始状态反复练习。
最后再分享一个操作小习惯:无论给/etc/shadow做了什么改动,动手前先备份一份原文件,命令就一条:
cp /etc/shadow /etc/shadow.bak.$(date +%F)改坏了能一键还原,比事后后悔强一百倍。这套流程跑熟之后,以后再遇到密码问题就不再是心烦意乱,而是心里有底——不管是帮别人找回密码还是加固自己系统,手上有工具、脑中有思路,就没什么好慌的。