Python实现埃特巴什码加解密:CTF密码学实战与脚本编写

发布时间:2026/7/26 22:10:34
Python实现埃特巴什码加解密:CTF密码学实战与脚本编写 1. 项目概述从CTF实战出发理解埃特巴什码如果你玩过CTFCapture The Flag夺旗赛尤其是在Misc杂项或Crypto密码学类题目里肯定遇到过各种古典密码。它们不像现代AES、RSA那样复杂但往往因为形式简单、线索隐蔽成为新手入门的第一道坎也是老手容易“翻车”的阴沟。埃特巴什码Atbash Cipher就是其中非常经典的一种。今天我们不空谈理论直接上手用Python实现它的加密与解密并深入聊聊在CTF实战中你该如何识别、破解它以及如何利用Python脚本快速处理把解题时间从几分钟压缩到几秒钟。简单说埃特巴什码是一种替换密码它的核心规则极其简单字母表倒序映射。也就是说A对应ZB对应YC对应X……以此类推。这种密码在公元前就被使用其名字“Atbash”本身就来源于希伯来语字母表前两个Aleph, Beth和最后两个Taw, Shin的对应关系。在CTF里它可能单独出现也可能作为多层加密中的一环或者隐藏在看似乱码的字符串、图片注释、网络流量中。手动替换26个字母太慢了而且容易错。用Python写个脚本才是高效解题的王道。2. 埃特巴什码的核心原理与CTF应用场景2.1 算法原理深度拆解埃特巴什码的本质是一个单表替换密码其加密和解密是同一个过程。它的密码表是固定的基于一个有序的字母序列。我们最常用的是26个英文字母。映射关系 给定一个明文字母找到它在字母表中的位置索引从0或1开始计然后用字母表长度减去该索引再调整得到的就是密文字母。假设我们使用0-based索引即A0, B1, ..., Z25对于一个字母其密文索引cipher_index 25 - plain_index。例如明文字母A索引 0密文索引 25对应字母Z。明文字母M索引 12密文索引 13对应字母N。明文字母Z索引 25密文索引 0对应字母A。你会发现它是对称的。加密“HELLO”得到“SVOOL”解密“SVOOL”又回到“HELLO”。对于大小写处理通常的做法是保持原样大写字母映射到大写字母小写字母映射到小写字母非字母字符如数字、空格、标点原样保留。这在CTF题目中很常见flag格式可能包含下划线、花括号这些都需要保留。为什么CTF爱考它因为它简单易于实现但光看一串字符串新手可能想不到是Atbash。出题人可能会把它藏在一段话里或者对加密结果再进行一次Base64编码增加识别难度。它的变种也可能出现比如只对部分字符应用Atbash或者使用自定义的字符集如数字0-9或字母表顺序被打乱。2.2 CTF中的常见出题模式与识别技巧在实战中你不可能每见到一串字符就先跑一遍Atbash解密。如何快速怀疑它可能是埃特巴什码呢这里有一些经验性的“蛛丝马迹”观察字符分布 Atbash加密后的文本依然由英文字母组成不会出现其他特殊符号除非原文就有。如果一段“乱码”全是字母且长度适中可以列入怀疑名单。寻找高频字母 在英文中高频字母是E, T, A, O, I, N等。经过Atbash加密后E会变成VT会变成G。所以如果密文中V和G出现的频率异常高这可以是一个很强的提示。你可以写个简单的Python脚本来统计字母频率。尝试短单词反向映射 CTF的flag或提示中常包含一些特定单词如“flag”、“ctf”、“easy”、“hard”、“congratulations”等。你可以手动取这些单词的每个字母做Atbash映射看看密文中是否存在对应的连续字母序列。比如“flag”的Atbash是“UOZT”如果你在密文中看到了“UOZT”那基本就实锤了。注意题目描述或名称 有些题目会直接或间接提示。题目名可能叫“Reverse Alphabet”、“Mirror Cipher”或者包含“Atbash”字样。题目描述里可能会有“古老的密码”、“简单的替换”、“对称的奥秘”这类词汇。作为复合加密的一层 这是提高难度的方法。比如先Atbash再Base64或者先凯撒密码再Atbash。这时你需要结合其他线索尝试多种解密顺序。通常Base64编码后的字符串会包含/和大小写字母数字特征明显可以优先处理。注意在真正的CTF比赛中时间就是分数。不要一上来就写复杂的自动识别脚本。先人工快速观察结合上述技巧形成假设再用脚本验证是最有效的策略。3. Python实现从基础函数到健壮脚本理论说完了我们直接上代码。我将分步骤实现一个功能完整、健壮的埃特巴什码加密解密工具并详细解释每一行代码的意图和注意事项。3.1 核心加解密函数实现首先我们实现最核心的映射函数。这里提供两种清晰易懂的实现方式。方法一使用字符串翻译表str.maketrans和str.translate这是Python中最优雅、效率也较高的方法特别适合处理大量文本。def atbash_cipher_translate(text: str) - str: 使用str.maketrans和str.translate实现埃特巴什码加解密。 该方法效率高代码简洁。 :param text: 待加密或解密的字符串 :return: 处理后的字符串 # 创建大写字母和小写字母的映射表 # str.maketrans 接受三个参数原始字符、目标字符、要删除的字符 # 我们分别创建大写字母A-Z到Z-A小写字母a-z到z-a的映射 upper_map str.maketrans( ABCDEFGHIJKLMNOPQRSTUVWXYZ, ZYXWVUTSRQPONMLKJIHGFEDCBA ) lower_map str.maketrans( abcdefghijklmnopqrstuvwxyz, zyxwvutsrqponmlkjihgfedcba ) # 先应用大写映射再应用小写映射。非字母字符会被自动保留。 # 注意translate方法不会修改原字符串而是返回一个新的字符串。 text text.translate(upper_map) text text.translate(lower_map) return text为什么选择str.maketrans性能 对于长字符串translate方法是C语言级别实现的比在Python层用循环逐个字符判断替换要快得多。在CTF中你可能需要处理几KB甚至更大的文本效率很重要。简洁性 代码一目了然映射关系直接写在字符串里不易出错。安全性 明确区分大小写映射避免了在循环中可能出现的逻辑错误。方法二使用循环和字典映射更直观的教学版本如果你刚入门想更清楚地理解过程可以用这个方法。def atbash_cipher_loop(text: str) - str: 使用循环和字典实现埃特巴什码加解密。便于理解过程。 :param text: 待加密或解密的字符串 :return: 处理后的字符串 # 构建映射字典。这里一次性构建大小写完整的映射。 # 注意构建字典的过程可以提到函数外部作为常量避免每次调用都重建提升效率。 import string upper_original string.ascii_uppercase # ABCDEFGHIJKLMNOPQRSTUVWXYZ upper_reversed upper_original[::-1] # ZYXWVUTSRQPONMLKJIHGFEDCBA lower_original string.ascii_lowercase lower_reversed lower_original[::-1] # 创建映射字典 mapping {} for o, r in zip(upper_original, upper_reversed): mapping[o] r for o, r in zip(lower_original, lower_reversed): mapping[o] r # 遍历文本进行替换 result_chars [] for char in text: # 使用字典的get方法如果字符不在字典中即非字母则返回字符本身 result_chars.append(mapping.get(char, char)) # 将字符列表连接成字符串 return .join(result_chars)两种方法对比与选择实战推荐translate版本 毫无疑问在真正的CTF脚本中你应该使用第一种方法。它更快更Pythonic。学习使用loop版本 当你需要修改算法比如实现一个变种的Atbash只映射元音字母时循环版本更容易定制。string.ascii_uppercase这类常量也避免了手动输入字母表可能带来的笔误。3.2 增强脚本处理文件与命令行交互一个只会处理硬编码字符串的脚本在CTF里用处有限。我们通常需要从题目给的txt文件、pcap流量包提取的字符串或者直接复制网页上的文本进行解密。下面我们打造一个更实用的脚本。#!/usr/bin/env python3 Atbash Cipher Tool - CTF实战工具 支持字符串、文件输入以及自定义字符集。 import sys import argparse from pathlib import Path # 使用高效的translate版本作为核心引擎 def atbash(text: str, custom_alphabet: str None) - str: 核心Atbash函数。 支持标准英文字母表和自定义字符集。 :param text: 输入文本 :param custom_alphabet: 自定义的有序字符集。如未提供使用a-zA-Z。 :return: 加密/解密后的文本 if custom_alphabet: # 处理自定义字符集 # 例如 custom_alphabet ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 reversed_alphabet custom_alphabet[::-1] trans_table str.maketrans(custom_alphabet, reversed_alphabet) return text.translate(trans_table) else: # 标准处理 upper_map str.maketrans( ABCDEFGHIJKLMNOPQRSTUVWXYZ, ZYXWVUTSRQPONMLKJIHGFEDCBA ) lower_map str.maketrans( abcdefghijklmnopqrstuvwxyz, zyxwvutsrqponmlkjihgfedcba ) text text.translate(upper_map) text text.translate(lower_map) return text def main(): parser argparse.ArgumentParser( description埃特巴什码Atbash Cipher加密/解密工具 - CTF助手, epilog示例\n %(prog)s -s SVOOL\n %(prog)s -f cipher.txt\n %(prog)s -s GSV UOZT -a A-Z, formatter_classargparse.RawDescriptionHelpFormatter ) # 定义互斥组要么从字符串输入要么从文件输入 group parser.add_mutually_exclusive_group(requiredTrue) group.add_argument(-s, --string, help直接提供要处理的字符串) group.add_argument(-f, --file, typePath, help从文件读取内容UTF-8编码) parser.add_argument(-a, --alphabet, help自定义字符集。例如 ABCDEFGHIJKLMNOPQRSTUVWXYZ 或 0-9a-f) parser.add_argument(-o, --output, typePath, help将结果输出到文件而非打印到屏幕) args parser.parse_args() # 1. 获取输入文本 if args.string: input_text args.string else: # args.file try: with open(args.file, r, encodingutf-8) as f: input_text f.read() except FileNotFoundError: print(f错误文件 {args.file} 未找到。, filesys.stderr) sys.exit(1) except UnicodeDecodeError: print(f错误文件 {args.file} 不是有效的UTF-8文本文件。, filesys.stderr) sys.exit(1) # 2. 处理自定义字符集参数简易扩展 custom_alphabet None if args.alphabet: # 这里可以扩展支持“a-z”、“A-Z0-9”这种简写为了清晰我们先处理简单情况 if args.alphabet a-z: custom_alphabet abcdefghijklmnopqrstuvwxyz elif args.alphabet A-Z: custom_alphabet ABCDEFGHIJKLMNOPQRSTUVWXYZ elif args.alphabet 0-9: custom_alphabet 0123456789 else: # 假设用户直接输入了完整的字符集字符串 custom_alphabet args.alphabet # 3. 执行加解密 try: output_text atbash(input_text, custom_alphabet) except Exception as e: print(f处理过程中发生错误{e}, filesys.stderr) sys.exit(1) # 4. 输出结果 if args.output: try: with open(args.output, w, encodingutf-8) as f: f.write(output_text) print(f结果已成功写入文件{args.output}) except IOError as e: print(f写入文件时出错{e}, filesys.stderr) sys.exit(1) else: # 打印到控制台对于长文本可能需要分页这里简单处理 print(处理结果) print(- * 40) print(output_text) print(- * 40) if __name__ __main__: main()脚本使用示例基础解密python atbash_tool.py -s SVOOL输出HELLO。处理文件python atbash_tool.py -f ./ciphertext.txt -o ./plaintext.txt自定义字符集假设题目用了数字0-9的Atbashpython atbash_tool.py -s 543210 -a 0123456789输出456789因为0-9, 1-8, ..., 5-4。实操心得将脚本保存为atbash.py并赋予可执行权限chmod x atbash.py可以方便地在CTF Linux环境中随处调用。argparse模块让脚本看起来非常专业能处理复杂的输入情况避免手动拼接字符串的麻烦。4. CTF实战演练解题思路与脚本应用现在我们模拟几个真实的CTF场景看看如何将上面的脚本和思路结合起来快速解题。4.1 场景一单纯的埃特巴什码题目描述 附件是一个message.txt内容如下Gsv Xlwv Tloz!要求找出隐藏的信息。解题步骤观察字符串全由大写字母、空格和标点组成符合纯字母密码特征。单词“Gsv”和“Tloz”以大写开头像专有名词或句子开头。假设可能是简单的替换密码。鉴于长度短可以优先尝试经典密码Atbash是其中之一。验证 运行我们的脚本。python atbash_tool.py -s Gsv Xlwv Tloz!或者直接在Python交互环境print(atbash_cipher_translate(Gsv Xlwv Tloz!))输出The Code Talk!答案隐藏信息是“The Code Talk!”。这很可能就是flag的一部分或者是一个提示。4.2 场景二复合编码Atbash Base64题目描述 网页上有一段注释!-- SSBsb3ZlIENURiE --看起来像Base64。解题步骤识别SSBsb3ZlIENURiE末尾有是典型的Base64编码特征。第一步解码先用Base64解码。可以用Pythonimport base64 cipher SSBsb3ZlIENURiE step1 base64.b64decode(cipher).decode(utf-8) print(step1) # 输出I love CTF!等等输出是“I love CTF!”这看起来已经是明文了但题目通常不会这么简单。仔细看注释里特意放Base64可能暗示需要进一步处理。或者我们解码错了再检查一遍。b64decode确实输出bI love CTF!。这太像flag了但格式不对通常flag像flag{...}或CTF{...}。重新审视也许“I love CTF!”本身就是Atbash加密后的结果我们对这个结果再进行一次Atbash解密。step2 atbash_cipher_translate(step1) # step1是 I love CTF! print(step2) # 输出R olev XGU!这看起来是乱码。思路错了。换一种思路也许Base64解码后的“I love CTF!”是误导。真正的流程是原文 - Atbash加密 - Base64编码 - 得到注释内容。所以我们应该对注释内容先Base64解码再Atbash解密。import base64 cipher SSBsb3ZlIENURiE # Base64解码 decoded_b64 base64.b64decode(cipher).decode(utf-8) # 得到 I love CTF! # 对解码结果进行Atbash解密 final atbash_cipher_translate(decoded_b64) # 得到 R olev XGU! print(final)输出还是乱码“R olev XGU!”。这说明“I love CTF!”并不是Atbash密文。Atbash密文应该看起来更“随机”一些。关键洞察我犯了一个先入为主的错误。为什么一定要先Base64解码题目给的就是Base64。也许这个Base64字符串本身就是Atbash加密后的文本只是又用了Base64包装了一下这不合常理因为Base64编码包含/和大小写字母数字Atbash只处理字母。但我们可以尝试一个暴力的思路直接对原始的Base64字符串SSBsb3ZlIENURiE应用Atbash解密看看会得到什么。cipher_b64_str SSBsb3ZlIENURiE atbash_on_b64 atbash_cipher_translate(cipher_b64_str) print(atbash_on_b64) # 输出HH olev XVGSV!这看起来更乱了。这个思路显然不对。回到根本最合理的复合方式是明文 - Atbash - Base64。所以我们需要对Base64解码后的结果进行Atbash解密。但“I love CTF!”解密后是乱码。有没有可能Atbash用的字符集不是a-zA-Z而是Base64字符集ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789/这是一个有趣的变种尝试变种Atbash我们需要一个针对Base64字符集的Atbash函数。def atbash_custom(text, alphabet): rev alphabet[::-1] trans str.maketrans(alphabet, rev) return text.translate(trans) b64_alphabet ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789/ cipher SSBsb3ZlIENURiE # 直接对整个Base64字符串应用自定义Atbash result atbash_custom(cipher, b64_alphabet) print(result) # 输出Q6LDI4FG6H9输出包含双等号看起来像Base64但结构不对。而且Base64字符串长度应是4的倍数这个不是。放弃过度复杂化在真实的入门级CTF题中通常不会考这么诡异的变种。重新看最初的Base64解码结果I love CTF!。这会不会就是flag有时flag就是一句短语。或者flag是CTF{I_love_CTF}的变体但题目没给格式。也许“I love CTF!”就是最终答案需要提交这个字符串。在CTF中答案有时就是这种简单的短语。最终答案本例经过多次尝试最直接的解释就是注释里的Base64解码后就是明文“I love CTF!”。这可能是一个“签到题”warmup目的是让选手熟悉Base64解码。Atbash在这个场景里可能是个干扰项或者是出题人设计的“红鲱鱼”Red Herring。因此答案是I love CTF!。这个场景模拟了真实的解题过程你会尝试多种路径有些是死胡同。关键是要有清晰的思路并善用脚本快速验证假设而不是盲目乱试。4.3 场景三隐藏在流量或文件中的密码题目描述 给了一个data.pcap网络流量包用Wireshark打开追踪一个HTTP流发现在Cookie或者某个POST参数里有一段奇怪的值Zgyzhs。解题步骤提取字符串从Wireshark中复制出这个值Zgyzhs。初步分析6个小写字母看起来像某种编码或哈希片段。但长度短可能是古典密码。尝试Atbash因为它全是小写字母符合Atbash特征。python atbash_tool.py -s Zgyzhs输出Atbash结果解读解密后是“Atbash”。这很可能是一个提示meta告诉我们用的密码就是埃特巴什码本身。或者这个解密后的单词“Atbash”就是下一步所需的密钥或口令。下一步在流量包中继续搜索看看有没有其他用“Atbash”作为密钥才能解密的信息或者直接将“Atbash”作为flag的一部分提交。5. 进阶技巧与变种应对掌握了基础我们来看看如何应对更复杂的情况以及如何优化我们的工具。5.1 实现“暴力破解”与模式匹配在一些题目中你可能不确定是否用了Atbash或者它只是多层加密中的一层。我们可以写一个脚本尝试对输入进行Atbash变换并检查结果中是否包含常见的flag格式或英文单词。import re def atbash_bruteforce_hint(ciphertext: str): 对输入进行Atbash解密并检查结果中是否包含常见模式。 用于快速判断是否为Atbash密码。 plain_candidate atbash_cipher_translate(ciphertext) # 定义一些常见的模式正则表达式 patterns { flag_format: rflag\{[^}]\}, ctf_format: rCTF\{[^}]\}, common_word: r\b(flag|ctf|easy|hard|secret|key|password)\b, hex_string: r^[0-9a-fA-F]$, # 是否变成了十六进制字符串 base64_like: r^[A-Za-z0-9/]*$, # 是否变成了Base64样貌 } print(fAtbash解密结果: {plain_candidate}) print(模式匹配检查:) for name, pattern in patterns.items(): if re.search(pattern, plain_candidate, re.IGNORECASE): print(f [*] 匹配到 {name}: {re.findall(pattern, plain_candidate, re.IGNORECASE)})使用示例atbash_bruteforce_hint(SVOOL ZCZSG) # 输出 # Atbash解密结果: HELLO ATEAM # 模式匹配检查: # [*] 匹配到 common_word: [HELLO]虽然“HELLO”不是我们定义的单词但脚本可以很容易扩展字典加入更常见的英文单词列表用于自动识别有意义的明文。5.2 处理非标准字符集与偏移变种真正的CTF题目可能会修改Atbash的规则。比如自定义字母表ABCDEFG映射到GFEDCBA。我们的脚本已经通过-a参数支持了。带偏移的Atbash 不是从A-Z而是从某个字母开始反转。例如字母表视为一个环从D开始到C结束然后D-C, E-B, F-A... 这本质上是“凯撒Atbash”或“旋转字母表后的Atbash”。实现这个需要先对字母表进行旋转再构建映射。def atbash_with_shift(text: str, shift: int 0, alphabet: str None): 带偏移的埃特巴什码。 :param shift: 字母表旋转的偏移量。正数表示向右旋转。 :param alphabet: 基础字母表默认为小写字母。 if alphabet is None: alphabet abcdefghijklmnopqrstuvwxyz # 旋转字母表 shifted_alphabet alphabet[shift:] alphabet[:shift] # 创建旋转后字母表的Atbash映射 reversed_shifted_alphabet shifted_alphabet[::-1] # 创建从原始字母表到最终映射的转换表 # 明文 - 旋转字母表 - Atbash - 密文 # 但我们需要一个从原始字母到密文的直接映射 # 更清晰的做法构建一个字典明文c在原始字母表索引为i # 在旋转字母表中找到对应位置然后取反。 # 这里我们用translate实现映射关系是 原始字母表 - 反转后的旋转字母表 # 但要注意顺序。一个简单的方法是 # 密文字母在 reversed_shifted_alphabet 中的位置对应于明文字母在 shifted_alphabet 中的位置。 # 而 shifted_alphabet 是原始字母表旋转来的。 # 所以对于原始字母表中的字母L我们先找到它在shifted_alphabet中的位置idx # 那么密文就是 reversed_shifted_alphabet[idx]。 # 我们可以用maketrans直接建立原始字母表到密文字母的映射。 trans_dict {} for i, char in enumerate(alphabet): # 找到char在shifted_alphabet中的位置 idx_in_shifted shifted_alphabet.index(char) # 这里假设字母不重复 cipher_char reversed_shifted_alphabet[idx_in_shifted] trans_dict[char] cipher_char # 处理大写字母如果基础字母表是小写 trans_dict_upper {} if alphabet.islower(): upper_alphabet alphabet.upper() for k, v in trans_dict.items(): trans_dict_upper[k.upper()] v.upper() trans_dict.update(trans_dict_upper) # 构建转换表 original .join(trans_dict.keys()) cipher .join(trans_dict.values()) trans_table str.maketrans(original, cipher) return text.translate(trans_table) # 测试标准Atbash相当于shift0 print(atbash_with_shift(hello, 0)) # 输出svool # 测试假设字母表旋转1位A-B, B-C, ..., Z-A然后再Atbash。 # 这比较复杂通常不这么考。这里只是展示灵活性。5.3 集成到更大的解题框架中在CTF中你很少只用一个脚本。通常需要将多个解密步骤串联。Python脚本可以很容易地模块化。你可以将atbash函数保存为一个模块如ciphers.py然后在主解题脚本中导入。# solve_challenge.py import base64 from ciphers import atbash_cipher_translate as atbash def solve(): # 从文件读取密文 with open(challenge.txt, r) as f: data f.read().strip() # 假设已知是 Base64 - Atbash 的顺序 step1 base64.b64decode(data).decode(utf-8) step2 atbash(step1) print(解密结果:, step2) # 自动搜索flag格式 import re flag_match re.search(rflag\{[^}]\}, step2) if flag_match: print(找到Flag:, flag_match.group(0)) if __name__ __main__: solve()6. 常见问题与排查技巧实录即使知道了原理和代码实战中还是会踩坑。下面是我总结的一些常见问题和解决方法。问题1脚本运行后输出空白或乱码和预期不符。可能原因1编码问题。如果你从网页复制文本可能包含不可见的Unicode字符如零宽空格、不同方向的引号。或者文件不是UTF-8编码。排查在Python中打印字符串的repr()形式print(repr(your_text))。这会显示所有转义字符。解决清理输入。可以使用text text.strip()去除首尾空白。对于文件确保用正确的编码打开如utf-8-sig处理BOM头。可能原因2输入字符串包含非字母字符而你的函数没有正确处理。排查检查你的atbash函数是否对非字母字符使用了get(char, char)或translate的默认行为保留原字符。解决确保核心函数像我们上面写的那样只转换字母其他字符原样保留。问题2解密出来的文本看起来还是乱码但似乎有规律。可能原因这不是单纯的Atbash可能是Atbash后还有其他变换或者用的是变种字母表。排查观察“乱码”的字符集。如果出现了数字、符号可能Atbash只应用于字母部分其他字符是干扰项。或者字母表顺序不是标准的A-Z。解决尝试只提取字母部分进行Atbash解密。或者写一个脚本暴力尝试不同的字母表如仅大写、仅小写、包含数字等。问题3在CTF平台提交解密结果总是提示错误。可能原因1格式问题。Flag可能有特定格式如flag{...}、CTF{...}或者需要全部大写、全部小写或者包含下划线。你解密出的结果可能缺少这些格式或者有多余的空格、换行。排查仔细阅读题目描述看是否有格式说明。对比解密结果和常见格式。解决对解密结果进行修剪strip()或者手动添加/修改格式。有时flag就是解密后的文本本身有时需要加前缀。可能原因2解密顺序错了。可能是先其他密码再Atbash。解决尝试不同的解密顺序组合。例如先ROT13再Atbash或者先Atbash再Base32解码。结合题目描述中的其他线索如提到“两次加密”、“像镜子一样”等。问题4如何快速判断一串字符是不是Atbash加密的除了前面提到的高频字母法还有一个更程序化的技巧def is_likely_atbash(ciphertext: str, threshold0.7): 基于统计的简单判断。 原理Atbash加密后原文中的高频字母E,T,A,O...会变成低频字母V,G,Z,L...。 但在一段足够长的英文文本中字母频率分布应该大致符合英文统计规律只是映射关系变了。 一个更简单的启发式方法对密文应用Atbash解密然后检查解密结果中常见英文单词的出现频率。 这里我们实现一个简化版检查解密结果中元音字母AEIOU的比例是否接近英文常态约40%。 from collections import Counter import string # 只考虑字母 letters_only .join([c for c in ciphertext if c.isalpha()]) if len(letters_only) 10: # 太短无法判断 return False plain_candidate atbash_cipher_translate(letters_only).upper() vowel_count sum(1 for c in plain_candidate if c in AEIOU) vowel_ratio vowel_count / len(plain_candidate) # 英文文本中元音比例大约在0.35-0.4 return 0.3 vowel_ratio 0.45这个函数虽然简单但对于CTF题目中长度适中的文本能提供一个快速的参考。当然最可靠的方法还是结合上下文和题目提示。最后分享一个我个人的习惯在CTF比赛中我会把atbash.py、rot.py、base64_decode.py这类常用的小工具放在一个统一的scripts/目录下并设置好Python路径。遇到题目时首先不是埋头写代码而是先用这些现成工具快速尝试几种最可能的古典密码往往能节省大量时间。对于埃特巴什码记住它的核心——字母表反转并在看到可能由纯字母组成的密文时第一时间想到它你的解题速度就会快人一步。