Crypto-XOR2实战:循环密钥与字节反转的完整解密思路
简介一份面向广东大学生网络攻防大赛参赛者、CTF Crypto方向练习者的crypto-xor2题目附件包重点考察异或(XOR)加密原理与密文分析思路。资源包共2个文件压缩后仅460B包含密文文件cipher和同名Python脚本task.py后者用于复现加密流程、定位密钥生成逻辑是整个题目最直接的解题线索。已有516人学习或下载。题目要求选手从XOR运算“相同为0、不同为1”的位特性出发结合已知明文攻击、重复模式检索、频率统计等手段推断密钥配合task.py提供的算法细节能够形成“解析脚本→还原密钥→异或解密”的完整闭环。学习这份附件既能掌握单钥异或加密的脆弱点也能积累CTF赛中处理小体积密文样本、编写Python解密脚本的实战经验适合在赛前做针对性训练并延伸理解常见流密码思路。1. 攻防大赛中的 crypto-xor2越简单的题越容易翻车那年的网络攻防大赛Crypto 方向出了一道 crypto-xor2。附件不复杂一个加密脚本一个十六进制文件脚本里白纸黑字写着 XOR。可我第一次跑解密输出全是乱码这才意识到 xor2 里的 2 不是随便起的。这题看着简单坑却藏在两层变换里循环密钥 XOR 之外输出前整体反转了字节序。跳任何一层解出来的都是乱码。这篇会讲透怎么拆两层变换、怎么用已知明文恢复密钥以及完整解密脚本。适合两类人准备网络攻防大赛的选手以及刷题总卡在 XOR 和编码转换上的朋友。看完照着做一遍下次遇到同类题就有标准动作了。2. 拆附件加密脚本和输出文件里藏着哪些判断依据2.1 附件通常长什么样在比赛环境里XOR 类题目最常见的配置是两个文件一个 Python 加密脚本一个包含密文输出的 txt 文件。这类题目的共同特征是加密逻辑本身不强考的是能不能把加密过程完整还原。脚本越短越容易在不起眼的地方埋操作这是比赛出题很喜欢用的手法。我拿到的附件里核心文件是 encrypt.py 和一个 output.txt。output.txt 的内容是一长串十六进制字符肉眼扫过去没有规律。加密脚本总共不到 20 行这个体量在 Crypto 签到题和进阶题之间算是典型。签到题一般一个函数就能看完进阶题则在某个参数上做文章比如密钥长度隐藏、多轮异或、输出前变形。拿到附件的第一件事不是打开编辑器写解密脚本而是把加密脚本从头到尾读一遍把每一步操作按顺序写下来。这一步很多人跳过最后付出的代价比想象中大。我习惯把脚本里的操作按执行顺序编号编完号再决定先处理哪一步。这个习惯在处理多层变换时能省下大量排错时间。2.2 加密逻辑逐行拆解下面这段是我从附件加密脚本里整理出来的核心逻辑变量名做了脱敏处理操作顺序保持一致from binascii import hexlify KEY b?? # 未知密钥长度未知 FLAG bflag{...} # 待加密的明文 def encrypt(msg, key): k len(key) # 第一层循环密钥逐字节异或 xored bytes([msg[i] ^ key[i % k] for i in range(len(msg))]) # 第二层整体字节序反转 return hexlify(xored[::-1]).decode()output.txt 里存的就是这个函数的输出一个十六进制字符串。把这段逻辑拆开看加密过程只有两个动作第一个动作是异或。明文和密钥逐字节异或密钥用完后从头再取。这种写法在 Python 里就是key[i % k]它决定了密钥长度是循环周期。循环密钥 XOR 在比赛中出现频率极高本质是维吉尼亚密码的字节版比单字节 XOR 多了一个周期概念。第二个动作是反转。异或得到的字节流整体倒序再转成十六进制写入文件。两个动作合起来正好对应题目名里的 xor2第一层是 XOR第二层是位置变换。很多人在第一步就栽了只盯着异或那行完全没注意到后面的切片反转。2.3 两个关键参数的判断依据读脚本时有两个参数决定解密脚本怎么写。第一个是密钥循环方式。key[i % k]说明密钥循环使用周期为 k。这种情况下整段明文加密就是 repeating-key XOR。它和单字节 XOR 的最大区别在于单字节 XOR 的密文分布保留明显字母频率特征循环密钥会把频率特征打散。从 output.txt 里直接看如果开头的字节分布比较均匀基本可以判断不是单字节 XOR。第二个是输出前的变换顺序。这里有一个关键点xored[::-1]发生在 hexlify 之前。也就是说output.txt 里的十六进制字符串从左往右第一个字节对应原始字节流的最后一个字节。解密的第一个动作必须是反转而不是直接 fromhex 后猜密钥。这个顺序写反后面所有对位都会错位。怎么从密文本身验证判断一个办法是看长度。输出字符串长度是偶数说明它是完整字节流的 hex 表示明文长度等于字符串长度的一半。另一个办法是回到脚本找所有疑似变换的行把「异或—反转—hex 编码」这个链条在纸上列出来。我一般会这么比先看有没有 hexlify、base64再看有没有循环密钥最后看输出前对字节流做了什么处理三个点排查完加密逻辑就清楚了。3. 攻击思路为什么 XOR 题靠已知明文就能破3.1 为什么不直接爆破全量密钥拿到这类题很多人第一反应是遍历密钥。想法很直接密钥就藏在某个范围里试到能解出 flag 为止。但问题在于如果密钥每一位都可能落在 0 到 255 之间密钥长度为 L 时暴力空间就是 256 的 L 次方。L 取 6 就是 280 万亿种组合本地跑一天都跑不完。但 XOR 有一个别的加密方式没有的性质异或是对称运算c p ^ k天然等价于p c ^ k。只要知道密文 c 和明文 p 中的任何一个就能直接恢复密钥 k。这就是已知明文攻击的基础。比赛给的明文不是完全未知——flag 的标准格式摆在题目描述里通常以flag{开头、以}结尾。光是前缀就已经提供了五个字节的已知明文。所以问题的复杂度从「爆破全量密钥」降成了「验证密钥」两者代价不在一个数量级。很多选手一上来就陷入暴力枚举的思维定式忽略题目里明晃晃给的格式信息这是 XOR 题最常见的弯路。3.2 先还原第二层再谈密钥恢复攻击顺序上有一条铁律任何非 XOR 的变换都要先还原。因为已知明文攻击依赖密文和明文逐字节对位如果字节序是反的密文第 0 个字节对应的是明文最后一个字节拿前缀去异或密文前缀得到的根本不是密钥。解密第一步是处理 hex 字符串、反转字节流from binascii import unhexlify raw open(output.txt).read().strip() xored bytes.fromhex(raw)[::-1] # 先转换再反转这里有个常见写法问题bytes.fromhex(raw)返回的是字节数组反转得到的就是异或层密文。如果直接反转字符串再 fromhex虽然结果等价但思路不清晰。先转 bytes 再反转代码读起来和攻击逻辑一致。反转之后xored[i]就和明文的第 i 个字节对上了这时用前缀flag{的 ASCII 值逐个异或xored前五个字节就能得到密钥在前五个位置上的片段。3.3 用已知明文定位密钥长度和密钥内容有了密钥片段接着的问题是密钥总长多少。如果密钥长度小于等于已知明文长度密钥已被完整恢复直接解全明文。如果密钥比已知明文长剩余位置需要枚举。我一般会这样处理先假设密钥长度在 1 到 8 之间每个长度试一遍。对每个 L用flag{前五个字节异或密文前五个字节得到一个长度 5 的密钥片段当 L 大于 5 时用片段加未知尾部组合去解全文看解出来是否可读。未知部分如果只有 1 到 3 个字节穷举空间是 256 到 1677 万配合可读性检查几秒钟就能跑完。判断解出来的对不对标准有两层一是明文以flag{开头、以}结尾二是中间所有字节都是可见 ASCII 字符。两个条件同时满足基本可以确定密钥和明文都对。这种「已知前缀 可读性检查」的组合是 CTF XOR 题最稳的套路。还有一个辅助手段可以提前缩小 L 的范围在密文里找重复片段统计片段间距的公约数这个思路来自 Kasiski 检测遇到长密钥时很好用。4. 完整复现一个脚本跑通解密全流程4.1 环境准备解密脚本只需要 Python 3不需要第三方库。比赛机 Python 版本通常在 3.8 以上bytes.fromhex和列表推导式足够完成全部工作。文件结构很简单output.txt和solve.py放同一目录。output.txt里只保留十六进制字符串不要有多余空行或开头空格否则strip()之后可能残留异常字符。如果你的题目附件里还有额外说明文件比如提示 flag 格式或者密钥长度优先按说明调整脚本参数。4.2 解密脚本import sys from itertools import product def load_cipher(path): raw open(path).read().strip() return bytes.fromhex(raw)[::-1] # 先还原第二层字节反转 def readable(msg): return (msg.startswith(bflag{) and msg.endswith(b}) and all(31 b 127 for b in msg)) def solve(path): xored load_cipher(path) prefix bflag{ for L in range(1, 9): if L len(prefix): key_part bytes([xored[i] ^ prefix[i] for i in range(L)]) msg bytes([xored[i] ^ key_part[i % L] for i in range(len(xored))]) if readable(msg): print(fL{L}, key{key_part}) print(msg.decode()) return else: known len(prefix) # 已知 5 字节 key_prefix bytes([xored[i] ^ prefix[i] for i in range(known)]) tail_len L - known if tail_len 3: continue # 避免指数爆炸 for tail in product(range(256), repeattail_len): key key_prefix bytes(tail) msg bytes([xored[i] ^ key[i % L] for i in range(len(xored))]) if readable(msg): print(fL{L}, key{key}) print(msg.decode()) return print(not found) if __name__ __main__: solve(output.txt)脚本执行后如果打印出紧凑的密钥和一段明文说明链路是通的。实际运行输出类似L6, keyb\x1f\x0a\x73\x4e\x21\x09 flag{...}4.3 参数说明与判决逻辑脚本里三个地方值得展开讲。第一处是readable()的判定标准。startswith 和 endswith 校验 flag 头尾中间字符范围 32 到 126排除控制字符和高位字节。这个标准误判的概率很低因为随机解出的字节流同时满足三个条件的概率可以忽略不计。如果出现多个候选再用题目描述里的 flag 格式过滤一遍就能收敛。第二处是 L 的遍历范围。1 到 8 覆盖了大多数比赛常见的密钥长度如果题目明说密钥很长把 range 上限改大即可。tail_len 大于 3 时脚本直接跳过这是为了避免指数爆炸。真遇到长密钥先检查明文有没有更长的已知片段比如题目里可能给出的提示词再决定要不要扩前缀。第三处是bytes.fromhex(raw)[::-1]的顺序问题。先转换再反转和先反转字符串再转换结果等价但前者更符合攻击逻辑转换得到真实字节流反转恢复 XOR 层。写脚本时顺序写反不影响答案但会影响排查问题时的思路。如果题目用的前缀不是flag{而是ctf{或别的格式把开头prefix的值改掉重跑即可算法本身不用动。5. 避坑清单XOR 题最容易翻车的五个点5.1 现象解出来全是乱码但每个字节都像是异或过的原因加密不止一层直接对 output.txt 做异或等于跳过第二层变换。字节序不对密钥对不上位恢复出来的自然是乱码。解决回到脚本把发生在 XOR 之后、hexlify 之前的操作全部反向执行。字符串反转就反转回去base64 就 base64 解码字符位移就反向位移。我的习惯是先在纸上写加密变换链再写解密链两边对照检查一次。这题的变换链是「循环 XOR → 反转 → hex 输出」解密链反过来就是「hex 解码 → 反转 → 循环 XOR」。5.2 现象脚本抛 TypeError unsupported operand type(s) for ^原因open().read()得到的是字符串字符串和整数异或直接报类型错误。这个错一眼就能看出来但很多人不改类型就继续写下一行导致后面全乱套。解决字符串先转 bytes。十六进制文本用bytes.fromhex(...)一次性完成类型转换和解码普通字符流用.encode()。起始类型对了后续异或都在 bytes 之间进行不会再因为这个报错。5.3 现象密钥长度猜成 1解出来半段可读半段乱码原因单字节 XOR 的假设忽略了循环密钥的周期。密文前半段碰巧落在某个模式上看起来正常后面周期的密钥片段不同就出现乱码。解决单独看每段确实像单字节 XOR但整体不满足频率特征时应该怀疑密钥长度大于 1。最直接的验证方式是按候选周期切段做频率统计或者用上文脚本的 L 遍历法把长度 2 到 8 全试一遍。这种现象最常见的翻车点在于「第一眼像单字节」的直觉值得留意。5.4 现象跑了很久的大循环最后什么都没解出来原因试图在未知密钥长度下爆破全量密钥。256 的 N 次方组合N 只要到 6 就是本地跑不动的量级。解决先降维。用已知明文定位密钥片段再枚举剩余字节能推的不要爆能枚举 256 的不要枚举 256 的 N 次方。比赛里看到暴力量级超过千万级的循环停下来重新审视题目给的已知条件。这一条也适用于其他加密题型不只是 XOR。5.5 现象解出来了但提交的时候不对原因flag 里可能存在不可见字符比如 UTF-8 多字节字符或明文包含换行符。解密脚本恢复了原始字节流但打印时decode()失败或终端转义干扰了复制。解决不要直接打印先判断msg是否以flag{开头、以}结尾再用repr()或把不可见字符转成 hex 输出亲眼确认字节内容后再提交。可见字符范围判定写对了下划线、花括号这类常见 flag 字符都能正常捕获。6. 从 crypto-xor2 到一个通用习惯解密前先画变换链这题解完之后我养成了一个对加密类题目都适用的习惯写代码前先把加密过程画成一条变换链。拿本题目举例加密脚本四行代码对应的链是这样的# 原始加密逻辑 xored bytes([msg[i] ^ key[i % k] for i in range(len(msg))]) # 步骤1循环XOR reversed_bytes xored[::-1] # 步骤2字节反转 out hexlify(reversed_bytes).decode() # 步骤3hex编码对应到解密的变换链就是一个反向执行的过程hex 解码 - 字节反转 - 循环密钥 XOR 恢复明文这条链的价值在于把「密文到明文」拆成独立小步骤每步只做一件事。写解密脚本时我按链的顺序逐个实现如果某一步结果不对直接在链上定位到那一步检查不需要从头到尾看一遍脚本。密钥恢复环节则变得非常机械已知前缀异或、循环验证、可读性检查代码基本是固定模板。后来我解过的不少 XOR 变体题都是在链上某个位置做手脚有的在 XOR 前先做位移有的在输出前套一层 base64有的把密钥顺序打乱。不管怎么变链的模型不变方向变一下就行。所以我的建议是拿到附件先花三十秒把加密脚本逐行翻译成链再去碰键盘。这个动作不挑题目难度越是短小精悍的题越值得先列清楚再动手。从那以后我每次遇到加密题目都强制走一遍「列链、检查方向、再写脚本」的流程。希望帮到你。本文还有配套的精品资源点击获取

相关新闻

图书馆AI问答助手“热启动”:用RAG让大模型告别胡言乱语

图书馆AI问答助手“热启动”:用RAG让大模型告别胡言乱语

做过图书馆信息化的人应该都有体会:读者问的问题,翻来覆去就那么几类——闭馆时间、借阅规则、馆藏位置、数据库使用、预约取书……但通用大模型一上场,经常“一本正经地胡说八道”,要么告诉你一个根本不存在的开馆时间&#xff0…

2026/10/19 14:16:37 阅读更多 →
软考软件设计师:程序设计语言基础与编译原理考点全梳理

软考软件设计师:程序设计语言基础与编译原理考点全梳理

软考软件设计师上午题一共75道选择题,涉及的知识面铺得非常广。很多人复习到“程序设计语言基础知识”这一章时,都会有同样的感觉:内容不难,但概念太细,编译原理相关的几个阶段总是看完就混,文法那四种类型…

2026/10/19 14:15:32 阅读更多 →
Node.js安装与npm环境配置:从版本选择到镜像加速全流程

Node.js安装与npm环境配置:从版本选择到镜像加速全流程

第一次接触Node.js的人,十个里有七个会倒在“装环境”这一步:官网上一堆版本号不知道选哪个,安装包下载完了一路点Next,最后在终端敲node -v却提示“不是内部或外部命令”。这篇文章就是专门解决这个问题的。我会从下载前的版本选…

2026/10/19 14:15:32 阅读更多 →

最新新闻

智能问卷设计全流程:从逻辑配置到数据清洗的落地实践

智能问卷设计全流程:从逻辑配置到数据清洗的落地实践

问卷调研这事,看着简单,翻车的人排着队。发出去一千份问卷,回来五百份,清洗完能用的可能不到两百。这些问题我在项目里碰过太多次,后来把整套方法沉淀下来,落地成代号就叫“百考通智能问卷设计”的工作链路…

2026/10/19 15:05:00 阅读更多 →
6G空口时延优化:从帧结构到AI的微秒级预算攻略

6G空口时延优化:从帧结构到AI的微秒级预算攻略

6G 空口时延优化,说白了就是把无线接入网这一段的时间账单一张张撕开来看,看谁在偷走微秒级的预算。5G时代我们谈URLLC,宣传口径是1ms空口时延,到了6G喊的是亚毫秒、0.1ms甚至更低——追求的是从“尽力达成的低时延”变成“确定性…

2026/10/19 15:05:00 阅读更多 →
aiopsterm:本地AI终端实现SSH增强与远程主机排障自动化

aiopsterm:本地AI终端实现SSH增强与远程主机排障自动化

1. 项目概述:当终端遇上本地AI,排障逻辑彻底重构“不用 SSH 手敲命令排障了”——这句话不是营销噱头,而是我连续两周在三类生产环境(某高校边缘计算节点、某IoT设备管理平台后台、某中小型企业内网监控系统)实测后的真…

2026/10/19 15:05:00 阅读更多 →
深度学习异常检测全解析:从自编码器到Transformer的实战指南

深度学习异常检测全解析:从自编码器到Transformer的实战指南

1. 异常检测与深度学习的技术联姻异常检测这个方向,我接触了差不多有六七年,从早期用孤立森林、One-Class SVM这些传统方法,到后来全面转向深度学习,中间踩过的坑和尝到的甜头都不少。这篇综述性质的分享,我想把异常检…

2026/10/19 15:05:00 阅读更多 →
Bootstrap手机商城源码实战:从静态页面到可维护项目

Bootstrap手机商城源码实战:从静态页面到可维护项目

简介:这是一套基于Bootstrap框架搭建的手机商城前端模板,面向具备一定HTML、CSS与JavaScript基础、希望快速构建移动端购物平台的开发者。项目采用响应式布局与12列栅格系统,整合导航栏、轮播图、模态框等预定义组件,并预留后端接…

2026/10/19 15:05:00 阅读更多 →
开源Code Review解决方案:从规范到工具的全流程实践

开源Code Review解决方案:从规范到工具的全流程实践

1. 为什么我会专门做一个开源的 Code Review 项目先交代一下背景。我所在的团队大概三十来人,前后端、算法、质量都混在一起,日常迭代节奏很快。Code Review 这件事一直都有,但长期处于一种"有等于没有"的状态:PR 挂着两…

2026/10/19 15:03:58 阅读更多 →

日新闻

频率跟踪型PWM电源设计:臭氧发生器谐振点漂移与软开关实现

频率跟踪型PWM电源设计:臭氧发生器谐振点漂移与软开关实现

简介:本资源为电源技术方向的学术研究文档,聚焦介质阻挡放电型臭氧发生器电源的频率跟踪型PWM控制策略,面向电力电子、高压电源及臭氧应用领域的科研人员与工程技术人员。针对负载呈容性、等效电容随外加电压升高而增大、谐振频率随之漂移的难…

2026/10/19 0:00:47 阅读更多 →
Vibe Coding 遇上 TaoToken:把开发者思维圣殿的灵感流接入统一 Key 通道

Vibe Coding 遇上 TaoToken:把开发者思维圣殿的灵感流接入统一 Key 通道

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 0:00:47 阅读更多 →
HundredCV-Chat话题建模实战教程:利用4,871个内置话题标签构建主题分析系统

HundredCV-Chat话题建模实战教程:利用4,871个内置话题标签构建主题分析系统

【免费下载链接】HundredCV-Chat 项目地址: https://ai.gitcode.com/hf_mirrors/Jax-dan/HundredCV-Chat 点击查看 免费下载 HundredCV-Chat 是一个由 100 位青年简历数据开发而来的中文多轮对话数据集,共包含 24,750 组日常闲聊对话和 4,871 个话题标签…

2026/10/19 0:00:47 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/19 10:02:04 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/19 1:30:52 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 2:54:50 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 9:10:22 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 12:16:16 阅读更多 →