1. CUPP工具的使用边界:它是审计助手,不是无脑扫描器
最近接到一个内部安全审计需求,要对公司一套核心业务系统的口令强度做全面评估。常规弱口令扫描器跑完第一轮,报告里基本都是123456、admin、password这类“全民通用型”弱口令。可实际测试时我发现,真正容易翻车的是另一类口令:用户把自己的姓名拼音、生日、手机号、工号按常见习惯随意拼接。比如zhangsan1992、wangli@123、LiMing0715。这类口令虽然不在常规弱口令字典里,但命中率出奇地高。
当时我选择引入 CUPP(Common User Passwords Profiler,通用用户密码剖析器)。这工具很老牌,核心逻辑不复杂:在不触碰未授权数据的前提下,把参加评估的人员信息字段作为“词根”,按照现实中人们起口令的习惯,自动排列组合出一大批候选口令。它本质上不是那种拿着彩虹表到处撞的扫描器,而是一个“按人物画像生成词库”的辅助工具。
这里必须先把边界说清楚。CUPP 这类工具一旦用错场景,很容易踩到合规红线。所以我在整个项目里的定位是:安全审计辅助器,只输入授权范围内可用的项目资料,生成结果只服务于内部薄弱口令排查和安全意识宣讲,绝不用于任何未授权的账号探测或外部系统验证。
1.1 为什么我会把 CUPP 放到“集成”这个框架里
单次运行 CUPP 其实很轻量,一条命令就能生成一份词表。但真正落地到企业级审计时,你会发现它有几个痛点:
- 默认输出格式比较原始,生成结果往往是一堆按行排列的口令,没有分类,也没办法直接导入到后续检测工具里。
- 每次运行都需要人工交互式录入信息,审计项目一多,重复操作极其烦人。
- 默认词组偏向西文命名习惯,对中文拼音场景覆盖不够,需要额外定制词根和变换规则。
所以我在这个项目里没有把 CUPP 当成一个独立工具直接调用,而是把它嵌入到一条完整的“口令生成流水线”里:先收集合规范围内的信息样本,再通过脚本批量整理词根,然后用 CUPP 的生成能力做组合扩展,最后自动脱敏成审计报告要用到的检测词表。
这么一搞,整个流程就从“手动敲命令”变成了“一条命令跑完整条链路”,后面接人的审计报告、接脚本检测、接整改通知单都方便很多。这也是项目名里“集成”二字的来由。
1.2 密码语料向量从哪里来
很多人第一次接触 CUPP 时,会以为它真的是凭空白造词。其实它背后靠的是信息字段的组合。在做内部审计时,我通常拿到并使用的字段分这么几类:
| 字段类别 | 典型内容 | 说明 |
|---|---|---|
| 基础姓名 | zhangsan、wangwu、lisi | 拼音全拼、姓名缩写 |
| 日期字段 | 1992、0715、920715 | 出生年份、生日月日、常见组合 |
| 工号学号 | 10086、T0001、20230045 | 企业内部编号 |
| 联系方式 | 138xxxx、尾号4321 | 只取授权范围内公开场景的片段 |
| 习惯后缀 | 123、@、abc、520 | 常见弱口令后缀与特殊字符 |
需要特别强调,这些字段的来源必须限定在项目组授权范围内,比如企业自己提供的测试名单、员工签字确认过的安全演练信息。我在实际项目中,会把真实姓名替换成脱敏后的拼音代号再进行测试,避免把个人信息无限制地堆进工具里产生隐私风险。
2. 搭建一个最小可用的 CUPP 集成环境
这部分直接讲操作。我的运行环境是一台 CentOS 7 服务器,装了 Python 3.8,CUPP 源码放在/opt/audit/cupp目录下。整个集成环境的搭建分三个步骤。
2.1 第一步:准备好合法范围内的身份字段样本
先用一个脚本,把授权名单里的信息整理成 CUPP 能直接吃的文本格式。我习惯的格式是每行一个词根,例如:
# words.txt zhangsan wangwu lisi 1992 0715 10086 T0001 1384321 520 123这里有个细节:不要一股脑把所有字段全丢进去,否则生成的词表会爆炸式增长,里面会混入大量根本不会有人使用的组合。我在实践中通常控制在 8~12 个有效词根范围内。词根越贴近目标人群的真实使用习惯,生成结果越有参考价值。
2.2 第二步:写一个可复用的批量生成脚本
CUPP 原生交互模式跑一次会问一堆问题,比如是否包含用户名、是否包含年份、键盘模式等。为了把整个生成过程固定下来,我建议绕过交互,直接用参数调用。
我先用一条命令生成初步词表:
cd /opt/audit/cupp python3 cupp.py --import words.txt --output base_wordlist.txt参数说明:
--import:导入外部词根文件。--output:指定输出文件名。
如果集群里有多个项目要测,我会再包一层 Python 脚本,实现“读取项目字段 → 动态生成 words.txt → 调用 CUPP → 汇总结果”的循环处理。核心脚本大概是这个逻辑:
import subprocess import os import time def generate_wordlist(project_name, fields): word_file = f"/opt/audit/projects/{project_name}/words.txt" output_file = f"/opt/audit/projects/{project_name}/cupp_raw.txt" with open(word_file, "w", encoding="utf-8") as f: for item in fields: f.write(item + "\n") cmd = [ "python3", "/opt/audit/cupp/cupp.py", "--import", word_file, "--output", output_file ] result = subprocess.run(cmd, capture_output=True, text=True) return result.returncode == 0这里我把每个项目独立目录化,方便后面做追踪和复测。实际跑通后,整个集成链路就成了:字段收集脚本 → CUPP 生成引擎 → 后续清洗模块。
这里需要提醒一句:如果你的业务场景涉及特定的口令策略,比如必须包含大写字母和特殊符号,那么 CUPP 原生输出可能不完全满足要求。这种情况我们会在后面的自定义模块中做二次加工,而不是强行改 CUPP 源码。
3. 自定义词库与不同系统的对接细节
CUPP 生成的原生词表,虽然覆盖面不错,但格式上往往还需要打磨,才能对接不同的检测系统和报告组件。我在实际项目里主要做了三件事。
3.1 把 CUPP 输出转化为明文口令检查点
CUPP 默认输出的词表是每行一个口令,但很多企业环境里的口令优化策略是组合式的。举个例子,公司要求口令必须超过 8 位,且包含字母和数字。CUPP 输出里会有一批类似zhangsan这种纯字母口令,也有19920715这种纯数字口令。这些本来就不可能成为实际可用口令,直接带进检测列表只会增加无效匹配。
所以我在集成环境里加了一层规则过滤模块,专门做三件事:
- 按目标系统密码复杂度策略做前置筛选。
- 把 CUPP 输出的原始词根按常见习惯二次拼接,例如
姓名缩写 + 年份 + 特殊字符。 - 对生成的候选词做去重和随机排序。
核心逻辑可以这样理解:
import itertools def expand_candidates(names, years, suffixes): result = [] for name in names: for year in years: for suffix in suffixes: result.append(f"{name}{year}{suffix}") result.append(f"{name.capitalize()}{year}{suffix}") result.append(f"{year}{name}{suffix}") return list(set(result))这一层完成后,得到的才是真正可用于比对入库审计系统账户口令的候选集合。
3.2 留意与其他弱口令工具的配合
很多团队在实际项目里不只用一个工具。我们这边常用的是hydra、john以及自建的口令强度检查脚本。CUPP 的集成价值就体现在这里:生成的词表可以直接导出成其他工具支持的格式。
比如john --wordlist要求纯文本词表,我们把 CUPP 输出做一次sort -u就能直接用。比如某些自研检测脚本需要 JSON 数组格式,那我再用一段脚本包装一下:
cat cupp_clean.txt | python3 -c "import sys,json; print(json.dumps([line.strip() for line in sys.stdin]))" > audit_wordlist.json这一步非常琐碎,但很关键。很多集成项目跑不通,并不是工具本身有问题,而是格式转换环节没做好。
这里还有一个经验之谈:词表生成后,我会习惯性留一份“原始全量版”和“策略过滤版”。原始版用于复盘分析,看用户到底有哪些起名习惯;策略过滤版才用于最终的实际检测。两者分开存放,能避免后续排查问题时把有效信息弄丢。
4. 真实审计案例:用自定义变体拼出用户习惯
我拿一次实际项目来举例。某客户要求对内部一个办公系统的弱口令风险做摸底,授权范围内提供了 200 个测试账号的脱敏字段信息。在正式检测前,我们就意识到这批账号里大部分人用的是中文拼音起名习惯,和 CUPP 默认词典的偏好有明显差异。
4.1 案例一:默认词典检测不到的口令
常规弱口令扫描器扫完,只报出了 3 个password和 2 个123456。但通过 CUPP 集成生成的自定义词表,我们匹配到了 17 个高风险口令。其中比较典型的是zhangsan123、lisi2023、wangwu0715。
这些口令为什么检测不到?因为通用弱口令字典收录的是固定排序的常用口令,它不会根据“这个用户的名字叫 zhangsan”来推导口令。CUPP 的价值恰恰在于:它把独立的词根信息组合起来,还原出用户最可能使用的口令。
4.2 案例二:团队部门拼凑词根如何在规则中收敛
另一个有意思的发现是,很多人的口令习惯把部门缩写和入司年份拼在一起。比如finance2021、hr2022、ops2020。这类口令如果只靠单个用户的姓名词根去生成,很容易漏掉,因为部门缩写不在 CUPP 默认的字段库中。
处理方式很简单:在词根文件里加一行部门缩写,再配合年份后缀,CUPP 就能自动生成一批同类变体。我把词根文件设计成可配置的,支持按部门维度输入:
finance hr ops admin 2020 2021 2022这样一来,原本需要单独猜测的hr2022,就自然地进入候选词列表。整个检测能力不再只依赖单个工具自带的词典,而是可以根据业务特点动态扩展。
我在项目复盘时强调过:这种基于业务字段的词根扩展,才是 CUPP 集成项目真正有价值的地方。你不需要去市面上找一个所谓“更全”的弱口令字典,只要把信息字段整理好,让 CUPP 按规则去组合,就能覆盖大量常规字典覆盖不到的盲区。
5. 踩坑记录:调试时最典型的四个失误
集成环境从零搭到跑通,前后花了差不多两个工作日。过程中踩了不少坑,这里挑四个最典型的写出来,供后来人参考。
5.1 数据拼接格式不统一导致的漏检
第一次整理词根文件时,我直接复制了一份手填表格里的名单。结果发现同一批人里,有的行是“张三”,有的行是“zhangsan”,还有一行是“Zhang San”。CUPP 遇到中文和空格格式,输出的候选词会有大量无效内容,导致后续匹配率骤降。
解决方案是统一格式规范。我在脚本里加了字段清洗步骤,把所有中转字符统一转成小写拼音,同时剔除空白行和明显不合理的超长词条。建议在项目一开始就确认字段规范,避免后期手工返工。
5.2 字符集和编码问题
CUPP 在 Linux 环境下默认以 UTF-8 处理文本,但当我第一次在 Windows 上编辑 words.txt,再传回 Linux 服务器运行时,出现了奇怪的换行符和编码报错。具体表现是生成结果里夹杂\r字符,导致口令匹配失败。
这个坑很好修,但很容易被忽略。我后来在脚本里统一加了编码处理和换行符清洗:
def clean_word_file(word_file): with open(word_file, "r", encoding="utf-8", errors="ignore") as f: lines = [line.strip() for line in f if line.strip()] with open(word_file, "w", encoding="utf-8") as f: f.write("\n".join(lines))别小看这几行,它能省下大量排查时间。
5.3 盲目扩大词根导致词表膨胀
一开始我以为词根越多越好,结果把几十个字段全部丢进 CUPP,生成的候选词表达到了几十万条。后续检测脚本处理时间大幅拉长,而且匹配到的真实命中率反而没有明显提升。
后来我收缩了词根范围,控制在不超过 15 个核心词根,配合 2~3 种变换规则,生成的词表大概在几千到一万条之间。这个规模既保证了检测速度,又不会因为候选词太少而漏掉目标。
5.4 违规边界把控不足
这个坑属于经验层面的。CUPP 生成结果涉及不少个人信息拼凑,如果不注意边界,很容易把审计行为演变成个人信息滥用。我在项目启动前反复和客户确认授权范围,并约定:所有词根只允许来源于客户提供的脱敏测试字段,不允许通过网络搜集、猜测、购买等方式获取额外信息。
同时也提醒准备做类似项目的人:务必把授权确认文档留档,不然工具跑得再顺,合规层面一旦出问题,整个项目都可能被追责。
这里放一个我在项目里使用的授权字段声明表格,方便参考:
| 字段类型 | 是否允许 | 备注 |
|---|---|---|
| 脱敏姓名 | 允许 | 必须由客户方主动提供 |
| 出生日期 | 部分允许 | 只允许到年份,不允许精确到日 |
| 工号 | 允许 | 客户内部授权范围内使用 |
| 手机号尾号 | 不推荐 | 隐私风险较高,未经确认不使用 |
| 社交账号信息 | 禁止 | 超出本审计项目授权范围 |
写在最后的个人体会
CUPP 本身是一个很有针对性的工具,但它的价值释放程度完全取决于使用者的“前置加工”和“后置对接”能力。单跑一条命令很容易,真正要花心思的是词根整理、规则过滤、输出格式统一这些看起来零碎的工作。我在这次内部审计项目里体会到,任何工具一旦被嵌入到完整的业务链路中,就不再是单一的命令行程序,而是一套可以沉淀、可复用、能标准化交付的安全服务能力。
后续如果再遇到类似的口令安全评估项目,我会直接把这套集成环境复用起来,只需要更新项目字段和授权确认文件就能快速投入工作。当然,工具始终只是辅助,口令安全评估最终还是要回归到“提升人的安全意识”这个根本目标上。毕竟再复杂的生成器,也比不上让每个用户从一开始就不使用弱口令来得实在。