写这篇东西之前我一直觉得,"字典生成"四个字天然带着劝退气质——听起来像是只有搞安全测试的人才需要,而且似乎很枯燥。但真等你在实际场景里用过一次crunch,你会发现自己之前为了生成一个特定格式的字典写的那些Python脚本、Shell循环,全都是在给工具做苦力。
crunch是一个能在终端里直接按指定规则穷举生成字符串组合的小工具。它没有任何图形界面,不需要配置服务,拿到手就能跑。最小的一条命令,几秒钟内就能让你理解它的全部逻辑;但真正要把它的字符集、模式占位符、分块输出这些能力组合起来,又足够你在真实测试中省下大把时间。这篇文章不打算写成man手册的翻译版,我按自己从零上手到实际使用这条线,把crunch的常用功能、适用场景和踩过的坑完整说一遍。无论你是在做授权的安全评估、密码找回,还是单纯想批量测试一批弱口令,这篇都能直接照着用。
1. 先说清楚:crunch为解决什么问题而生
1.1 一个能直接命中痛点的场景
假设你现在需要验证某个系统里是否有人用"姓名拼音首字母+出生年月"当密码,而且你对这位用户的生日只掌握一个大概区间。手里没有任何现成字典能满足这种高度定制化的需求,现成的rockyou.txt动辄十几GB,里面绝大部分内容又是纯英文单词或常见弱口令,跑起来浪费算力不说,成功率还低。
这时候你的选择无非两条路:要么写一段嵌套循环脚本,用各种排列组合生成文本;要么找一个帮你干这件事的工具,把规则写在命令参数里。crunch就是后者。它做的唯一一件事,就是根据你给定的长度范围和字符集,按顺序穷举出所有可能的字符串,然后输出到屏幕、文件,或直接通过管道喂给下游工具。
1.2 和手写脚本相比,crunch到底强在哪
我自己以前写过一段生成8位纯数字字典的Python代码,逻辑很简单,三层for循环就够。但一旦规则复杂起来,比如"前两位必须是小写字母,第三位必须是大写字母,后面四位必须纯数字,而且不允许连续两位相同",手写循环就开始变得容易出错且难维护。crunch把这类规则抽象成了几个参数:最小长度、最大长度、字符集、模式占位符,几个选项组合一下就能表达清楚。
另外,crunch生成数据的速度和资源占用是经过优化的。它用C语言实现,不停往标准输出吐数据,几乎不占内存——不管你要生成的是1000行还是几十亿行,它的内存占用都保持在一个很低的水平。相比之下,如果图省事用某些脚本语言先把所有组合都装进内存再写文件,碰到稍大一点的字符空间,内存直接爆掉。
1.3 别把crunch理解成"破解工具"
这里值得多写一句:crunch本身是个纯字典生成器,它不连接任何目标系统,不做任何验证,也谈不上"攻击"。它输出的东西只是一个文本流。真正用它的人可能是做授权渗透测试的工程师,可能是忘了压缩包密码想枚举找回的普通用户,也可能是做安全意识培训时给员工演示弱口令风险的安全讲师。工具是中性的,区别只在于用的人是否在合法授权和合规范围内操作。我后面讲的所有案例,前提都是你对自己的资产或已获得授权测试的目标进行操作。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 把第一条crunch命令跑通:几个最常用的参数
2.1 从最小可运行命令理解三个默认行为
crunch的基本格式是:
bash复制crunch <min-length> <max-length> [charset] [options]
当前三个参数都给你的时候,命令逻辑就清楚了。比如:
bash复制crunch 2 3 abc
这条命令的含义是:生成长度从2到3的所有字符串,字符集只包含 a、b、c 三个字符。输出内容大致是这样:
text复制aa
ab
ac
ba
bb
bc
ca
cb
cc
aaa
aab
...
ccc
这里有几个值得注意的默认行为。第一,最小长度和最大长度是包含边界值的,2到3意味着长度为2和长度为3的都要生成。第二,字符集是位置参数,如果省略不写,crunch默认使用26个小写字母作为字符集。第三,所有生成结果默认直接打印到标准输出,也就是终端屏幕上。正因为第三个行为,当你生成的空间较大时,千万不要随手敲一条大命令就往终端上输出——那效果和直接把文件cat到屏幕上没有任何区别,终端会直接被刷爆,你还得手动中断进程。
2.2 结果落到文件:-o参数和Shell重定向
把输出保存到文件有两条路。一条是Unix原生的重定向:
bash复制crunch 4 4 abc > dict.txt
另一条是crunch自带的输出参数:
bash复制crunch 4 4 abc -o dict.txt
两者最终效果差别不大,但从工作流的规范性来说,我建议优先使用 -o。原因后面在分块输出那里能体现出来——用 -o 和 -o START 组合时,crunch可以把一个大型字典按大小自动切成多个文件,这是Shell重定向做不到的。
文件落地之后,你可以用 wc -l 快速验证行数是否符合预期。比如上面 4 4 abc 的规模,预期的组合数是 3^4 = 81行,如果 wc 数出来不是81,那你就要检查是不是参数写错了。
2.3 生成之前先算一笔账:规模估算公式
在使用crunch之前,最应该养成的习惯是先估算生成规模,而不是直接跑。字符空间的计算公式其实很简单:
text复制总组合数 = 字符集长度 ^ 最小长度 + 字符集长度 ^ (最小长度+1) + ... + 字符集长度 ^ 最大长度
举个例子,你要生成8位纯数字密码字典,字符集是数字,长度固定8位,那总数就是10^8,也就是1亿行。每行包括8个字符加一个换行符,共9字节,所以落盘后的体积大约是 100000000 × 9 ≈ 900MB。如果你把范围扩到8到10位纯数字,总数就是 10^8 + 10^9 + 10^10,也就是1110亿行,体积直接奔着10TB去了。这个规模下,与其想着生成全量字典,不如在规则上多做限制,后面我会专门讲模式匹配怎么帮这个忙。
| 字符集 | 长度 | 组合数 | 生成文件体积(估算) |
|---|---|---|---|
| 数字(10) | 4位 | 1万 | 约50KB |
| 数字(10) | 8位 | 1亿 | 约900MB |
| 小写字母(26) | 6位 | 约3.08亿 | 约2.2GB |
| 小写字母(26) | 8位 | 约2088亿 | 约17TB |
| 小写+数字(36) | 8位 | 约2.82万亿 | 约25TB |
这个估算表每次生成前都可以自己心算一遍,避免制造出远超需求的巨型文件——磁盘写满、后续处理工具读不动,这些问题在生成阶段就该被控制住。
3. 字符集和模式匹配:让字典贴合真实密码习惯
3.1 用-f引用系统字符集文件,而不是手打一大串字符
crunch支持在命令行直接传字符集,比如前面那种"abc"三个字符的例子。但真实场景下你需要的字符集往往不是三个字符,而是"26个小写字母+10个数字+常用符号"这种几十上百字符的长串。如果你直接在命令行里把这些字符全手打出来,不仅麻烦,而且容易在传参时出现转义问题。
crunch针对这个问题,默认安装时带了一个字符集定义文件,在Kali这类发行版里路径通常是 /usr/share/crunch/charset.lst。用 -f 参数指定这个文件,再通过文件的编号或名称引用具体的字符集:
bash复制crunch 8 8 -f /usr/share/crunch/charset.lst numeric -o 8digit.dic
这条命令的格式是 -f 后面跟字符集定义文件路径,再跟一个定义文件里列出的字符集名称。numeric 对应的就是纯数字字符集。除了 numeric,charset.lst 里还预置了这些常用字符集:
混合大小写、混合大小写+数字、混合大小写+数字+14个符号……这些预置字符集基本覆盖了日常需求,省得你自己去拼写。你可以直接查看这个文件的内容,里面每一行定义了字符集的名称和实际字符内容,理解了这种格式之后,甚至可以自己往里面加自定义字符集,达到复用的效果。
3.2 -t模式占位符:按照密码习惯做定向生成
如果说字符集是"在哪些字符里面选",那么 -t 模式负责的是"密码的结构长什么样"。很多真实密码并不是完全随机的,它们有结构特征:开头是大写字母,中间是名字拼音,结尾是几位数字。crunch用四个占位符来表达这种结构:
- @ 表示小写字母
- , 表示大写字母
- % 表示数字
- ^ 表示符号
举个例子,如果你确定某个目标密码是"3位小写字母+2位数字"这种结构,长度一共5位,可以这样写:
bash复制crunch 5 5 abc123 -t @@@%%
注意这里有两个特别容易踩的坑。第一,字符集参数还是要给的,而且这个字符集里必须包含模式中用到的字符类型所对应的字符。比如 -t @@@%% 用到了小写字母和数字,那么字符集里面至少要包含你期望出现的字母和数字。第二,-t 模式会把生成结果限制在你给的结构中,你给的字符集字符会被填入对应的@、%占位符位置,而不是自由组合。
这个功能在实际找回密码时极其有用。比如你忘了某个压缩包的密码,但确信它当年是"姓名拼音首字母+出生年月日"的格式,也就是3位小写字母+8位数字,一条命令就能把这个空间完整枚举出来:
bash复制crunch 11 11 abc -t @@@%%%%%%%% -o recover.dic
这里有个安全提示要记住:真正用于恢复的场景,字符集一般要按大小写单独拆分,或者要确认目标密码对大小写是否敏感。否则小写字母用@占位符生成,结果里不含大写字母,那如果密码里实际有大写字母,这个字典就白跑了。
3.3 -d限制重复字符:主动缩减无用空间
另外还有一个非常实用但有使用门槛的参数:-d。它用来限制某个字符在生成结果中最多连续重复多少次。比如:
bash复制crunch 6 6 abc -t @@@@%% -d 2@
这条命令的意义是:小写字母部分,同一个字母最多连续出现2次。稍微解释一下,-d 2@ 表示 @ 对应的字符集中,任意一个字符连续出现的次数最多为2。比如 aabb 是被允许的,但 aaab 就会被过滤掉。
为什么这个参数有用?因为真实密码集中的连续重复字符模式(aaa、111这种)其实占比并不高,而穷举法又特别喜欢生成这类组合——它按照字典序一个一个试,aaa 这种就是很早就会被枚举到。如果你已经用常见的字典跑过一轮,最该做的就是排除这类你已经试过或几乎不可能的空间,-d 可以帮你把这类候选直接砍掉,有效降低总体规模。
3.4 排列模式-p:处理"多个单词组合"的最佳选择
最后一个高价值参数是 -p。它和前面的逻辑完全不同,不是从字符集里逐个选字符,而是把若干个给定字符串做全排列组合。比如:
bash复制crunch 1 1 -p admin root 2024
这条命令生成的不是字符组合,而是 admin、root、2024 这三个词的所有排列组合,像 adminroot2024、2024adminroot 之类的。使用 -p 时,前面固定要写 1 1 作为最小最大长度(实际长度由给定字符串的组合决定),后面直接跟你要组合的各个词。用这个功能可以快速生成"公司名+年份"、"用户名+工号"这类有语义的密码字典,实用性极高。
4. 输出控制与断点续跑:大规模生成时必须掌握的工作流
4.1 分块输出:避免单个字典文件过大
实际使用中,一次生成几十GB甚至几百GB的字典并不是什么夸张的事。这种规模如果一次性写进一个文件,后续加载、切割、排序都很难受,而且一旦中途出错,整个字典全废。crunch提供了分块输出的能力:
bash复制crunch 6 6 -f /usr/share/crunch/charset.lst mixalpha-numeric -o START -b 1gb
这里的 -b 1gb 表示按体积分块,每个文件最大1GB。-o START 是关键,它告诉crunch:输出文件名用时间戳自动生成。当你使用 -o 加具体文件名时,-b参数是不生效的;只有把输出名写成 START,crunch才会在达到体积上限后自动关闭当前文件,再创建下一个文件。
类似地,-c 参数可以按行数分块:
bash复制crunch 6 6 -f /usr/share/crunch/charset.lst mixalpha-numeric -o START -c 1000000
这表示每个文件最多包含100万行。按行分块有个好处是每个文件的行数固定,对后续批量处理程序来说更容易均衡负载。我个人更常用 -c 而不是 -b,因为行数和组合数可以直接对应,便于控制每个文件对应的枚举进度。
4.2 用-s指定起始字符串:实现断点续跑和并发拆分
crunch本身的设计是单进程顺序生成的,不支持真正的断点续传。但它有一个起始字符串参数 -s,可以指定从哪个字符串开始生成。这个参数有几个用处。
第一,当你一次性需要生成的规模太大,担心过程被意外中断时,先把整份工作拆成几段,每段用不同的起始字符串并行跑,各跑各的文件,最后合并。比如8位小写字母,可以从 aaaaaaaa、baaaaaaa、caaaaaaa……分别起跑,分成26份并行生成,时间直接缩短到原来的约1/26。
bash复制crunch 8 8 -f /usr/share/crunch/charset.lst lalpha -s aaaaaaaa -o part1.dic
crunch 8 8 -f /usr/share/crunch/charset.lst lalpha -s baaaaaaa -o part2.dic
第二,如果一次生成中途断了,你根据当前文件最后一行字符串,推算出一个接近的起点,用 -s 参数续上,避免从头再来。注意,你给的起始字符串必须在字符集和长度的空间范围内,而且它的格式必须与生成目标一致(含字符集要求),否则crunch会报错。
4.3 不落盘:直接管道给下游工具
字典生成只是整个测试链路的其中一环。很多时候你的最终目标不是拿到一个字典文件,而是验证这些密码是否匹配某个哈希值。既然crunch的输出是标准输出,那么就完全没必要先把字典落盘,再让另一个工具读取——直接把标准输出通过管道接给验证工具即可,省掉一次巨大的磁盘读写。
一个很典型的例子是配合哈希验证工具使用。因为它本身吃标准输入,所以可以这样写:
bash复制crunch 8 8 -f /usr/share/crunch/charset.lst numeric | hashcat -m 22000 -a 0 -w 3 handshake.hc22000
这里的管道相当于把crunch生成的每一行数据即时喂给hashcat。hashcat每处理完一行,crunch才生产出下一行——两者协同工作,内存占用极低,生成的字典也不会占用任何磁盘空间。这个"生成即使用"的模式是我实测之后觉得最舒服的用法,再大的字符空间也不会因为磁盘不够而被迫放弃。
4.4 边生成边压缩:-z参数
如果确实需要保存文件,又不想让原始文件占太多磁盘,crunch的 -z 参数可以在输出时直接压缩。注意 -z 必须和 -o 一起使用,压缩算法支持 gzip 等格式:
bash复制crunch 8 8 -f /usr/share/crunch/charset.lst numeric -o dict.txt.gz -z gzip
生成结束后,你会得到 dict.txt.gz。这种压缩对字典类文本非常有效,因为文本字符集有限,重复模式多,压缩率常常能达到10倍以上。生成8位纯数字字典(约900MB)压缩后可能只有几十到一百多MB,磁盘压力小很多。但代价是后续使用前需要先解压,或者让下游工具直接支持读压缩文件。同时,压缩状态下crunch已经退出了管道工作模式,无法做到生成即验证,属于一种"为磁盘让路"的折中。
5. 三个实战案例:从命令到结果
5.1 案例一:已知密码结构片段,找回压缩包密码
我朋友之前有个加密压缩包,密码他自己设的,大概十年前设置的。隐约记得是"姓名首字母小写三个字母+8位数字",长度11位,数字部分像是某个日期。也就是说结构基本锁定为 @@@%%%%%%%%。
直接用 -t 模式生成:
bash复制crunch 11 11 -f /usr/share/crunch/charset.lst lalpha-numeric -t @@@%%%%%%%% -o birthday_candidates.dic
但这里有一个关键问题,lalpha-numeric 字符集包含了数字,@占位符只填入小写字母,%占位符只填入数字,因此总体空间是26^3 × 10^8,也就是175亿行,依然太大。进一步压缩空间的办法,是去猜数字部分的年份。既然是"某个日期",那前四位非常可能是19xx或20xx,所以可以把日期范围限制到适合用 -s 指定起点的部分,或者干脆先生成1900-1999开头、2000-2024开头的几个分块文件,并行跑。
这里我踩过的一个经验是:如果你的起始字符串和生成结构发生冲突(比如 -s 给了一个结构不符的字符串),crunch不会好心帮你纠正,而是直接报错。所以遇到复杂结构时,与其靠 -s 切分,不如把字符集拆得更细、结构定得更严,直接从源头缩空间。
5.2 案例二:授权范围内做内网弱口令验证
在拿到授权的内网安全评估中,经常会遇到需要验证一批账号是否存在弱口令的情况。弱口令不一定是纯数字,也不一定是"123456"这种明文词,更多时候是"某个单词加上数字"的模式。
这种场景我会先用crunch生成一批候选密码,再做统一的批量验证:
bash复制crunch 6 8 -f /usr/share/crunch/charset.lst mixalpha-numeric -d 2@ -o weak_combined.dic
-c 参数用来控制文件行数,方便分块验证。整个过程中值得一提的细节在于,对输出文件里的每条候选密码,验证工具的并发能力和批次策略比字典本身更重要——字典生成往往是瞬间完成的,真正耗时的是网络交互和认证请求的往返。所以字典的候选质量(也就是结构贴合度)比字典的绝对数量更能决定成功率。crunch的价值在于,它能根据你掌握的目标密码习惯,帮你快速对齐这部分候选质量。
5.3 案例三:作为字典生成前端,参与完整的自动化流水线
在实际的测试流程中,我倾向于把crunch嵌进一个自动化脚本中,让它作为"生成候选"的前端环节。比如,我写了一个简单的Shell脚本,先从配置里读出目标特点,比如用户名列表和一些常见年份,然后动态拼接出crunch命令:
bash复制#!/bin/bash
YEARS="2020 2021 2022 2023 2024"
for year in $YEARS; do
crunch 8 10 -f /usr/share/crunch/charset.lst lalpha-numeric -p admin "$year" -o cand_$year.dic
done
这个脚本的核心逻辑是把"人"的因素注入字典生成过程。admin是常见用户名前缀,年份是密码中最高频出现的数字段,用 -p 排列模式直接组合,生成出来的字典虽然行数不大,但每一行的命中概率都很高。实际跑下来,这种"小而精"的字典在命中率上完全不输动辄几GB的通用字典,验证速度却快了几个量级。
6. 我踩过的坑和效率建议
6.1 不要小看终端失控问题
crunch刚上手时最容易犯的错,是在没有-o或管道的情况下,直接跑一个大空间的生成命令,然后整个人对着疯狂滚动的终端屏幕手足无措。crunch本身的设计就是往标准输出不断吐数据,终端程序处理这些数据非常吃力,表现得比写文件还慢。所以我现在的习惯是:但凡字符集超过10个、长度超过4位的组合,一律先估算规模,确认空间可控后在命令里加上 -o 或管道。
6.2 字符集传参时的引号和转义
另一个高频踩坑点来自特殊字符的传参。当你的字符集里包含空格、引号、$符这类Shell保留字符时,不处理的话会被Shell当成语法吃掉。比如你需要把空格纳入字符集:
bash复制crunch 2 2 "a b" -o with_space.dic
这里必须用双引号把字符集整体包起来,否则Shell会把空格当成参数分隔符,crunch收到的字符集就变成了只有"a"和"b"。类似的,字符集里如果包含反斜杠或感叹号,注意用单引号或双引号正确包裹。经验法则:字符集内容只要不是字母和数字的简单组合,就应该用引号包裹,然后通过少跑几条小测试命令来验证。
6.3 -t 和 -l 配合时的"歪门邪道"
如果你想让 -t 模式匹配某个特殊字符(比如让密码的某一位就是指字面意义的 @),直接用 -t @@@@@ 会把那一位当成小写字母占位符。这时你需要 -l 参数来指定每一位的字面量。这个参数的解释比较绕,我用一个直观的例子:
bash复制crunch 5 5 abc@ -t @@^@@ -l @x@@
这里的巧妙之处在于 -l 的作用就是声明"模式里的第2位不是占位符,而是字面量",因此字符串中的 ^ 会被当作普通字符处理,不参与符号占位。实际使用中这个参数极易把人绕晕,我建议先在终端上生成一个小规模样本确认输出格式,再投入正式使用。
6.4 分块文件的命名和时间戳
用过 -o START 跑分块生成的人应该都有过这种困惑:生成的第一个文件名往往带一串时间戳,比如 cunch_abcdef-0.txt,这种命名机制导致你没法简单预测下一个文件的文件名。因此,在脚本中处理分块输出时,不要依赖文件名规则去定位最新文件,而是统一用通配符或者先清空旧产物再跑。同时注意,如果上一次生成中途残留了半截文件,下一次跑之前最好手动清理,否则很容易把旧文件和新文件混在一起,造成字典内容重复或缺失。
6.5 从效率角度讲几个实操习惯
crunch本身单进程效率已经很高,它生产数据的速度远高于常见下游工具的消费速度,所以一般情况下不需要再去额外并行化。真正值得优化的方向通常有两个。
第一,尽量从规则上缩减空间,而不是依赖并行。能用模式匹配锁定位置就锁定位置,能限制重复就限制重复。空间缩减十倍,比启动十个并行进程更省事也更可靠。
第二,如果确实要并行,优先按语义拆分成多个小空间(比如不同前缀或不同结构),而不是简单地对一个空间首字母分段,因为后者在拼接结果时容易产生重复。这一点用 -s 参数分段时要特别留心边界字符串的处理——两个分段的交界处很容易出现重复或遗漏,我自己的经验是宁可段与段之间稍微重叠一点,也不要让中间出现空缺。
6.6 一点个人体会
crunch是个没什么学习曲线的小工具,它的绝大多数用法都能在十分钟内试明白。但真正把它用好,靠的不是记住多少个参数,而是你在每次生成之前多想一层:目标密码可能的习惯是什么、这些候选中哪些实际上可以安全地排除、生成的字典后续怎么被消费。明白这些之后,crunch对你来说就不再只是一个"密码生成器",而是整个测试流程里一个顺手又高效的零件。
