Python构建定制化弱口令字典:从原理到实战的自动化生成指南 1. 项目概述为什么我们需要一个“弱口令字典”在网络安全领域无论是进行授权渗透测试、安全自查还是作为开发者评估自身系统的健壮性密码强度测试都是一个绕不开的环节。而“弱口令字典”就是这场攻防演练中最基础、也最直接的“武器库”。它本质上是一个文本文件里面按行存储了大量由常见密码模式、默认口令、键盘组合、个人信息如生日、姓名等构成的密码字符串。安全人员通过自动化工具使用这个字典去尝试“碰撞”目标系统的登录入口从而发现那些因用户或管理员疏忽而设置的脆弱密码。你可能会问网上不是有很多现成的弱口令字典可以下载吗比如那个著名的“弱口令50w常用字典神器.txt”。确实如此但直接使用现成字典存在几个明显短板一是针对性不强通用字典可能不包含你目标系统特有的命名规则或业务逻辑二是时效性问题新的默认密码和流行组合在不断产生三是隐私与合规风险从不明来源下载的字典文件本身可能就藏有恶意代码。因此掌握自己生成字典的能力意味着你可以根据具体的测试目标例如某公司员工可能使用的密码习惯、某个物联网设备的默认密码规则来定制化生成效率和精准度都会大幅提升。用Python来做这件事再合适不过了。Python语法简洁拥有强大的字符串处理和文件操作能力几行代码就能实现复杂的组合逻辑。更重要的是这个过程本身就是一个绝佳的Python学习项目能让你在实践中掌握循环、列表推导式、文件读写等核心语法。接下来我就带你从零开始用大约5分钟的时间构建一个可定制、可扩展的弱口令字典生成脚本。2. 核心思路与设计如何构建一个高效的生成引擎生成弱口令字典核心思路是“排列组合”与“规则模拟”。我们不是漫无目的地生成随机字符串而是基于对用户设置密码习惯的深入研究模拟出几种高概率的密码模式。一个健壮的生成器通常包含以下层次2.1 基础词库构建这是字典的“原料”。我们需要准备几类基础数据常见弱口令如123456,admin,password,qwerty,111111等常年位居弱口令排行榜前列的“经典款”。键盘模式模仿人们在键盘上输入的连续按键如qazwsx,1qaz2wsx,!qazwsx。年份与日期特别是近20年的年份2000-2024以及1-31的数字日期、1-12的数字月份这是生日密码的核心。姓名与昵称根据目标信息收集可能的用户名、英文名、中文名拼音等。特定业务关键词如公司名缩写、产品名、部门名称等。2.2 组合规则设计有了原料下一步是设计“烹饪方法”。主要规则有简单拼接将基础词两两直接拼接如admin123,root2023。前后缀追加在基础词前后添加常见数字或符号后缀/前缀如admin!,123admin,admin123。常见的后缀包括123,!,,#,2024,abc等。大小写变换对字母进行首字母大写、全大写、全小写等变换如Admin,ADMIN。leet语转换一种用数字和符号替代字母的网络用语如admin转换为4dm1npassword转换为pssw0rd。日期组合将年份、日期、月份进行多种顺序组合如19880808,08081988。2.3 生成策略考量在设计脚本时我们必须考虑两个关键问题规模控制和去重。无限制的组合会导致字典文件体积爆炸轻松达到几十GB不仅难以使用而且大部分是无效组合。因此我们需要通过参数如最大长度、组合深度来控制生成规模。同时在组合过程中会产生大量重复项必须在写入文件前进行去重以提升字典质量。我们的Python脚本将围绕这些思路构建一个模块化、可配置的字典生成器。3. 环境准备与代码框架搭建开始编码前只需要一个最基本的Python环境。你可以在终端输入python --version检查是否已安装。如果没有去Python官网下载最新稳定版安装即可记得在安装时勾选“Add Python to PATH”。我们不需要任何第三方库完全使用Python标准库。首先创建一个名为weak_password_generator.py的新文件。让我们先搭建起整个脚本的骨架。#!/usr/bin/env python3 # -*- coding: utf-8 -*- 弱口令字典生成器 作者你的名字 功能根据多种规则生成定制化的弱口令字典 import itertools from typing import List, Set class WeakPasswordGenerator: def __init__(self): # 初始化基础词库 self.base_words [] # 初始化规则集合 self.rules [] # 用于存储最终结果的集合自动去重 self.passwords: Set[str] set() def load_base_words(self, custom_words: List[str] None): 加载基础词库。可以传入自定义列表也可以使用内置的常见词。 # 内置一些最常见的弱口令 common_weak [123456, admin, password, qwerty, 12345678, 111111, 123123, admin123, root, letmein] self.base_words common_weak.copy() if custom_words: self.base_words.extend(custom_words) # 简单去重 self.base_words list(set(self.base_words)) print(f[] 已加载基础词 {len(self.base_words)} 个) def add_rule_simple_concatenate(self, suffixes: List[str] None): 规则1基础词与后缀简单拼接 if suffixes is None: suffixes [123, !, 123, 456, 789, 2024, abc] new_passwords set() for word in self.base_words: for suffix in suffixes: new_passwords.add(word suffix) # 也可以尝试前缀 new_passwords.add(suffix word) self.passwords.update(new_passwords) print(f[] 规则[简单拼接] 新增 {len(new_passwords)} 条密码) def add_rule_case_variations(self): 规则2大小写变换规则 new_passwords set() for word in self.base_words: if word.isalpha(): # 只对纯字母词进行变换 new_passwords.add(word.lower()) new_passwords.add(word.upper()) new_passwords.add(word.capitalize()) self.passwords.update(new_passwords) print(f[] 规则[大小写变换] 新增 {len(new_passwords)} 条密码) def generate(self) - List[str]: 执行所有已添加的规则生成密码并返回列表 # 首先基础词本身也是密码 self.passwords.update(self.base_words) print(f[*] 开始生成弱口令字典...) # 这里依次调用各种规则方法 self.add_rule_simple_concatenate() self.add_rule_case_variations() # ... 可以在此处调用更多规则方法 print(f[*] 生成完成总计 {len(self.passwords)} 条唯一密码) return sorted(list(self.passwords)) # 排序后返回列表 def save_to_file(self, filename: str weak_passwords.txt): 将生成的密码保存到文件 password_list self.generate() with open(filename, w, encodingutf-8) as f: for pwd in password_list: f.write(pwd \n) print(f[] 字典已保存至文件: {filename} (共 {len(password_list)} 行)) # 一个简单的使用示例 if __name__ __main__: generator WeakPasswordGenerator() # 可以添加自定义的基础词比如目标公司的名称、产品等 custom_words [company, staff, test, demo] generator.load_base_words(custom_words) generator.save_to_file()这段代码定义了一个WeakPasswordGenerator类它具备了基础的框架加载词库、添加规则、执行生成、保存文件。运行这个脚本你会得到一个包含了基础词及其简单变形的字典文件weak_passwords.txt。注意这只是一个起点。生成的字典非常初级。接下来我们要为这个引擎注入更强大的规则。4. 核心规则深度解析与实现现在让我们深入实现几个更复杂、也更有效的生成规则。我们将把这些规则作为类的方法添加到上面的框架中。4.1 日期与年份组合规则生日密码是弱口令的重灾区。我们需要系统性地生成各种日期格式。def add_rule_date_combinations(self, years: List[int] None, max_day31, max_month12): 规则3生成基于日期的弱口令 if years is None: years list(range(2000, 2025)) # 默认生成2000-2024年的年份 new_passwords set() # 1. 纯年份 for y in years: new_passwords.add(str(y)) # 2. 年份常见后缀 common_suffixes [, !, , #, 123, abc] for y in years: for suf in common_suffixes: new_passwords.add(str(y) suf) new_passwords.add(suf str(y)) # 3. 年月日组合 (YYYYMMDD, YYYYDDMM, MMDDYYYY等) # 这里为了控制规模我们只组合年份和1-31、1-12的数字不穷举所有日期 for y in years: for d in range(1, max_day 1): for m in range(1, max_month 1): # 格式: YYYYMMDD new_passwords.add(f{y}{m:02d}{d:02d}) # 格式: YYYYDDMM new_passwords.add(f{y}{d:02d}{m:02d}) # 格式: DDMMYYYY new_passwords.add(f{d:02d}{m:02d}{y}) print(f[] 规则[日期组合] 新增 {len(new_passwords)} 条密码) self.passwords.update(new_passwords)4.2 Leet语转换规则Leet又称1337是一种字符替换文化能有效生成变种密码。def _leet_transform(self, word: str) - List[str]: 对单个单词进行leet语转换返回可能的变体列表 leet_map { a: [4, ], e: [3], i: [1, !], o: [0], s: [5, $], t: [7], } variants [word] # 这是一个简单的递归替换复杂实现需考虑性能 # 这里我们实现一个基础版本对每个可替换字母生成其替换和未替换的版本 # 更优的实现可以使用itertools.product import itertools char_options [] for char in word.lower(): if char in leet_map: char_options.append([char] leet_map[char]) else: char_options.append([char]) for combo in itertools.product(*char_options): variants.append(.join(combo)) # 返回唯一列表 return list(set(variants)) def add_rule_leet_speak(self): 规则4对基础词进行Leet语转换 new_passwords set() for word in self.base_words: if any(c.isalpha() for c in word): # 至少包含一个字母 leet_variants self._leet_transform(word) new_passwords.update(leet_variants) print(f[] 规则[Leet语转换] 新增 {len(new_passwords)} 条密码) self.passwords.update(new_passwords)4.3 键盘空间模式规则模拟在键盘上相邻键的输入顺序。def add_rule_keyboard_patterns(self): 规则5生成键盘空间模式密码 # 定义几种常见的键盘行走路径横向、纵向、斜向 patterns [ qwerty, asdfgh, zxcvbn, # 横向 qazwsx, edcrfv, # 斜向 1qaz, 2wsx, 3edc, 4rfv, 5tgb, 6yhn, 7ujm, 8ik,, 9ol., 0p;/, # 纵向列 !qaz, wsx, #edc, $rfv, %tgb, ^yhn, ujm, *ik, (ol, )p:?, qwertyuiop, asdfghjkl, zxcvbnm, # 长横向 1234567890, # 数字行 ] # 以及它们的反转 patterns_reversed [p[::-1] for p in patterns] patterns.extend(patterns_reversed) new_passwords set(patterns) # 为这些模式添加简单后缀 for p in patterns: for suf in [, !, 123, .., ]: new_passwords.add(p suf) print(f[] 规则[键盘模式] 新增 {len(new_passwords)} 条密码) self.passwords.update(new_passwords)将这些方法添加到WeakPasswordGenerator类中并在generate方法里按需调用你的生成器威力将大大增强。实操心得规则添加的顺序和组合会影响最终字典的规模和有效性。通常先添加基础规则如简单拼接再添加变形规则如Leet、大小写最后添加模式规则如键盘、日期。每添加一个规则都可以观察一下生成的密码数量避免规模失控。一个针对性强、规模在10万到100万之间的字典通常比一个数十亿条但杂乱无章的字典更实用。5. 高级功能与定制化扩展一个基本的生成器已经完成但要应对真实场景我们还需要一些“高级功能”。5.1 密码复杂度过滤与长度控制不是所有生成的字符串都适合作为密码测试。我们需要过滤掉太短或太长的项。def generate(self, min_len: int 4, max_len: int 24) - List[str]: 执行生成并过滤长度不符合要求的密码 # ... 原有的规则调用 ... # 在所有规则执行完毕后进行过滤 filtered_passwords {pwd for pwd in self.passwords if min_len len(pwd) max_len} print(f[*] 长度过滤: {len(self.passwords)} - {len(filtered_passwords)} (长度范围: {min_len}-{max_len})) self.passwords filtered_passwords return sorted(list(self.passwords))5.2 基于已知信息的靶向生成这是定制化的核心。假设我们通过信息收集得知目标用户叫“张三”Zhang San出生于1990年5月10日在“ABC公司”工作。def load_target_info(self, name_en: str None, name_pinyin: str None, birth_year: int None, birth_month: int None, birth_day: int None, company: str None, keywords: List[str] None): 加载目标个人信息构建高相关性的基础词库 target_words [] if name_en: target_words.append(name_en.lower()) target_words.append(name_en) if name_pinyin: # 处理拼音生成全拼和首字母 target_words.append(name_pinyin.lower()) # 假设拼音是空格分隔如 zhang san initials .join([part[0] for part in name_pinyin.split() if part]) target_words.append(initials.lower()) target_words.append(initials.upper()) if all([birth_year, birth_month, birth_day]): # 生成多种日期格式 target_words.append(f{birth_year}{birth_month:02d}{birth_day:02d}) target_words.append(f{birth_day:02d}{birth_month:02d}{birth_year}) target_words.append(f{birth_year%100:02d}{birth_month:02d}{birth_day:02d}) # YYMMDD if company: target_words.append(company.lower()) target_words.append(company.upper()) if keywords: target_words.extend(keywords) # 将目标词添加到基础词库 self.load_base_words(target_words) print(f[] 已加载目标信息词库: {target_words})5.3 使用示例与完整调用让我们整合所有功能写一个完整的示例if __name__ __main__: gen WeakPasswordGenerator() # 场景针对特定目标生成字典 gen.load_target_info( name_enzhangsan, name_pinyinzhang san, birth_year1990, birth_month5, birth_day10, companyabc, keywords[office, server, test] ) # 执行所有生成规则 password_list gen.generate(min_len6, max_len20) # 保存文件 output_file target_specific_passwords.txt with open(output_file, w, encodingutf-8) as f: for pwd in password_list: f.write(pwd \n) print(f\n[] 靶向字典生成完毕) print(f 文件: {output_file}) print(f 密码总数: {len(password_list)}) print(f 示例密码前10条: {password_list[:10]})运行这个脚本你将得到一个高度定制化的字典里面包含了像zhangsan1990、zs0510、abc!#、admin19900510这类高相关性的密码其测试成功率远高于通用字典。6. 性能优化与大规模生成实践当基础词库很大或规则很复杂时生成过程可能会消耗大量内存和时间。我们需要进行优化。6.1 使用生成器Generator避免内存爆炸不要一次性生成所有组合再保存而是边生成边写入文件或者使用生成器逐个产出。def _generate_by_rule(self, rule_func, *args, **kwargs): 一个辅助生成器按规则逐条产生密码 # 这里只是一个示例框架实际需要根据每个规则函数调整 # 核心思想是使用 yield 而非 return list pass def stream_generate_to_file(self, filename: str, min_len4, max_len24): 流式生成并直接写入文件极大节省内存 with open(filename, w, encodingutf-8) as f: # 1. 写入基础词 for word in self.base_words: if min_len len(word) max_len: f.write(word \n) # 2. 为每个规则实现一个流式生成的子函数并在这里调用 # 例如for pwd in self._stream_simple_concatenate(...): f.write(pwd\n) # 注意去重需要在写入时或规则内部处理可以使用一个已写入集合记录 print(f[] 流式生成完成文件已保存: {filename})6.2 多进程加速生成对于CPU密集型的组合计算如大规模的笛卡尔积可以使用multiprocessing库进行并行处理。import multiprocessing def _chunk_worker(base_chunk, suffix_chunk): 工作进程函数处理一个数据块 results set() for b in base_chunk: for s in suffix_chunk: results.add(b s) return results # 在主函数中分割任务使用进程池 # 注意进程间通信开销大适用于计算密集型且数据可分割的任务注意事项多进程优化通常是在字典规模需求极大例如千万级以上时才需要考虑。对于百万级别的字典单进程的优化版本通常可以在可接受的时间内几分钟到十几分钟完成。优先考虑算法优化如减少不必要的循环、使用更高效的数据结构如itertools.product再考虑并行化。6.3 控制字典规模与有效性平衡生成不是越多越好。一个100GB的字典几乎无法用于实际的爆破测试。你需要通过以下方式控制限制基础词数量精选最具针对性的词不要无脑添加。限制组合深度例如只进行“基础词后缀”的一层组合不做“基础词后缀另一种变形”的多层嵌套。使用频率权重给更常见的后缀如“123”、“!”更高的优先级并限制低频后缀的生成。最终去重与排序在保存前务必对最终集合进行去重和排序这不仅能减小文件体积也能让字典在使用时更高效一些爆破工具对排序字典有优化。7. 安全使用、伦理边界与常见问题7.1 安全使用与法律合规这是最重要的一部分。你必须清楚仅用于授权测试你只能在拥有明确书面授权的系统或你自己拥有完全所有权的系统上使用此工具进行测试。未经授权对任何系统进行密码爆破是违法行为。用于安全自查你可以用自己的网站、服务器、路由器来测试密码强度发现并修复弱口令。用于教育与研究在隔离的实验室环境如虚拟机、docker容器中学习安全技术是正当的。7.2 生成字典的常见问题与排查问题1生成的字典文件为空或很小。排查检查base_words是否成功加载。打印self.base_words看看。确认规则函数是否被正确调用查看打印的日志信息。检查长度过滤参数min_len是否设置过高。问题2生成过程太慢程序像卡住了。排查你很可能陷入了组合爆炸。例如如果有1000个基础词和100个后缀简单拼接就会产生10万条密码。如果还有多层循环数量会指数级增长。立即中断程序CtrlC重新评估你的基础词库规模和规则复杂度。从少量数据开始测试。问题3字典中有很多不合常理的密码如过长、乱码。排查检查你的规则逻辑特别是循环嵌套。确保你是在组合有意义的元素而不是在盲目地拼接所有字符。添加强制的长度过滤和字符类型过滤例如剔除包含不可打印字符的字符串。问题4如何生成中文拼音的变体思路中文拼音密码很常见。你需要一个拼音库如pypinyin将中文名转换为拼音。然后对拼音应用上述所有规则拼接、数字后缀、Leet变换等。例如“张三” -zhangsan-zhangsan123,zhanGsan,zh4ngs4n。7.3 让脚本更健壮输入验证与错误处理一个完整的脚本应该能处理各种边界情况。def load_base_words(self, custom_words: List[str] None): 增强版的词库加载带有清洗和验证 common_weak [123456, admin, password] # 示例 self.base_words common_weak.copy() if custom_words: if not isinstance(custom_words, list): raise TypeError(custom_words 必须是一个字符串列表) # 清洗输入去除两端空格过滤空字符串和非字符串类型 cleaned_words [] for word in custom_words: if isinstance(word, str): word_stripped word.strip() if word_stripped: # 非空 cleaned_words.append(word_stripped) else: print(f[-] 警告: 忽略非字符串元素 {word}) self.base_words.extend(cleaned_words) # 去重并过滤掉长度异常的词可选 self.base_words list(set([w for w in self.base_words if 0 len(w) 50])) print(f[] 已加载并清洗基础词 {len(self.base_words)} 个)最后记住这个工具的价值不在于它本身能生成多少条密码而在于你如何根据情报和经验去配置和引导它。一个由100条高度相关密码组成的字典其价值可能超过一个10亿条的杂乱字典。不断根据测试结果和新的弱口令模式去更新你的规则和词库才是保持这个工具生命力的关键。