这是什么编码 - writeup by AI
📋 题目信息
| 项目 | 内容 |
|---|---|
| 题目名称 | 这是什么编码 |
| 来源平台 | BUGKU CTF |
| 题目类型 | Crypto (密码学) |
| 核心考点 | Base 家族编码识别、多层嵌套解码 |
| 涉及编码 | Hex、Base32、Base64 |
🎯 题目描述
给定的密文文件 encode.txt 中包含一串经过多重编码的字符串,需要通过分析和解码,最终提取出隐藏的 flag。
原始密文(前 100 字符):
4b5a4b455536534e4b5a48454f56334f4a5a4b57455232534b564b464d5754584b524c4655574445493544464f544b5647...
密文总长度:2560 个字符
🔍 考点分析
1. 主要考点
- 编码特征识别:通过字符集和长度特征判断编码类型
- 多层解码能力:理解编码可以嵌套使用
- 耐心与细心:需要多次迭代解码
2. 涉及的编码知识
十六进制编码 (Hex)
| 特征 | 说明 |
|---|---|
| 字符集 | 0-9, A-F (16 个字符) |
| 长度特征 | 偶数 |
| Padding | 无 |
| 压缩比 | 2:1 (编码后长度翻倍) |
Base32 编码
| 特征 | 说明 |
|---|---|
| 字符集 | A-Z, 2-7 (32 个字符) |
| 长度特征 | 8 的倍数 |
| Padding | = (最多 6 个) |
| 压缩比 | 8:5 ≈ 1.6:1 |
Base64 编码
| 特征 | 说明 |
|---|---|
| 字符集 | A-Z, a-z, 0-9, +, / (64 个字符) |
| 长度特征 | 4 的倍数 |
| Padding | = (最多 2 个) |
| 压缩比 | 4:3 ≈ 1.33:1 |
💡 解题思路
整体策略
- 观察特征:分析密文的字符组成和长度
- 初步判断:根据特征推测编码类型
- 逐层解码:从外层到内层依次解码
- 循环检测:每次解码后检查是否出现 flag
- 记录路径:保存完整的解码过程
编码嵌套逻辑
原始数据
↓ [Hex 编码]
Hex 密文 (2560 字符)
↓ [Base32 编码]
Base32 密文 (1280 字符)
↓ [Base64 编码]
Base64 密文 #1 (800 字符)
↓ [Base64 编码]
Base64 密文 #2 (600 字符)
↓ [Base64 编码]
Base64 密文 #3 (448 字符)
↓ [Base32 编码]
Base32 密文 #4 (336 字符)
↓ [Base32 编码]
Base32 密文 #5 (208 字符)
↓ [Base64 编码]
Base64 密文 #6 (128 字符)
↓ [Base32 编码]
Base32 密文 #7 (96 字符)
↓ [Base64 编码]
Base64 密文 #8 (56 字符)
↓ [Base32 编码]
Base32 密文 #9 (40 字符)
↓ [解码]
Flag (23 字符)
📝 详细解题步骤
Step 1: 初始密文分析
输入:原始密文(2560 字符)
特征分析:
- ✅ 只包含字符
0-9和A-F - ✅ 长度为偶数(2560)
- ✅ 符合十六进制编码特征
判断 :这是十六进制编码 (Hex)
操作:
python
decoded = bytes.fromhex(cipher).decode('utf-8')
结果:
- 解码后长度:1280 字符
- 压缩比:2:1
- 新密文特征:只包含
A-Z和2-7
Step 2: Base32 解码
输入:Step 1 的结果(1280 字符)
特征分析:
- ✅ 只包含大写字母
A-Z和数字2-7 - ✅ 长度能被 8 整除(1280 % 8 = 0)
- ✅ 符合 Base32 编码特征
判断 :这是Base32 编码
操作:
python
padding = (8 - len(s) % 8) % 8 # 计算 padding
decoded = base64.b32decode(s + '=' * padding).decode('utf-8')
结果:
- 解码后长度:800 字符
- 压缩比:1.6:1
- 新密文特征:包含大小写字母、数字,可能是 Base64
Step 3: 第一次 Base64 解码
输入:Step 2 的结果(800 字符)
特征分析:
- ✅ 包含大小写字母和数字
- ✅ 长度能被 4 整除(800 % 4 = 0)
- ✅ 符合 Base64 编码特征
判断 :这是Base64 编码
操作:
python
padding = (4 - len(s) % 4) % 4
decoded = base64.b64decode(s + '=' * padding).decode('utf-8')
结果:
- 解码后长度:600 字符
- 压缩比:1.33:1
- 仍然是 Base64 编码特征
Step 4-5: 连续 Base64 解码
继续对 Step 3 的结果进行 Base64 解码:
Step 4:
- 输入:600 字符
- 输出:448 字符
- 仍然是 Base64 编码
Step 5:
- 输入:448 字符
- 输出:336 字符
- 变化:不再符合标准 Base64 特征
Step 6: Base32 解码(关键转折)
输入:Step 5 的结果(336 字符)
特征分析:
- ✅ 只包含大写字母和部分数字(2-7)
- ❌ 长度不能被 4 整除(336 % 4 = 0,但字符集不符合 Base64)
- ✅ 符合 Base32 特征
判断 :切换回Base32 编码
操作:
python
padding = (8 - len(s) % 8) % 8
decoded = base64.b32decode(s + '=' * padding).decode('utf-8')
结果:
- 解码后长度:208 字符
- 仍然是 Base32 编码特征
Step 7: 再次 Base32 解码
输入:Step 6 的结果(208 字符)
操作:继续使用 Base32 解码
结果:
- 解码后长度:128 字符
- 变为 Base64 编码特征
Step 8-11: 交替解码
按照以下顺序继续解码:
| 步骤 | 编码类型 | 输入长度 | 输出长度 | 压缩比 |
|---|---|---|---|---|
| 8 | Base64 | 128 | 96 | 1.33:1 |
| 9 | Base32 | 96 | 56 | 1.71:1 |
| 10 | Base64 | 56 | 40 | 1.4:1 |
| 11 | Base32 | 40 | 23 | 1.74:1 |
Step 12: 发现 Flag
输入:Step 11 的结果(23 字符)
检查结果:
python
if 'flag{' in current.lower():
print("✓ 找到 Flag!")
💻 完整解题代码
python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import base64
from datetime import datetime
def analyze_string(s, step_name=""):
"""分析字符串的特征信息"""
print(f"\n{'='*70}")
print(f"[{step_name}] 字符串特征分析")
print('='*70)
# 基本信息
print(f"长度:{len(s)} 字符")
print(f"长度 % 4: {len(s) % 4} (Base64 要求)")
print(f"长度 % 8: {len(s) % 8} (Base32 要求)")
# 字符集分析
unique_chars = sorted(set(s.replace('=', '')))
char_set = ''.join(unique_chars)
print(f"\n唯一字符数:{len(unique_chars)}")
print(f"字符集:{char_set[:50]}{'...' if len(char_set) > 50 else ''}")
# 字符类型
has_upper = any(c.isupper() for c in s)
has_lower = any(c.islower() for c in s)
has_digit = any(c.isdigit() for c in s)
has_only_hex = all(c in '0123456789ABCDEFabcdef' for c in s.replace('=', ''))
has_only_b32 = all(c in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567' for c in s.replace('=', ''))
print(f"\n包含大写字母:{'是' if has_upper else '否'}")
print(f"包含小写字母:{'是' if has_lower else '否'}")
print(f"包含数字:{'是' if has_digit else '否'}")
print(f"\n编码匹配:")
print(f" Hex: {'✓' if has_only_hex else '✗'}")
print(f" Base32: {'✓' if has_only_b32 else '✗'}")
print(f" Base64: {'✓' if (has_upper or has_lower or has_digit) else '✗'}")
def try_decode_hex(s):
try:
return bytes.fromhex(s).decode('utf-8')
except:
return None
def try_decode_b32(s):
try:
clean = s.replace('=', '')
pad = (8 - len(clean) % 8) % 8
return base64.b32decode(clean + '=' * pad).decode('utf-8')
except:
return None
def try_decode_b64(s):
try:
pad = (4 - len(s) % 4) % 4
return base64.b64decode(s + '=' * pad).decode('utf-8')
except:
return None
def solve():
start_time = datetime.now()
print("="*70)
print("CTF 题目:这是什么编码 - 详细解题过程")
print("="*70)
# 读取密文
with open('encode.txt', 'r') as f:
current = f.read().strip()
step = 0
path = []
while step < 50:
step += 1
# 检查 Flag
if 'flag{' in current.lower():
print(f"\n{'='*70}")
print("🎉 成功找到 Flag! 🎉")
print(f"{'='*70}")
print(f"步数:{step}")
print(f"路径:{' -> '.join(path)}")
print(f"\nFlag: {current}")
break
# Step 1: Hex
if step == 1:
result = try_decode_hex(current)
if result:
path.append("Hex")
current = result
analyze_string(current, "Step 1 - Hex 解码后")
continue
# 尝试 Base32
result = try_decode_b32(current)
if result:
path.append("Base32")
current = result
analyze_string(current, f"Step {step} - Base32 解码后")
continue
# 尝试 Base64
result = try_decode_b64(current)
if result:
path.append("Base64")
current = result
analyze_string(current, f"Step {step} - Base64 解码后")
continue
break
end_time = datetime.now()
print(f"\n耗时:{(end_time - start_time).total_seconds():.2f} 秒")
if __name__ == '__main__':
solve()
🎓 经验总结
1. 编码识别技巧
| 编码类型 | 快速识别方法 |
|---|---|
| Hex | 只有 0-9 和 A-F,长度偶数 |
| Base32 | 只有 A-Z 和 2-7,可能有等号 |
| Base64 | 有大小写字母、数字,可能有+/和等号 |
📌 工具推荐
在线工具
- CyberChef: https://gchq.github.io/CyberChef/
- Base64 在线解码: https://www.base64decode.org/
- 多编码识别: https://www.dcode.fr/cipher-identifier