GitHub推荐:14 年 6K Star:一个 969 行 Python 工具如何成为渗透测试教学的事实标准
GitHub: https://github.com/mebus/cupp
一句话总结
CUPP(Common User Passwords Profiler)是一个基于个人画像(姓名/生日/宠物/伴侣)的针对性弱密码字典生成器,14 年来以单一 Python 文件、无第三方依赖的极简形态,成为 Kali Linux、OWASP 教学、OSCP 取证课程的「行业入门教材」。
值得关注的理由
- 教科书级别的「单文件 CLI 范式」:969 行 Python、零第三方依赖、
python3 cupp.py -i即跑——是「Unix 单文件工具」风格的现代范例,教学意义远大于实战意义。 - 安全工具的可信度范本:GPL-3.0 强 copyleft、CHANGELOG 严格、bumpversion 受控、GNU 风格 banner——给「个人侧写驱动 wordlist」这个争议领域建立了开源信誉护城河。
- 细分市场的事实标准:6K Star + 2K Fork(拷贝率 33%)+ 被 Kali 内置 + 多语言(包含中文)Wikipedia 收录 + 几乎所有 OSCP/CTF 教学材料引用——市场再小,这个位置也稳。
项目展示

演示动画:依次询问姓名、伴侣/子女/宠物生日、公司、特殊字符等 9 维字段,最后输出
.txt字典文件——一人一对话就能产出针对该目标数 KB 的 wordlist。
注:项目 README 中只有这一张官方截图。其余「媒体」均为 CI/Rawsec/Codacy 等项目健康指标 badge,无展示价值。
项目画像
| 维度 | 数据 |
|---|---|
| GitHub | https://github.com/mebus/cupp |
| Star / Fork / Watcher | 6,161 / 2,052 / 428 |
| 代码行数 | 969(Python 100%,1 个核心可执行文件) |
| 项目年龄 | 170 个月(≈14.2 年) |
| 开发阶段 | 已放弃(事实上的维护期:近 90 天 0 commit,2025-12 是 backlog 清理 + 版本号 bump) |
| 贡献模式 | 单人主导(16 名贡献者中 Top1 占 ~69%,作者 Mebus 主导) |
| 热度定位 | 大众热门(密码画像字典生成这一极垂直领域的头部) |
| 质量评级 | 代码一般 / 文档良好 / 测试不足 / CI 基本 |
热度观察
近 161 个 stargazer 采样中 93 个集中在最近 1 个月(其中 68 个 1 天内)——典型的「老项目新流量」病毒式引用驱动,常因某安全课程/博客/工具集合重新引用 CUPP 而涌入新星。这反向印证其行业 awareness 地位。
作者视角:为什么存在这个项目
创始人/作者背景
- 作者 Muris Kurgas(j0rgan)@ remote-exploit.org 时代是 active pentester,2008 年前后在 BackTrack 社区写下初代 CUPP —— 注释里
j0rgan@remote-exploit.org、pwnsauce用词、ASCII 牛头 banner 都强烈指向「前线渗透测试员个人工具」视角。 - 现维护者 Mebus(GitHub 自 2010 起,荷兰亚琛)2012 年从 remote-exploit 归档导入到 GitHub。其 bio「Hacken is niet toegestaan in Nederland!」(荷兰语双关)暗示他属同一欧洲安全文化圈。
- Mebus 现维护 321 个仓库(大部分 fork + 硬件项目),CUPP 是他唯一破 6K Star 的非 fork 项目(仅次于 PolEi),是「个人 security portfolio 头牌」。
问题判断
作者在渗透测试中反复观察到一个现象:系统最强的人是口令最弱的人——人类给系统设置的强密码很难,习惯性复用姓名+生日+宠物名这类「脑内好记」的组合。这是个社会工程学的工程化问题,人脑难以穷举这些「私人信息」的所有排列组合,但算法可以。
时机的关键不是「新技术」而是「工具链补充」:CUPP 上游填补的是 John the Ripper/hashcat wordlist 生成这一环的画像侧,传统 wordlist(rockyou、Seclists)覆盖面广但缺乏目标画像人本属性,CUPP 把「私人信息结构化提取 + 笛卡尔积爆炸」抽象出来。
解法哲学
作者明确选择了「单兵 / 单文件 / 零依赖 / 交互优先」四件套,外加「严格不做什么」:
- 不做的:不接外部 API、不做 GUI(mentalist 后来做了)、不做分布式爆破调度、不做 hashcat 包装——严格留给上游工具链。
- 做的:单文件 CLI(969 行 Python)、交互式对话(
interactive())、配置文件驱动(cupp.cfg)、GPL-3.0 强 copyleft。
这条哲学决定了其模仿成本高、迁移成本低:follower 们(mentalist 做 GUI、bopscrk 做现代化)自然分流到不同侧面,CUPP 守住了最经典的「CLI + 画像」一格。
战略意图
核心产品但非商业基础设施。GPL-3.0 + 零 SaaS 化 + 零赞助/广告 = 严格的 genuine open 策略,不存在 open-core 或商业版。作者精力已转向 RP2040 / Pi5 硬件项目,CUPP 进入维护期。#10 Issue(长期 open)暴露其作者「不想做扩展」的态度——组合关系网所需的数据模型升级被搁置了多年。
核心价值提炼
创新之处
按新颖度×实用性排序:
- 个人画像驱动的密码生成(核心创新)——把「人」建模为 9 维 profile dict(核心身份 + 关系网 + 生日 + 兴趣词),每维做正向词 + Title 大写 + 反序 3 种变体,再与 years/birthdate/random nums/specialchars 笛卡尔积,最后整体
dict.fromkeys()去重。这是同期 pydictor「规则拼接」路线无法匹敌的差异化点。 - 零依赖单文件 CLI 范式——969 行 Python 不依赖任何第三方包,在 air-gapped USB、live CD、目标机旁都能一键
git clone && python3 cupp.py跑起来。对渗透测试员这类「不信任目标机网络环境的场景」是决定性优势。 - 「cfg + INI + global CONFIG dict」三位一体参数注入——配置变更不需要 Python 重打包,运维直接改
.cfg重跑即可。这是「运维可调阈值而无需触碰代码」模式的极简实现。 dict.fromkeys().keys()保序去重——利用 Python 3.7+ 字典插入序特性做 O(N) 去重且不丢失原序,比sorted(set(...))简单。中小数据量(<10w 词)下首选。print_to_file写完字典后的「Hyperspeed Print」打字机彩蛋——time.sleep + clear + 一行行重显,复古 hacker 美学,社区引用「we remember CUPP for this」。
可复用的模式与技巧
| 模式 | 描述 | 可迁移场景 |
|---|---|---|
profile = {} 字段化采集 → generate_wordlist_from_profile() 解耦 | 把「用户交互」与「数据加工」拆成两个函数,通过 profile dict 通讯;测试可直接注入 profile 跳过 stdin | 任何「CLI 入参 → 结构化数据 → 算法加工」流水线(爬虫配置、扫描规则、CI 化工具) |
cfg-driven global CONFIG dict | 配置变更不需要重打包,运维直接改 cfg | 任何需要「用户可调阈值」的本地工具(爬虫限速、扫描器指纹库、压测并发数) |
interactive() 的 while len(field)==0 零依赖表单 | 最朴素的「无值重输」循环,不依赖 inquirer/prompt_toolkit | 任何不想引入 CLI UI 库的小工具(git 钩子、CI 助手、本地管理脚本) |
dict.fromkeys(list).keys() 保序去重 | 利用 dict 插入序 O(N) 去重 | 任何中小数据量 dedupe 场景 |
make_leet(x) 链式 str.replace | 「单次全局替换」替代「字符级候选爆炸」 | 同构的「枚举 → 取代表」类变换(转义、归一化、同义词替换) |
关键设计决策
决策 1:单文件 969 行 CLI(拒绝模块化)
- 问题:让渗透测试员能在陌生环境(air-gapped USB、live CD、目标机旁)一键跑起来
- 方案:全部函数顶层
def,全局 dictCONFIG = {}传递配置,文件名即模块名 - Trade-off:牺牲可测试性(
test_cupp.py只能from cupp import *测整文件),牺牲可扩展性(增加字段要改 5 处),换取「可读 / 易懂 / 易传播」 - 可迁移性:高(适合 < 1500 行的工具型 CLI;超过即反噬)
决策 2:配置驱动 + ConfigParser + 全局字典
- 问题:用户想自定义年份范围、leet 字符表、特殊字符表,但不能改 Python 代码
- 方案:
cupp.cfg用 INI 格式声明[years]/[leet]/[specialchars]/[nums]/[alecto]/[downloader]六个 section,read_config()在main()第一行加载,结果塞进全局CONFIG - Trade-off:牺牲类型安全(
get不存在会抛NoSectionError,Issue #16 历史教训)和抽象边界,换来「零配置可跑、改 cfg 即可调参」 - 可迁移性:高
决策 3:拒绝 leet 化文件级爆炸(Issue #12 历史信号)
- 问题:leet 每字符可选 0~3 替换 → 输出爆炸(n 字符 ≈ K^n)
- 方案:只做「单次全替换」(preserve 顺序,不做排列),把 leet 当成可选后处理而非笛卡尔积维度
- Trade-off:牺牲 leet 覆盖度(不生成
4l3xvsa13xvs4l3X…),换取结果可预期 / 文件可读 - 可迁移性:高(任何「生成式枚举 vs 单次替换」决策点)
决策 4:关系网仅支持两层扩展(本人 + 伴侣 + 子女)
- 问题:用户要「关系网」字段组合输入(Issue #10 长期 open)
- 方案:
kombi[1..7]三个 sections 各自做组合、伴侣+生日、子女+生日的派生字典 - Trade-off:牺牲扩展性(加祖辈/同事/同事宠物要改交互 + generator + leet 三处),换来「用户心理模型一致:profile = 一个人」
决策 5:GPL-3.0 强 copyleft
- 问题:避免衍生版闭源商业化
- 方案:禁止任何衍生版添加额外限制
- 后果:衍生项目(mentalist、bopscrk、BEWGor)都必须在 GPL 框架下开源
竞品格局与定位
竞品对比矩阵
| 维度 | mebus/cupp | LandGrey/pydictor | sc0tfree/mentalist | r3nt0n/bopscrk | berzerk0/BEWGor |
|---|---|---|---|---|---|
| 核心路线 | 画像驱动 CLI | 规则工厂 CLI | 规则 GUI | 画像 + 突变 CLI | OSINT 联动 CLI |
| Star | 6.1k | 3.6k | 2.0k | 1.1k | 418 |
| 依赖 | 零依赖 | 零依赖 | Electron GUI(100MB+) | Python + requests | API 调用 |
| 多语言 / Unicode | 主要 ASCII | u16 编码、中文 | 基础 | 多语种 | 基础 |
| Leet 化 | 一次性替换 | 多种模式 | 规则编辑 | 字符级多突变 | 基础 |
| 配置文件 | cupp.cfg | 多模式命令行 | GUI 参数面板 | JSON / argparse | JSON |
| 教学收录 | Kali + OWASP + OSCP | OWASP | 部分 | 部分 | 边缘 |
| 活跃度 | 已停滞 | 中等 | 中等 | 中等 | 低 |
差异化护城河
- 生态护城河(最强):Kali 默认集成 + rawsec 收录 + 多本安全教材引用 + 14 年 README 沉淀 + Codacy/Travis/Coveralls badge 制造的「项目健康感」+ GPL-3.0 强 copyleft 形成的社区信号
- 文化护城河(次强):ASCII 牛头 banner +
pwnsauce词汇 + 「Hyperspeed Print」彩蛋形成的 hacker subculture 标签 - 技术护城河(极薄):bopscrk 已经证明所有创新点(画像 + leet + 关系网 + 突变)都能更现代地重写
竞争风险
最可能威胁:bopscrk(「CUPP 的下一代」宣传 + 现代化 + 字符级多突变 + 多语种)。次威胁:mentalist(教育市场 GUI 分流)。再次:pydictor(更通用的规则组合)。
CUPP 仍能保住位置的核心理由:教学价值(不需要现代化,因为现代学生学的第一课就是它)+ 用户基数 + 生态壁垒。
生态定位
在整个技术生态中,CUPP 扮演「合法渗透开箱即用工具链中的个人 wordlist 工厂」一格,是教科书级别的「单文件 CLI 渗透工具」教学样本(Kali 内置 + 多本安全教材引用)。其维护投入已显著放缓,更多在「品牌存在」而非「持续创新」价值。
套利机会分析
- 信息差:无——已是该子领域头部,再去 fork 已无太多新意。
- 技术借鉴:
- 「profile dict + interactive() + generator() 解耦」模式可迁移到任何 onboarding 表单 / quiz bot
- 「cfg + INI + global CONFIG dict」模式可迁移到任何「运维可调阈值、不要碰代码」的小工具
- 「
dict.fromkeys().keys()保序去重」是 Python 3.7+ 的隐藏利器
- 生态位:填补「渗透测试 wordlist 生成」中画像侧的空白,与 pydictor 的「规则侧」形成长期互补。
- 趋势判断:整体停滞(作者精力已转向硬件项目),但「老项目新流量」持续——任何安全课程/教程重新引用 CUPP 都能带来一波关注,符合「品牌存在持续价值」判断。
风险与不足
- 代码已腐朽:Python 3 兼容性、ConfigParser 鲁棒性这类底层维护缺口长期未修;Issue 列表中仍有「Can’t run」类问题。
- 数据模型瓶颈:「profile = 一个人 + N 个属性」无法表达「关系图谱」,是 Issue #10 长期 open 的根源。
- 测试覆盖不足:8 个 unittest 偏「smoke test」,核心算法(leet 输出正确性、生日切片边界、组合去重正确性)没断言。
- CI 过时:Travis Python 3.6 已 EOL(2021),无 matrix 多版本、无 lint、无 black/ruff,未适配 GitHub Actions。
- refactor = 0 的隐性信号:作者不希望别人动它的结构——技术上可定义为「不欢迎 fork 续命」。
行动建议
- 如果你要用它:合法渗透测试、CTF 比赛、密码强度审计——比 pydictor 更精准的「目标画像侧」选择,但记得不要照搬 leet 设置(单次替换覆盖度有限,重要场景应串接 hashcat 规则)。
- 如果你要学它:
- 重点关注
cupp.py的interactive()+generate_wordlist_from_profile()+read_config()三个函数的解耦——「用户交互/数据加工/参数加载」三分离的范式 - 学习
make_leet()的「cfg + 链式 replace」组合 - 学习「
dict.fromkeys(list).keys()保序去重」的小技巧
- 重点关注
- 如果你要 fork 它:
- 想清楚你要解决 Issue #10 的「关系图谱」需求吗?要的话需要重写 profile 数据结构(从 dict 升级为图)。
- 加入 Python 3.10+ 现代特性(type hint、
dataclass) - 迁移 CI 到 GitHub Actions + 加入 ruff
- 保留单文件 + 零依赖哲学(这是它的灵魂)——可以考虑用 pyproject 把单文件编译成 wheel,但不引入运行依赖
知识入口
| 资源 | 链接 |
|---|---|
| DeepWiki | 未收录 |
| Zread.ai | 未收录 |
| 关联论文 | 无 |
| 在线 Demo | 无(CLI 工具,无 playground) |
| 收录引用 | Kali Linux 工具集、OWASP Testing Guide、Rawsec CyberSecurity Inventory |
外部深度视角
未找到有分析深度的外部文章——这反向印证其定位:CUPP 是「**工具使用者人人知、架构/思想分析无人写」的教科书型项目,它的价值在于被引用、被使用,而非被讨论。