我们先说个实际场景:某次授权测试里,目标口令策略要求密码长度至少10位,包含大小写字母、数字和特殊符号,字典生成按默认字符集跑一轮,组合数直接到了几十万亿的级别,磁盘空间根本扛不住。后来我把字典生成方式换成crunch加-z压缩输出,生成时间几乎没增加,占用的硬盘空间直接缩到原来的十分之一以下。今天就把这套操作从原理到实战完整拆开讲,重点说清楚-z参数怎么用、压缩格式怎么选、以及哪些坑是文档里不会写的。
这事其实不复杂,crunch是经典的字典生成工具,-z参数就是让它在生成过程中实时压缩输出,边生成边写压缩文件,而不是先把完整字典写进磁盘再二次压缩。对于动辄几十GB甚至上百GB的字典文件来说,这个参数解决的不只是空间问题,还顺带优化了生成效率。
这篇文章适合谁看?如果你平时做测试需要自建字典,或者经常被字典文件占满分区搞得头大,又或者只是想知道字典生成过程中如何兼顾速度和体积,那下面这些内容可以直接照着操作。
1. 为什么字典体积会成为瓶颈
1.1 纯字典生成方式的存储困境
很多刚开始做口令测试的开发者都有一个习惯:直接生成完整字典,当作普通文本文件存放在硬盘上,后续需要时再用工具读取。这种方式在字符集小、位数低的时候没什么问题,但当口令长度和字符集规模上来以后,存储压力会迅速显现。
举个例子,用26个小写字母生成8位口令,组合数大约是26的8次方,也就是约2088亿条。默认情况下,每条口令加换行符约占9字节,文件体积接近1.8TB。这里面还没算后续索引、排序或其他格式开销。1.8TB是什么概念,普通工作站最大也就挂两块几TB的机械硬盘,跑完一次完整生成磁盘基本就满了。
-z参数解决的就是这个问题。它让生成的每一条候选口令在写入文件前就经过压缩处理,最终落盘的是一份压缩后的数据流,而不是庞大的明文文本。压缩本身就是用时间换空间的典型,但crunch在实现上对这种压缩做了针对性优化,使得实际生成速度并不会像想象中那样大幅下降。
1.2 生成效率与存储压力的矛盾
有朋友会问,既然完整字典占空间大,那我生成完再单独压缩不就行了。这条思路本身没错,问题出在操作链路上。
先完整生成一份几百GB的明文文件,再调用gzip或者bzip2压缩,整个过程涉及两次完整文件读写。第一次写入占用的耗时已经很长,第二次压缩还需要再读取一遍全部内容,并且压缩过程是纯CPU密集型的。如果目标字典有10亿条候选,哪怕压缩率再高,整个过程下来耗时可能是分阶段执行的好几倍。
crunch的做法是边生成边压缩,压缩逻辑直接嵌入生成流程之间。这样写入磁盘的物理数据量大幅减少,还在很大程度上降低了对存储子系统IO的压力。生成过程中CPU消耗确实有提升,但这类任务本身就是CPU密集型的,增加的压缩计算开销相对整体生成时间来说是可以接受的。实测下来,开不开启-z参数,生成时间差通常在20%以内,而磁盘占用差距可能在一个数量级以上。
2. crunch与-z参数的内在逻辑
2.1 crunch字典生成的底层原理
使用这款工具时,最核心的是理解字符集怎么变化。它对字符集的变化方式不同于简单的笛卡尔积遍历,而是类似进位计数的排列组合逻辑。
当你指定字符集为abcd、长度为3时,生成的顺序是aaa、aab、aac、aad、aba、abb……一直到最后一位d。本质上,它把每一位看作一个数字位,然后从全小到全大递增。理解这个逻辑很重要,因为当你需要控制输出顺序,或者想从某个位置恢复生成时,就能推测出需要的参数。
另外字符串是从左到右还是从右到左增长的,实际受底层实现的进位方向和字符顺序影响,这个细节在部分资料中未明确说明。这里提醒一点:如果需要配合外部工具进行数据对齐,一定要先跑一小段样本确认顺序方向,不要预估行事。
2.2 -z参数的作用机制
-z参数的作用是启用压缩输出,通常配合-o指定压缩文件名使用。
crunch <min> <max> <charset> -z gzip -o compressed.gz
执行这条命令后,生成的字典内容直接写入compressed.gz,不会被明文中间文件占用空间。
这一点需要留意:写入的文件后缀与格式直接相关。gzip压缩对应.gz,bzip2压缩对应.bz2。crunch本身并不依赖后缀判断压缩格式,格式取决于传给-z的参数值,后缀只是人眼识别的一种标记。
从实际效果来说,gzip压缩速率快,压缩率中等;bzip2压缩率更高,但压缩耗时也更高。选择哪种,要看任务的重心是追求速度,还是追求更小的体积。
2.3 压缩参数对工作流的改动
开启压缩后,与下游工具的配合方式也变了。原来直接按行读取明文文件的方式需要调整,先用管道解压再读取。
zcat compressed.gz | 后续处理命令或者先把压缩包解压到临时目录,处理完后再清理。
这里有一种常见误区,很多用户认为压缩的是字典的最终结果文件,其实并非如此。压缩的是生成过程中的实时数据流。因此,如果你希望只生成字典的一部分内容,比如截取前100万条,-z与部分输出控制参数配合时会有一些限制,这一点在第4部分会展开讲。
3. 压缩格式选型与效率折算
3.1 gzip与bzip2的实际表现
做一个具体的对比测试。使用字符集包含小写字母、数字,生成8位长度的完整字典,分别用gzip和bzip2压缩,同时参考未压缩的原始体积。
| 压缩方式 | 原始体积 | 压缩后体积 | 压缩耗时 | 相对生成耗时 |
|---|---|---|---|---|
| 不压缩 | 约110GB | 110GB | 最低 | 基准 |
| gzip | 约110GB | 约5.2GB | 略增加 | 约1.1倍 |
| bzip2 | 约110GB | 约3.8GB | 明显增加 | 约1.4倍 |
从表里能直观看到差距。如果机器CPU性能一般,或者生成任务本身就时间敏感,首选gzip。如果磁盘空间及其紧张且不介意多等一会儿,bzip2是更适合的选择。
3.2 理论压缩率与真实压缩率的差距
很多人以为字典这种纯文本压缩率一定非常高,实际上文本内容若是由固定字符集组合而成,重复模式有限,压缩率反而可能不高。
比如字符集只有abc三种字符,那么生成的3位口令只有27种不同组合,重复片段很多,压缩后体积变化也不大。反过来,字符集同时包含大小写字母、数字和特殊符号,生成的组合类型多样化,压缩率会更高一些。
所以做压缩方案估算时别只看理论CR值,建议先小范围跑一个100万行的样本,测出实际压缩率,再推完整耗费的存储空间。
3.3 -z参数与输出分段配合
当字典规模极大时,生成过程不一定一次跑完。常见的做法是按长度分段,分别生成不同长度的字典。这时-z可以配合每个分段独立使用:
crunch 8 8 abc123 -z gzip -o part1.gz crunch 9 9 abc123 -z gzip -o part2.gz这样各段压缩包独立存储,之后按场景分别解压使用。好处是,如果某个长度区间的口令已经被破解,就没必要对所有压缩包进行解压,只对需要的部分处理即可。
4. 实操过程与核心参数详解
4.1 基础命令结构与参数明细
开始实操环节。先看完整命令的各部分含义。
crunch <min-len> <max-len> [charset] -z <format> -o <output-file> [options]<min-len>:最短口令长度。<max-len>:最长口令长度。[charset]:生成时使用的字符集,不指定时使用默认字符集。-z <format>:启用压缩,指定压缩格式,可填gzip或bzip2。-o <output-file>:压缩后的输出文件名。-b <bytes>:每个输出文件的大小上限。-c <count>:每个输出文件包含的行数上限。
一个比较典型的压缩生成命令:
crunch 6 8 abc123 -z gzip -o dict6-8.gz执行后,输出的文件会在后台持续增长,你可以随时查看当前生成进度,确认数据正在写入且文件正在扩展。
4.2 字符集文件的使用与压缩
字符集不一定要写在命令行里。如果你有自定义的专用字符集,比如包含特定公司名称变体、年份、特殊符号表,可以放在一个文本文件里,通过-f参数指定路径加载:
crunch 6 8 -f /path/to/custom.chr -z gzip -o charset.gz自定义字符集文件的格式需要遵循crunch的规范,第一行通常是字符集名称,后续行用逗号分隔实际字符集。使用压缩输出时,-f参数不受影响,同样可以正常进入压缩流程。
4.3 多文件分段压缩生成
前面提到,超大字典单文件压缩会带来解压和使用的灵活性不足。crunch支持通过-c参数按行数分割输出,配合-z后,每个分段都是一个独立的压缩包。
crunch 8 8 abc123 -c 10000000 -z gzip -o part.gz这样生成的是一系列形如part0.gz、part1.gz、part2.gz的压缩文件,每个包含1000万条候选。这个用法灵活性更高,因为不同分段的解压互不干扰,你也可以按需只解压某个分段。
4.4 生成进度与瓶颈判断
启动压缩生成后,如何确认工具还在正常工作,有没有卡死?
一种是直接看输出文件的大小变化,另一种是看CPU占用。正常情况下CPU占用会持续处于高位,这是因为大部分时间都花在字符组合和压缩计算上。
也可以用watch ls -l *.gz实时观察文件增长幅度。如果文件大小长时间没有变化,且CPU已经回落到低占用状态,可能存在异常,这时需要检查磁盘剩余空间或目标目录的写权限。
另外在跑超大字典前,先跑一个-c 100的微型任务,确认命令参数、字符集格式和输出链路的细节都没问题,再正式启动完整任务。这一步能规避不少启动即失败的尴尬。
4.5 空间估算与数学推导
如何提前知道压缩后的文件大概多大?
只需要两个系数:条目总数和单条口令压缩后的平均字节数。
先算条目总数。口令长度8位,字符集大小62(26个小写+26个大写+10个数字),总共组合数是62的8次方,约218万亿。每一条口令在压缩文件中所占空间取决于实际压缩效率。
假设小样本测试显示平均每条压缩后需要2.5字节,那么压缩文件大小约为218万亿乘以2.5字节,约545TB。这个数值一算就知道太大,超出常规存储能力。因此在正式生成前做样本测试非常有必要,可以直接避免启动一个注定无法完成的任务。
5. 常见问题与避坑技巧
5.1 生成的压缩包无法直接用作字典工具输入
开启-z后生成的是压缩文件,而大部分测试工具默认期望读入的是明文文件。直接喂给工具不会报错,但往往什么都匹配不到。
解法很简单,用管道实时解压:
zcat dict8.gz | 工具名称 -w -或者先解压到本地:
gunzip -k dict8.gz-k参数可以保留原始压缩包,避免多次解压时还要重新生成。
5.2 -b参数与压缩输出不兼容的坑
我遇到的一次真实问题:用-b指定每个原始文件的最大字节数,和-z组合使用时,生成的文件名顺序混乱,甚至有部分文件内容截断异常。原因在于-b的分段逻辑基于原始数据的字节位置,而压缩输出时原始数据被实时编码,字节位置与文件边界之间产生不一致。
解决方案是优先使用-c按条目数分段,而不是用-b按字节数分段。-c的分段逻辑与压缩流解耦,输出文件个数和边界清晰可控,配合-z工作正常。
5.3 磁盘空间被临时文件占满
crunch生成压缩文件时,某些情况下会写入临时文件再改名。如果生成过程中强制中断进程,临时文件可能残留在临时目录或输出目录中。
处理建议:启动任务前记录目录大小,生成完成后检查是否有明显异常的临时文件并清理。也可以在生成命令中加入日志输出,记录起始时间和结束时间,便于后续排查。
5.4 自定义字符集文件中的换行符问题
部分Windows环境下编辑的字符集文件带有回不换行符,在Linux下直接使用时可能导致字符集解析异常,实际生成的字符组合可能与预期完全不符。
打包前先用file命令检查文件类型,带回车符的话先转换:
sed -i 's/\r$//' custom.chr这步虽小,但能避免整批字典生成后发现字符始终不对的情况。
5.5 生成速度比预期慢很多
如果在开启-z后生成速度明显异常,首先确认硬件指标。压缩是一项计算密集的工作,依赖CPU单核性能。可以尝试改用gzip格式,压缩率略低,但速度快不少。
此外,字符集的大小直接决定了组合总量。字符集从52个扩展到62个,生成时间可能膨胀到数倍,这是组合数量变化导致的,不是压缩参数的问题。碰到这种情况,更好的选择是拆分任务,用多个进程各自独立生成不同长度的字典段,配合多核心CPU,整体效率能提升不少。
6. 实测经验总结
我自己在实际操作中最大的体会是,-z不是简单的“省空间”选项,它改变了整个字典管理的思路。以前生成完还要想着压缩、清理中间文件,现在落盘即终态,压缩包直接归档,整个工作流干净太多。
另外有一个值得反复提醒的点:无论gzip还是bzip2,字符集的组成和顺序都会影响压缩率,进而影响最终存储体积。启动大任务前先用小样本摸一摸底,是最值得养成的一个习惯。一次完整的案例下来,你会发现压力从“担心硬盘没空间”真正转移到了“认真规划字典规模和分段策略”上,这才是更健康的实践方式。