ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

rcracki_mt实战:纯CPU环境下的彩虹表密码恢复指南

rcracki_mt实战:纯CPU环境下的彩虹表密码恢复指南 我记得第一次接触rcracki_mt是在处理一个老掉牙的Windows系统密码恢复任务。第三方工具导出一堆LM/NTLM哈希客户那边催得紧GPU服务器还在机房吃灰手头只有一台四核的普通工作站。当时试过hashcat跑字典速度虽然不差但要跑完一个中等规模的字母数字组合空间时间仍然不乐观。后来想起还有彩虹表这套路翻出RainbowCrack套件里的rcracki_mt结果一发不可收拾。这个工具不像hashcat那样需要昂贵的显卡也不像john那样依赖字典质量它靠的是预先算好的“密码哈希对照账本”破解的时候不是“算”出来的而是“查”出来的。今天这篇就把它从原理到实战整个捋一遍给准备在纯CPU环境里做密码恢复、安全审计或者单纯在CTF里想快速出答案的朋友们做个完整参考。1. 为什么说彩虹表是“空间换时间”的极致玩法——核心原理1.1 暴力破解和查表的本质区别暴力破解的思路很直接拿字典里的每个候选密码去跑哈希算法算出一个值就和目标哈希比对一次。假设有1亿个候选密码要破解100个哈希那就要跑1亿乘以100次哈希运算时间复杂度是线性叠加的CPU永远是被“计算”这件事卡住。彩虹表的逻辑完全不同。它把“计算”这个最贵的操作提前做完了做成一张巨大的查找表。破解的时候针对每一个目标哈希只需要做有限次数的哈希运算和归约运算然后去表里比对命中了就顺着链条找回原文。换句话说暴力破解是每次都要从头算彩虹表是几乎每次都直接查结果。这也是为什么一台没有独显的老机器跑rcracki_mt反而可能比跑hashcat的某些场景更快——因为瓶颈不在计算速度而在表的命中率和磁盘读取速度。1.2 哈希链、归约函数和表的生成逻辑要理解彩虹表首先要理解“哈希链”这个概念。我们先定义一个哈希函数H比如MD5再定义一个归约函数R。R不是H的逆函数它的作用是把一个任意哈希值映射回一个“看起来像密码”的字符串。比如MD5出来是一串128位的值R可能只取其中的某几位映射成一个小写字母组合。然后我们选一个起始密码P0做这样一串操作P0经过H计算得到H0H0经过R1归约得到P1P1经过H计算得到H1H1经过R2归约得到P2以此类推直到得到一个终点密码Pk这一整条链就是一条“哈希链”。我们不需要把链上的每个中间状态都存下来只需要存起点P0和终点Pk。一张表由成千上万条这样的链组成表文件就是一堆起点和终点的集合。破解某个哈希X的时候先用Rk把X归约成字符串然后查看有没有哪条链的终点和它一致如果没有就继续往前走用Rk-1/H组合反推一层再查一次。最多走k步只要某一步命中了某条链的终点就能顺着起点重新演算整条链在链中间找到那个和目标哈希匹配的节点它的前一个节点就是明文密码。1.3 彩虹表相比普通哈希链改进在哪里如果所有链都用同一个R函数链之间很容易发生“合并碰撞”也就是两条不同起点的链在某个节点汇合了后面就完全重复表的质量会大幅下降。彩虹表的“彩虹”体现在每一层用不同的归约函数R1、R2、R3……Rk相当于给每条链加了垂直方向的“隔离带”大幅度降低了碰撞合并的概率。这也是为什么叫rainbow因为每一层颜色都不一样。这个机制直接决定了使用中的两个关键点表文件越大、链数越多覆盖的密码空间就越大成功率越高。明文长度范围比如1到8位和字符集纯数字、小写字母、可打印ASCII必须在建表时定死超出范围的密码永远破不出来。2. 编译安装没有现成包里该怎么做2.1 Linux下的编译步骤rcracki_mt是RainbowCrack套件社区改造版中的破解程序本身不依赖复杂的库核心依赖是OpenMP用于多线程并行。在Debian/Ubuntu这类系统上先装好基础工具包sudo apt update sudo apt install build-essential libssl-dev libgomp1然后从开源社区拉取rainbowcrack的源码包原本的project-rainbowcrack站点和各个镜像仓库都能找到解压之后进入源码目录tar -zxvf rainbowcrack-1.2-src.tar.gz cd rainbowcrack-1.2-src/ make如果系统较新编译器版本较高可能会在编译阶段报一些废弃API的警告比如openssl/md5.h相关的告警通常不影响生成。编译完成后目录下会出现几个可执行文件rtgen、rtsort、rcrack、rcracki_mt其中rcracki_mt就是我们今天的主角。2.2 源码结构的几个关键文件如果读者想自己修改特性源码里值得关注的文件有两处src/目录下的rcracki.cpp这是rcracki_mt的入口多线程调度逻辑都在这里。src/ChainWalkContext.cpp它决定了哈希链的行走方式归约函数和字符集的处理逻辑都在里面。想增加字符集或者调整归约行为改这个文件。我自己在编译时踩过一个坑OpenMP的链接参数如果被makefile忽略编译出来的程序跑起来只有单线程。解决办法是检查makefile里是否包含-fopenmp如果没有可以在make之前手动设置export CFLAGS-fopenmp export CXXFLAGS-fopenmp make clean make2.3 Windows下的食用方式Windows平台下没必要折腾源码编译社区里有编译好的二进制版本直接把整个文件夹解压出来把彩虹表文件放进去就能用。需要注意的一点是版本位数老版本的二进制很多是32位的在大内存机器上可能认不全表文件建议优先找64位版本否则几百GB的表目录遍历时内存映射容易出怪异问题。2.4 安装后的功能验证拿到可执行文件之后先做一次最简单的自测。用Linux自带的md5sum算出一个字符串的哈希然后指定一个很小的彩虹表文件验证能否破解echo -n hello | md5sum拿到5d41402abc4b2a76b9719d911017c592后找一个md5字符集的彩虹表执行./rcracki_mt -h 5d41402abc4b2a76b9719d911017c592 ./md5_ascii-32-95#1-8_0_4000000_2000000.rt如果一切正常程序会打印出明文结果。这一步能同时验证二进制文件、表文件和命令行参数读写是不是正常。3. 命令格式与参数拆解从一行命令看懂起效逻辑3.1 基本命令结构与两种输入模式rcracki_mt的命令行格式很简单总体是这样rcracki_mt [选项] 彩虹表路径其中“彩虹表路径”可以指定一个表文件也可以用目录加通配符的形式指定多个表比如./tables/*.rt。这个工具的核心选项分成两组一组负责指定目标哈希一组负责控制破译过程和性能。目标哈希有两种输入方式-h直接在命令行里写一个哈希值适合单个目标快速测试。-f指定一个文件文件里每行一个哈希值适合批量处理。还有一个-n参数配合-f使用。它的含义容易让人犯迷糊它指的是文件中哈希条目的“行数”或“格式类型”在源码里它的作用是告诉程序按什么格式解析文件内容。实际使用中最稳妥的做法是保持每行一个十六进制哈希值不要加多余的空格和冒号绝大多数情况下-n都不需要专门指定。3.2 常用选项一览参数含义使用要点-h指定单个哈希适合快速验证表是否有效-f指定哈希列表文件文件每行一个哈希十六进制形式-t指定线程数默认等于CPU核心数超大内存机器可适当调低-s指定起始位置用于断点续跑特别适合超大表-l指定日志文件记录破解进度和结果脚本化时建议开启-p彩虹表所在目录配合通配符路径使用简化输入-g调试模式输出更详细的内部运行日志排查问题用3.3 一行命令的执行逻辑拆解拿这个命令举例./rcracki_mt -t 8 -f target_hashes.txt -l crack_result.log ./tables/ntlm_ascii-32-95#1-8_0_4000000_2000000.rt这一行干了这么几件事启动8个线程加载指定的彩虹表文件到内存映射区域。读取target_hashes.txt把所有哈希值解析成内部格式。用8个线程同时去查表每个哈希独立进行链匹配。命中结果同时打印到屏幕和写入crack_result.log。需要注意rcracki_mt的“多线程”本质上是把多个哈希的查表任务分配到不同线程而不是把一个哈希的查表过程拆成多段并行。所以如果目标文件里只有一个哈希线程数再多也没意义。3.4 关于“结果文件”中一个反直觉的地方rcracki_mt找到明文后不会主动把结果写到一个统一的“cracked.txt”里而是输出到屏幕和指定的日志文件。日志文件是纯追加模式不会覆盖这个设计在批处理场景下其实很友好——脚本反复调用同一个命令日志不会互相覆盖结果始终累积。实战中我更推荐把-l参数设为固定文件名比如cracked_$(date %Y%m%d).log这样一天跑一轮日志自然按天归档分析结果时非常方便不会出现多条命令输出混在一起找不到结果的情况。4. 彩虹表的选型与生成用对表等于成功了一半4.1 表命名规则每一个字段都有意义彩虹表的文件名看着很长其实每个字段都对应一个关键维度。随便拆一个md5_ascii-32-95#1-8_0_4000000_2000000.rtmd5哈希算法类型。ascii-32-95字符集。ascii-32-95表示从ASCII码32到95之间的可打印字符包括空格、标点、数字、大写和小写字母基本覆盖键盘上能直接敲出来的字符。#1-8明文长度范围从1位到8位。_0这是该密钥空间下的第0张表。同一个空间可以生成多张表索引不同每张表覆盖不同的随机链集合。4000000每条哈希链的长度即链上经过的明文-哈希变换次数。2000000表内含有的哈希链总数。这几个数字直接决定了表的尺寸和破解成功率。链长和链数相乘得到的总数大约对应这个表可以覆盖的明文空间大小链越长单次破解需要遍历的步数越多但表文件相对更小链越多表的覆盖率越高但文件体积也越大。4.2 不同算法和场景怎么选表LM哈希这是老Windows系统里那个传奇的弱哈希算法明文被切分成7位一组的片段分别哈希密钥空间特别小。对应的彩虹表体积也不需要很大几百MB就能达到极高的成功率。老系统密码恢复强烈推荐。NTLM哈希现代Windows系统里最常用的哈希算法可以看作MD4的变体。如果没有加盐完全可以用彩虹表处理。字符集较小纯数字或小写字母时成功率非常可观。MD5/SHA1最常见的Web应用密码哈希格式。但要特别注意很多应用会加盐加盐之后彩虹表就失效了。只有无盐MD5/SHA1才适合用彩虹表。bcrypt/scrypt/argon2这类算法本质上是故意设计得很慢而且强制加盐彩虹表完全无效这类哈希只能靠暴力破解或字典rcracki_mt对它们也无能为力。4.3 自己用rtgen生成彩虹表的成本估算没有现成表时就得自己动手生成。生成工具是同一个套件里的rtgen命令格式如下./rtgen md5 ascii-32-95 1 8 0 4000000 2000000生成之后还需要用rtsort排序./rtsort md5_ascii-32-95#1-8_0_4000000_2000000.rtrtsort这一步很容易被新手忽略如果不排序rcracki_mt加载表时会报错或者匹配失败因为二分查找依赖有序排列。成本要提前算清楚。我举个实际例子ASCII可打印字符集约95个字符、长度1到8位全部密码空间大约是95的1次方加到95的8次方约等于6.7×10的15次方。要覆盖这么大的空间一张表的链长设为400万、链数设为200万大约只能覆盖8×10的12次方个明文覆盖率远不够需要生成多张表配合。生成和排序这些表单机CPU可能需要连续跑几天甚至几周磁盘占用也是几十GB到几百GB。所以我的建议很直接先下载网上公开分享的标准表或者从其他安全测试工具包里复用现成的表实在找不到匹配的再考虑自己生成而且只生成小字符集、短长度范围的表。自己盲目生成“全字符集全长度”的庞大数据集大概率是时间和磁盘的双重浪费。4.4 表文件格式rt、rti和后缀rtgen生成的是.rt文件这是最基本的表格式。在破解时rcracki_mt会对.rt文件进行二分查找所以要求表内容经过rtsort排序。有的版本还会生成.rti索引文件这是表格的辅助索引可以在加载时加快初始定位。文件后缀名有两种变体需要知道.rt标准彩虹表文件使用二进制格式存储起点终点对。.rti索引文件配合.rt一起加载可以加速查找但如果索引文件与你手上的.rt文件不匹配比如排序后重新生成过表它会自动重建或者报错。5. 完整实战一个批处理密码恢复案例5.1 准备哈希文件假设我们从一台旧测试机里导出了一批NTLM哈希文件取名ntlm_hashes.txt内容像这样209c6174da490caeb422f3fa5a7ae634 a9fdfa038c4b75ebc76dc855dd74f0da f81d4fae7dec79458ce06e18b0bfb3f3注意每行一个哈希不要带用户名、冒号或者多余的空白字符。rcracki_mt对格式的容忍度不高这是最常见的人为错误来源。如果是从其他工具导出的建议先做一次预处理cut -d: -f4 ntlm_dump.txt ntlm_hashes.txt sed -i /^$/d ntlm_hashes.txt这两行的含义是按冒号切分取第四个字段哈希部分然后删除空行。经过预处理之后的文件才适合直接交给rcracki_mt。5.2 执行破解命令选好对应的NTLM表后执行./rcracki_mt -t 4 -f ./ntlm_hashes.txt -l ./ntlm_cracked.log ./tables/ntlm_ascii-32-95#1-8_0_4000000_2000000.rt程序启动后会有类似这样的输出rcracki_mt 1.2 ... loading rainbow table ... examining table: ./tables/ntlm_ascii-32-95#1-8_0_4000000_2000000.rt ... start cracking ...中间的破解过程可能持续几十秒到几分钟取决于表的大小、哈希数量和磁盘读取速度。线程数-t 4对应四核CPU如果机器是八核十六线程可以调成-t 8甚至更高。5.3 解析输出结果成功破解的哈希会在终端里直接打印出“plaintext of hash is ...”同时写入ntlm_cracked.log。我的习惯是跑完后统一处理日志grep plaintext of ntlm_cracked.log | sed s/.*hash //; s/ is /:/g final_result.txt这样得到的final_result.txt就是“哈希值:明文”的干净对照表后续交给客户或者存档都方便。5.4 一个比较典型的实战经验在这种批处理模式下我实际处理过一批一万多个NTLM哈希用字符集为纯数字的小表表文件约300MB大约15分钟内破出了其中八千多个纯数字密码。剩下的数字加字母组合换了一张更大的ascii-32-95#1-8表又跑了半小时最终总成功率在九成以上。这个命中率比纯字典攻击高很多这就是彩虹表在批量场景下的威力。6. 多线程调优与性能观察让CPU和磁盘都吃满6.1 线程数选择的真实逻辑rcracki_mt的-t参数直观上以为是越大越快实际上没那么简单。我做过一个对照测试同一个表文件、同一个哈希文件在不同线程数下的表现如下线程数消耗时间观察到的瓶颈18分30秒CPU单核跑满磁盘几乎空闲42分20秒CPU四核跑满磁盘读取有明显增加81分55秒CPU多核工作但磁盘读取时间明显上升161分50秒接近极限磁盘已成为新瓶颈原因在于多个线程同时查表都要从同一个表文件里读取数据磁盘的随机读取能力被快速耗尽。如果表文件在机械硬盘上线程数超过8以后收益极低如果表文件放在SSD或者NVMe盘上线程数可以适当提高。6.2 表加载与内存占用rcracki_mt加载表文件时并不是把整个文件读进内存而是用内存映射的方式按需读取。这意味着即使表文件有几十GB也不需要机器有几十GB内存系统只把正在访问的页调入内存其他部分留在磁盘上。这也是它能支持超大表的原因。但如果机器内存确实足够大还可以利用操作系统层面的文件缓存。Linux下可以用vmtouch这个工具把表文件提前“敲”进内存sudo vmtouch -t ./tables/*.rt做过这一步之后再次运行rcracki_mt时所有表数据都在内存里破解速度可以得到显著提升。对于反复要跑多批哈希的场景这个操作非常值。6.3 多表并行把“查表”变成流水线如果目标哈希文件里既有NTLM又有MD5或者你想用多张表覆盖不同明文范围可以并行起多个rcracki_mt进程每个进程指向不同表。终端工具或者脚本可以直接用后台运行./rcracki_mt -t 4 -f hashes.txt -l ntlm.log ./tables/ntlm_*.rt ./rcracki_mt -t 4 -f hashes.txt -l md5.log ./tables/md5_*.rt wait这里强调的是多进程并行和单进程多线程是两回事。单进程多线程共享同一个表文件的读取缓存而多进程各自独立等于把磁盘带宽和CPU核心都当成资源池来同时利用。实测下来两到三个并行进程是性价比最高的方案再多就会因为磁盘争抢导致整体吞吐量下滑。7. 高频报错与排错记录这些坑我替你趟过了7.1 文件格式错误导致哈希无法解析最常见的问题是把带冒号的哈希文件直接丢给-f参数比如一行写成username:1000:AAD3B435B51404EEAAD3B435B51404EE:209c6174da490caeb422f3fa5a7ae634:::rcracki_mt不会自动去掉用户名部分它只会机械地尝试把整行当作哈希值解析十六进制字符串里混入字母和符号之后解析失败程序会给出提示并跳过该行。解决方法是像上文那样先用cut做一次预处理把干净哈希提取出来。7.2 表文件未排序导致的匹配失败自己用rtgen生成表之后如果忘记执行rtsortrcracki_mt在加载时会给出明显的排序错误提示。如果你用的是下载的表也要确认它是经过排序的版本。判断方法很简单用十六进制工具打开表文件尾部如果看到大量连续递增的二进制序列基本可以确认是排序过的。7.3 哈希算法与表类型不匹配每次把NTLM哈希丢给MD5表或者把LM哈希丢给NTLM表结果都是白跑一趟。判断哈希类型的方法LM哈希是固定的32位十六进制后半段常常是AAD3B435B51404EE这种固定填充。NTLM哈希是32位十六进制没有固定规律。MD5是32位十六进制SHA1是40位十六进制。最简单的排查手段是用hash-identifier这类小工具或者直接看导出源。表名里的哈希算法标识必须和目标哈希类型一致这一点在批量处理前一定要核对否则跑一个通宵出来全是零命中那叫一个崩溃。7.4 进度看起来像“卡住”的真相用超大表几十GB跑批量哈希时程序经常长时间没有新输出看起来像卡死了。实际上它可能正在内存中做大量的二分查找比对或者在等待磁盘读取。判断是否真的卡死可以看CPU占用率如果CPU占用率高说明它正在全力干活如果CPU占用率几乎为零而且IO等待很高说明磁盘是瓶颈。针对这种情况最快的手段是停止运行CtrlC把表文件放到SSD或者直接用vmtouch预热到内存再重新启动。不用担心重新跑会重复劳动因为哈希匹配是幂等的重跑一次不会损失任何已破解的结果日志里的记录也不会丢。7.5 和hashcat、john的分工建议很多朋友会问现在hashcat这么强GPU服务器也很便宜还有必要用rcracki_mt吗我的建议是分场景如果目标是无盐哈希、批量大、时间是硬约束又刚好有一批合适尺寸的表文件rcracki_mt可能是最快的方案。如果哈希是带盐的比如大部分Web应用里的bcrypt或者密码空间远超出表覆盖范围直接上hashcat跑字典和规则。如果表文件缺失又不想花几天时间生成那hashcat或john是更务实的选择。工具没有绝对的优劣只有是否匹配场景。rcracki_mt最大的价值在于它是一种“离线预计算”的思路适合那种“哈希丢过来马上要答案”的审计场景。尤其是机器上没有独立显卡、只有一堆老旧的CPU服务器的时候它确实是查漏补缺的利器。最后再分享一个实战中的小技巧很多人用rcracki_mt只把它当成一个“破解器”忽略了它和rtgen、rtsort的组合能力。我现在的习惯是维护一个小型彩虹表库按照不同字符集和长度分目录存放再写一个简单的包装脚本自动根据目标哈希类型来匹配表文件并执行破解。这相当于给自己做了一个轻量级的“密码恢复服务”任何一批无盐哈希过来脚本自动跑一遍几分钟内出报告。还有一个小细节值得留意启动rcracki_mt之前用ulimit -n看一下文件描述符上限。如果同时加载的表文件数量很多系统默认的1024个文件描述符可能不够用比如加载300个表文件时就可能出现“Too many open files”的报错。临时调高ulimit -n 65535这个命令不会持久生效但足够让一次批量任务跑完。遇到过这个报错的朋友应该知道这种问题藏得很深不仔细看根本想不到是文件描述符的锅。记录在这里希望能帮后面的人少走一段弯路。
返回列表