SSH私钥密码短语破解全攻略:从ssh2john到Hashcat实战
学习OSCP系列翻到这一篇正好把密码攻击里最容易被低估的私钥破解环节做个完整还原。这期的核心研究对象是SSH私钥的密码短语——说白了就是你在目标机器上弄到一把id_rsa文件时它不只是带一把锁你还得先撞开上面那层passphrase才能把它真正当作登录工具来用。备考OSCP或者平时做渗透测试的朋友经常是拿到私钥就急着去连结果被终端问Enter passphrase时一脸懵。这个场景在横向移动阶段出现频率极高也是我见过卡人最久的地方之一。这篇不是空讲原理。我会把从私钥识别、格式判断、ssh2john转换、John和Hashcat双线爆破到最终解锁并成功登录的完整链路都过一遍同时把我自己在测试环境里踩过的坑、不同私钥格式对爆破速度的影响、以及那些容易让人原地心态爆炸的报错一起整理出来。适合正在攻武器阶段的朋友收藏也适合做Red Team但还没系统处理过私钥加密这块的同行拿来做操作清单。1. 为什么攻防两端都要盯住SSH私钥的密码短语1.1 私钥不等于入场券passphrase到底在保护什么很多人对SSH私钥加密有一个误解以为私钥文件本身就是明文的钥匙。实际上如果你在创建密钥对时设置了密码短语passphraseOpenSSH会用这个短语派生出的密钥去加密整个私钥文件内容。也就是说你看到的-----BEGIN OPENSSH PRIVATE KEY-----往下那一大坨base64文本真正私钥材料的密文版本没有短语的人即使拿在手里也读不出来。我做过一个简单的类比私钥本身是一把钥匙放在一个保险柜里密码短语是保险柜的密码。想用钥匙开门得先知道保险柜密码把钥匙取出来。在OSCP的考点里这正是出题人喜欢设关卡的地方——他们把一个可以畅通无阻的私钥放在某处让考生发现但同时又给它上了锁逼着你走完提取→转换→爆破→使用这条完整的密码攻击链路。这套链路熟练之后在真实项目中遇到类似情况也能条件反射地处理。另一个值得了解的点是加密算法本身的差异。OpenSSH从7.8版本开始默认生成的私钥是OpenSSH格式内部默认采用bcrypt作为KDF迭代次数设计得比较高目的就是为了拖慢离线暴力破解的速度。而老式的PEM格式私钥比如-----BEGIN RSA PRIVATE KEY-----开头的那种用的是相对更弱的KDF同样的字典和同样的机器爆破速度往往能快上一个数量级。这个区别直接决定了你是跑几分钟还是跑几个小时下文我会专门展开。1.2 从OSCP机子的角度看私钥出现的典型位置参加OSCP模拟或实战时私钥文件通常不会光明正大地躺在桌面上但出现位置也相当有规律。最常见的是某个用户的home目录下/home/user/.ssh/id_rsa这个场景经常出现在你成功提权到某个普通用户之后想用它的身份横向移动到另一台机器。也有的是藏在Web目录的备份文件里、配置文件备份中甚至通过目录遍历、任意文件读取之类漏洞直接拉下来的/root/.ssh/id_rsa。我个人的查找习惯是拿到一个低权限Shell后先看当前用户和其他用户的home目录然后翻.bash_history和authorized_keys。.bash_history里可能有SSH连接命令能告诉你这台机器曾经连过哪台主机、用的是哪个用户名而id_rsa的出现往往对应着一个横向移动通道。需要注意的是如果别人想让你发现私钥它通常就在台面上但周围会有虚假路径或者权限陷阱。比如私钥权限是644这在靶机里很常见因为靶机能让你读取但在你实际使用时又会因为权限过宽而被SSH客户端拒绝——这就是一个经典的考察点。2. 拿到私钥之后的第一步识别格式与验证加密状态2.1 从文件头快速区分OpenSSH格式与PEM格式拿到私钥文件第一件事不是立刻扔给爆破工具而是先看清它的格式。很多人上来就用ssh-keygen -y -f id_rsa结果报错然后就开始怀疑人生。其实先看一眼文件头你就能判断后面的路怎么走。私钥文件常见三种开头-----BEGIN OPENSSH PRIVATE KEY-----OpenSSH新格式Linux新版本默认KDF多为bcrypt-----BEGIN RSA PRIVATE KEY-----、-----BEGIN DSA PRIVATE KEY-----经典的PEM格式-----BEGIN EC PRIVATE KEY-----椭圆曲线私钥也是PEM风格在终端里可以直接执行file id_rsa head -n 1 id_rsa这两条命令不会修改文件内容只是查看元信息。我用的时候会再执行一次ls -l id_rsa看权限。这里要说一个非常重要的坑SSH客户端要求私钥权限必须是600或更严格否则就算密码短语正确、公钥匹配它也会直接拒绝使用这把私钥。靶机里拿到的私钥经常是644甚至更宽松你在本机使用前必须先chmod 600 id_rsa。如果想快速判断这个私钥是否设置了密码短语可以试着用空密码读取公钥ssh-keygen -y -f id_rsa -P 如果输出一串ssh-ed25519 AAAA...或ssh-rsa AAAA...说明这个私钥根本没有密码短语保护你直接就能用如果提示需要密码那就进入下一步流程。这一步大概花不到五秒但能帮你避免白跑一轮爆破。2.2 密码短语验证用ssh-keygen当试锁器在爆破过程中我们需要不断验证某个候选密码是不是真的正确。这时候不必每次都把私钥克隆到本机然后用ssh -i去连接目标服务器——那样太慢了而且容易在目标机器上留下没必要的日志。更可靠的方式是使用ssh-keygen -y -f这个组合来充当试锁器ssh-keygen -y -f id_rsa -P candidate_password密码短语正确时命令会输出对应的公钥错误时则返回类似load failed或incorrect passphrase的提示。这个操作只在本机完成不会触发远程的任何登录。我在实际测试中习惯写一个小循环脚本把Wordlist里的每一个密码都通过这种方式跑一遍虽然效率不如John和Hashcat但在网络连接受限或者对方有登录监控的情况下这是一个非常隐蔽的验证手段。顺便提醒一句-y参数不会修改私钥文件本身它只是读取并导出公钥。不要害怕执行它会破坏原始文件。我见过有朋友担心这条命令生成新密钥覆盖掉旧文件其实是多虑了。真正的危险操作反而是改写私钥的ssh-keygen -p修改密码短语在没有正确旧密码的情况下不要乱试否则修改失败还好说万一误操作把密钥改错就得不偿失了。3. 转换Hash与爆破John与Hashcat双线路线3.1 用ssh2john把私钥变成可破解的HashJohn the Ripper和Hashcat都不能直接拿base64私钥文本去爆破需要先把私钥转换成它们认识的Hash格式。这里主角是ssh2john.py脚本。在Kali Linux里它的路径一般是python /usr/share/john/ssh2john.py id_rsa id_rsa.hash执行完以后用cat id_rsa.hash看一眼生成的Hash内容大致长这样id_rsa:$sshng$1$16$...这个$sshng$开头的新格式Hash有两个用途John直接读取Hashcat则用-m 22921处理。而老式PEM私钥生成的Hash在Hashcat里的对应模式可能是-m 22911。我在刚接触这个工具时犯过一个错以为所有SSH私钥Hash都通用结果Hashcat报Token length exception后来才发现新老格式的mode完全不同。建议转换完后先看一下contents再根据私钥头部信息决定后续用哪个mode。有一个细节值得注意ssh2john.py如果在转换过程中报错比如提示base64解码失败或不能识别私钥格式通常意味着你拿到的不完全是标准私钥文件也可能是包了一层别的加密内容或者是文件在传输过程中被改动过。碰到这种情况先检查完整性用wc -c对比文件大小必要时用xxd看一眼文件头部是否有异常填充。长时间陷入爆破工具报错而不检查源文件是我整理这个项目时发现最常见的拖节奏行为。3.2 John the Ripper的字典爆破实操John的优点在于开箱即用对CPU多线程的支持好而且很多Kali中的Wordlist直接放在/usr/share/wordlists/下。核心爆破命令就一句话john --wordlist/usr/share/wordlists/rockyou.txt id_rsa.hash跑完后查看结果john --show id_rsa.hash如果Rockyou这种大字典没跑出来我会再做两件小事一是确认John确实识别了Hash列表有时候因为Hash文件里带了文件名前缀需要指定格式john --formatssh --wordlist/usr/share/wordlists/rockyou.txt id_rsa.hash二是考虑是否要加规则。John自带了一堆mutation规则但规则会显著增加组合数量跑起来更慢。我的经验是先用纯字典精确匹配因为OSCP类靶机设置的密码短语绝大多数是字典中的原词纯字典跑完没结果再考虑加--rulesbest64或--rulesall跑一轮。每个环节要有目的性不要一开始就把规则拉满否则满屏进度条一天都跑不完。关于John的速度这里必须给个心理预期对于新OpenSSH格式私钥其bcrypt KDF设计上就很慢CPU跑单个Hash大概是每秒几百次到几千次具体取决于主机。相比之下老PEM格式可能是它的几十倍。如果跑了几分钟仍然没有进度变化不用慌张这是正常的你需要观察的是John输出的处理速率到底有没有在实际推进以及是否可以用Hashcat利用GPU进一步加速。3.3 用Hashcat走GPU加速爆破并踩坑提醒如果当前设备有NVIDIA或AMD独立显卡Hashcat的速度优势就能体现出来尤其是对OpenSSH新格式的bcrypt KDF。基础命令如下hashcat -m 22921 id_rsa.hash /usr/share/wordlists/rockyou.txt -o cracked.txt这里的-o参数指定输出文件爆破成功后可以拿着结果直接去解锁私钥。有一点非常重要Hashcat对Hash文件内容非常敏感如果id_rsa.hash内容是id_rsa:$sshng$...需要把id_rsa:这一段文件名前缀去掉或者用--username参数告诉Hashcat忽略。否则多半会看到Token length exception或者Separator unmatched这类提示。老PEM格式则用hashcat -m 22911 id_rsa.hash /usr/share/wordlists/rockyou.txt还有一类场景是私钥里面包含的是椭圆曲线密钥EC此时Hashcat也会提示不同的Cost参数和威布尔值。我在自己的GPU上实测同一台机器跑OpenSSH新格式的Hash速度通常只有PEM的几十分之一。所以如果你能确认是PEM老格式直接优先用22911速度体验非常爽。另外如果运行过程中Hashcat提示Slow Hash相关警告不要紧张那是它在提示当前KDF计算开销较高属于正常现象。在无法使用GPU的环境下我通常就把Hashcat放一边回退到John加多线程参数例如john --fork8 --wordlist/usr/share/wordlists/rockyou.txt id_rsa.hash这里的--fork8表示开8个进程并行处理合理利用CPU核心。跑爆破这件事思路比工具重要有时你只需要换个工具效率就能天差地别。4. 实战操练一个完整的模板机横向场景4.1 临时搭建私钥横向移动的实验环境为了让流程更直观我自己用两台Docker容器模拟过一个比较标准的横向移动场景。容器A扮演已入侵的机器里面Web服务的备份目录放着一把用于连接容器B的私钥容器B开启SSH服务并把对应公钥放进目标用户的authorized_keys。我用的搭建步骤如下# 容器B目标主机 docker run -d --name target --network net_test ubuntu:22.04 /bin/bash -c apt update apt install -y openssh-server service ssh start sleep infinity然后在容器B里创建用户deploy把公钥写进/home/deploy/.ssh/authorized_keys同时把对应私钥复制到容器A的/var/www/html/backup/id_rsa并故意把权限改成644。这样整个攻击路径就是从容器A的Web目录下载备份文件拿到一张需要密码短语的私钥然后试图用它横向连接容器B。这个环境我跑过好几次非常适合练手。之所以强调权限改成644是因为很多初学者在拿到私钥后直接丢进Kali去连遇到Permissions too open报错完全摸不着头脑。实际上靶机给你的文件大概率就是这种宽松权限你需要在攻击机上执行chmod 600 id_rsa来“修复”它。这一步会出现在后续的连接过程中提前习惯了就不会慌。4.2 从拿到私钥到成功登录的全过程回放我把一次完整实验的过程按顺序贴一下每一步都是实际跑过的第一步从容器A的Web目录下载私钥到Kaliwget http://target-A/backup/id_rsa chmod 600 id_rsa第二步确认私钥类型head -n 1 id_rsa # 输出: -----BEGIN OPENSSH PRIVATE KEY-----第三步用ssh2john转换Hashpython /usr/share/john/ssh2john.py id_rsa id_rsa.hash cat id_rsa.hash第四步John爆破john --wordlist/usr/share/wordlists/rockyou.txt id_rsa.hash john --show id_rsa.hash爆破完成后John会直接列出密码短语明文。我跑的这次大概等了十几分钟原因就是这个OpenSSH新格式的bcrypt KDF确实慢但最终还是命中了rockyou字典里一个词。第五步验证密码短语ssh-keygen -y -f id_rsa -P CrackedPassphrase看到公钥输出说明密码短语正确。第六步横向连接容器Bssh -i id_rsa deploytarget-B连接时如果提示输入密码短语输入刚爆破出来的短语即可如果一切顺利会直接进入deploytarget的Shell。这一步顺利完成后整个“提取→转换→爆破→验证→登录”的横向移动闭环就走通了。整个过程看起来不难但每一步都有对应的坑权限不对、Hash格式不对、Hashcat mode选错、密码短语验证命令用反等任何一个点都会把人卡住。5. 常见问题与避坑速查5.1 高频报错与解决办法在你真正操作的时候以下报错出现频率最高我根据自己踩过的坑整理成了速查表现象原因解决办法Permissions too open私钥文件权限过于宽松执行chmod 600 id_rsaload failed/incorrect passphrase密码短语错误或私钥受损用字典继续爆破或检查私钥文件完整性Hashcat报Token length exceptionHash文件包含文件名前缀或格式不对去掉id_rsa:前缀确认mode是22921还是22911John报No password hashes loaded对Hash格式识别失败指定--formatssh或重新用ssh2john转换SSH连接提示Permission denied (publickey)用户名不对或公钥未加入authorized_keys确认目标用户检查公钥是否正确安装ssh-keygen -y -f报错说invalid format文件并非合法私钥可能被篡改用file和xxd检查私钥结构爆破速度远低于预期OpenSSH新格式使用bcrypt KDF换GPU跑Hashcat或换PEM格式思路重新评估这些坑本身并不难解决难的是它们往往组合出现。比如拿到一把权限为644的OpenSSH新格式私钥用错Hashcat mode跑不出来好不容易跑出来登录时又因为权限问题失败三个报错叠在一起非常容易让人怀疑自己是不是拿错了文件。遇到这种情况我的排查顺序固定是先ls -l查权限再head查格式再ssh-keygen -y -f -P 查是否加密最终才进入爆破环节。每一步都在缩小问题范围而不是瞎改参数。5.2 优化破解效率的几个小技巧提高私钥密码短语破解效率我总结出几个小技巧第一先用空密码和常见弱口令做快速验证。OSCP练习环境中偶尔会出现私钥根本没有密码短语保护的情况这时候直接就能用省去大量爆破时间。验证命令就是我前面提到的ssh-keygen -y -f id_rsa -P 再配合几个常见密码如password、123456、root跑一遍几乎不花时间。第二在跑大字典之前先做个有依据的猜测。比如私钥所在地是deploy用户的home目录靶机的命名习惯可能把密码短语设置为s3cr3t、deploy123这类与用户相关联的词。我从不盲目从头跑而是先切一个top密码小字典包括top12000此类的常见密码集合看一下能否在几分钟内命中。第三如果确认是OpenSSH新格式且字典跑不通不要死磕到底。这个Hash的KDF是bcrypt计算开销非常高继续硬刚几百小时也不现实。我的建议是转向其他攻击面翻看目标机器上的进程环境变量、/etc/motd、Web服务日志甚至检查authorized_keys文件里有没有多条公钥记录有时候目标用户同时开放了多个访问方式没必要一条路走到黑。第四破解出来的密码短语要闭环验证。我用ssh-keygen -y -f id_rsa -P xxx验证通过后一定会再用ssh -i id_rsa usertarget实际登录一次确认这个私钥在目标机上的可用性。这个习惯帮我避免过多次“密码对了但用户不对、IP不对”的尴尬场景。写在最后的一点个人体会做完这个实验我最大的感受是私钥和密码短语在渗透测试里必须当作两个独立概念看待。拿到私钥只代表你取得了进入下一步的候选凭证真正的门槛是passphrase这道保险锁。OSCP考点的表面目的是让你会用工具实际上是在训练你把整条攻击链拆成多个独立节点逐一破解的思维方式。当你从一台机器上拿到id_rsa却无法登录时按这篇的顺序一步步来识别格式、查权限、转换Hash、双线爆破、验证密码、登录。如果字典跑不通也别硬耗退出来看看还有没有别的攻击面。这个领域最值钱的能力不是某个工具跑得多久而是知道什么时候换路线。