首页
课程
问答
CTF
社区
招聘
峰会
发现
排行榜
知识库
工具下载
看雪20年
看雪商城
证书查询
登录
注册
首页
社区
课程
招聘
发现
问答
CTF
排行榜
知识库
工具下载
峰会
看雪商城
证书查询
社区
CTF对抗
发新帖
0
0
[原创]第二题:巳时·绿光幽语 — 解题 Writeup
发表于: 2026-8-11 12:29
10
[原创]第二题:巳时·绿光幽语 — 解题 Writeup
新用互名
2026-8-11 12:29
10
## 1. 题目概览、授权目标与已知条件 - 题目类型:reverse - 附件:`/workspace/attachments/题目/题目.exe`(PE32+ console,x86-64,约 7.4 MB) - SHA256:`f6b192f9ee87c4ad2bc8681291ca428cf8e98fec26fa5d7b82c6e791a7a90ead` - 题目描述(故事向):终端屏幕泛绿光,显示一段记忆碎片;"文件分段加密:古典密码、时间戳算法、硬件密钥。三段必须同步解密,否则自毁";"硬件密钥被拆成十六个碎片,分散在十六个存储扇区"。 - 操作员补充提示:需要还原的代码为 ```python def my_function(): print("恭喜成功!") ``` "请输入key还原代码(请输入6个字符)"——即需要找出一个 6 字符的 key。 - 授权目标:仅分析 `/workspace` 下的题目附件,不访问外部目标。预期 Flag 格式未在平台配置中给出。 ## 2. 初步判断与关键假设 1. 附件是 PyInstaller 打包的 Python 3.13 程序(`.fptable` 等节名、`pyi-*` 引导字符串、DLL 尾部 `MEI` cookie)。 2. 程序入口 `main.pyc` 直接 `sys.exit(0)`,说明真正的挑战逻辑不在入口脚本,而是隐藏在某个被冻结/打包的组件里(经典"藏逻辑"手法)。 3. 按操作员提示,存在一个"输入 6 字符 key 还原代码"的程序;最可能藏在 PyInstaller 冻结进 `python313.dll` 的 Python 模块中(Python 3.13 的 PyInstaller 会把 `os` 等基础模块冻结进 python DLL)。 ## 3. 可复现的分析步骤(按时间顺序) ### 3.1 附件盘点与去壳识别 ```bash file 题目.exe # PE32+ executable (console) x86-64, 7 sections strings -a 题目.exe | grep -iE "pyi-|MEI|python313" ``` 发现 `pyi-`、`Py_DecodeLocale` 等 PyInstaller 引导字符串 → 判定为 PyInstaller 打包,且入口极小。 ### 3.2 PyInstaller 解包 - 用官方 `pyinstxtractor.py`(在 Python 3.13 下运行)解包: ``` python3.13 pyinstxtractor.py 题目.exe [+] Python version: 3.13 [+] Found 21 files in CArchive [+] Found 112 files in PYZ archive [+] Possible entry point: main.pyc ``` - 关键产物(`/workspace/artifacts/题目.exe_extracted/`): - `main.pyc`:175 字节,反汇编后仅为 `import sys; sys.exit(0)`,是"假入口"。 - `python313.dll`(7.1 MB)、`base_library.zip`、`PYZ.pyz`(112 个标准库 pyc)等。 - PYZ 中全部为标准库模块,无自定义模块 → 挑战逻辑不在 PYZ。 ### 3.3 定位隐藏的挑战代码 - 在整个解包目录中搜索提示字符串,命中: ``` my_function: 题目.exe_extracted/python313.dll ``` - 在 `python313.dll` 中 `0x4dace9` 附近发现 `my_function`、`b_key`、`buf`、`range`、`__code__`、`replace`、`succ`、`co_code`、`co_consts`、`input`、`Exception` 等名字——这是一段被冻结进 python DLL 的 Python 模块代码(内容为修改过的 `os` 模块,作者在其中植入了挑战逻辑)。 - 通过 VA 指针扫描找到 DLL 内冻结模块表(`_PyImport_FrozenModules`,位于 0x4bc220),其中: ``` name='os' code_off=0x4d00e0 size=47420 ``` ### 3.4 反序列化冻结 os 模块并反汇编 ```python import marshal dll = open('python313.dll','rb').read() code = marshal.loads(dll[0x4d00e0:0x4d00e0+47420]) # 用 Python 3.13 ``` - 模块 `co_name == '<module>'`,`co_filename == '<frozen os>'`。 - 反汇编模块尾部(行 1185-1229)还原出挑战伪代码: ```python for x in range(20): # 最多 20 次尝试 def my_function(): # 当前内容: print(666) print(666) buffer = b''.join([...8段16字节加密数据...]) # consts[145] w = b'' for i in buffer: w += (i ^ 85).to_bytes(1) print(w.decode('utf-8')) # 打印提示(见下) key = input() # 请输入6个字符 if len(key) != 6: continue b_key = key.encode() c = b'\xecbmucryb6tcr*c\x03ucryb6tCr\x1eb' # consts[149] 加密co_code buf = b'' for i in range(len(c)): buf += (c[i] ^ b_key[i % 6]).to_bytes(1) # XOR 解密 my = my_function.__code__.replace(co_code=buf) succ = b'\x9f\xe3\x9b\x91\xf5\xee\x9f\xea\xa6\x91\xe9\xed\x96\xde\xb7' # consts[151] buf = b'' for i in range(len(succ)): buf += (succ[i] ^ b_key[i % 6]).to_bytes(1) my = my.replace(co_consts=(None, buf.decode('utf-8'))) my_function.__code__ = my try: my_function() # key 正确 → 打印 "恭喜成功!" except Exception: continue # key 错误 → 重试 ``` - 提示文字验证:`b''.join(consts[145])` 每字节 XOR 85 后按 UTF-8 解码,正是操作员给的提示: ``` 提示,需要还原的代码 def my_function(): print("恭喜成功!") 请输入key还原代码(请输入6个字符) ``` ### 3.5 求解 6 字符 key(核心) 加密方式为逐字节 XOR 循环 6 字节 key: ``` restored[i] = enc[i] ^ key[i % 6] ``` 两处密文 + 已知明文: 1. `consts[151]`(15 字节)解密后为 `co_consts` 中的目标字符串 `"恭喜成功!"`(UTF-8,15 字节): ``` key = consts[151] ^ "恭喜成功!".encode('utf-8') = "yb6tcr" ``` 2. 用 `key="yb6tcr"` 解密 `consts[149]`(26 字节)得到完整合法的 3.13 字节码: ``` 95005b0100000000000000005301350100000000000020006700 = RESUME 0; LOAD_GLOBAL print; LOAD_CONST 1; CALL 1; POP_TOP; RETURN_CONST 0 ``` 与 `def my_function(): print("恭喜成功!")` 编译产物完全一致。 两条路径独立推导出同一个 key:**`yb6tcr`**(y b 6 t c r)。 ### 3.6 端到端验证(本机 Python 3.13.15) 运行 `/workspace/artifacts/solve.py`: ``` [+] key = yb6tcr [+] decrypted co_code = 95005b0100000000000000005301350100000000000020006700 [+] decrypted consts = 恭喜成功! --- 执行还原后的 my_function --- 恭喜成功! --- 执行成功 --- ``` 错误 key(如 `abcdef`、`000000`)解密出的字符串无法按 UTF-8 解码(或字节码非法),程序进入 `except Exception` 分支重试——与程序行为一致。 ## 4. 关键发现与证据 | 项目 | 位置 | 说明 | |---|---|---| | PyInstaller cookie | 题目.exe 0x717f0b | `MEI...`,python313.dll | | 冻结 os 模块 | python313.dll 0x4d00e0, 47420B | 含挑战逻辑 | | 加密 co_code | os 模块 co_consts[149] | `ec626d7563727962367463722a63037563727962367443721e62` | | 加密 consts 字符串 | os 模块 co_consts[151] | `9fe39b91f5ee9feaa691e9ed96deb7` | | 提示数据 | os 模块 co_consts[145] | 8×16B,XOR 0x55 → 提示文字 | | 恢复后的 key | 推导+双重验证 | **`yb6tcr`** | 产物: - `/workspace/artifacts/solve.py` — 一键求解+验证脚本 - `/workspace/artifacts/extract_challenge.py` — 解包与定位脚本 - `/workspace/artifacts/题目.exe_extracted/` — 完整解包结果 - `/workspace/artifacts/题目.exe_extracted/python313.dll` — 关键 DLL - `/workspace/artifacts/sec_*.bin` — 各 PE 节提取 - `/workspace/artifacts/icon_png_0.png`、`icon_view.png` — 资源图标(确认无隐写 flag) ## 5. 成功结果 - 恢复出的代码:`def my_function(): print("恭喜成功!")` - **6 字符 key(即本题答案):`yb6tcr`** - 按常见 CTF 约定,Flag 为:`flag{yb6tcr}` - 说明:平台未提供 Flag 验证器,`flag{}` 包装为行业惯例;key 本身已通过还原代码并输出"恭喜成功!"获得完整验证。 - 验证方式:`python3.13 /workspace/artifacts/solve.py`(见 3.6),输出 `恭喜成功!`。 ## 6. 风险与边界说明 - 仅分析了题目附件 `题目.exe` 及其解包内容,未访问任何外部网络目标。 - 参考资源:PyInstaller 官方 pyinstxtractor(GitHub extremecoders-re/pyinstxtractor)、CPython 3.13 源码(marshal 格式)、PyInstaller 源码(冻结模块结构),仅用于理解打包/反序列化格式。 - 未找到独立的外部 Flag 验证器,`flag{}` 包装未经平台确认;若平台需要裸 key 形式,请直接提交 `yb6tcr`。 ## exp ```python #!/usr/bin/env python3 # -*- coding: utf-8 -*- # 第二题:巳时·绿光幽语 — 求解脚本(在 /workspace/artifacts 下运行) # 依赖:解包后的 题目.exe_extracted/python313.dll 与 Python 3.13 import marshal import types DLL = '题目.exe_extracted/python313.dll' OS_CODE_OFF = 0x4d00e0 # 冻结 os 模块 code 偏移(来自 DLL 冻结模块表 0x4bc220) OS_CODE_SIZE = 47420 def xor_repeat(data: bytes, key: bytes) -> bytes: return bytes(data[i] ^ key[i % len(key)] for i in range(len(data))) def main(): with open(DLL, 'rb') as f: dll = f.read() code = marshal.loads(dll[OS_CODE_OFF:OS_CODE_OFF + OS_CODE_SIZE]) consts = code.co_consts my_function_code = consts[143] enc_code = consts[149] # 加密后的 co_code enc_str = consts[151] # 加密后的 co_consts 字符串 # 由目标字符串 "恭喜成功!" (UTF-8) 反推 key target = '恭喜成功!'.encode('utf-8') key = xor_repeat(enc_str, target)[:6] print('key =', key.decode()) # 验证:还原 co_code 与 co_consts new_code = xor_repeat(enc_code, key) new_str = xor_repeat(enc_str, key).decode('utf-8') print('co_code =', new_code.hex()) print('consts =', new_str) restored = my_function_code.replace(co_code=new_code) restored = restored.replace(co_consts=(None, new_str)) fn = types.FunctionType(restored, globals()) print('--- 执行还原后的 my_function ---') fn() # 输出:恭喜成功! print('--- 执行成功 ---') if __name__ == '__main__': main() ``` 实际脚本保存路径:`/workspace/artifacts/solve.py`(运行方式:`python3.13 /workspace/artifacts/solve.py`)。 ## 最终 Flag ```text flag{yb6tcr} ```
冰与火的战歌:Windows内核攻防实战高级班!从零到实战,融合AI与Windows内核攻防全技术栈,打造具备自动化能力的内核开发高手。
收藏
・
0
点赞
・
0
打赏
分享
分享到微信
分享到QQ
分享到微博
赞赏记录
参与人
雪币
留言
时间
查看更多
赞赏
×
1 雪花
5 雪花
10 雪花
20 雪花
50 雪花
80 雪花
100 雪花
150 雪花
200 雪花
支付方式:
微信支付
赞赏留言:
快捷留言
感谢分享~
精品文章~
原创内容~
精彩转帖~
助人为乐~
感谢分享~
最新回复
(
0
)
游客
登录
|
注册
方可回帖
回帖
表情
雪币赚取及消费
高级回复
返回
新用互名
3
发帖
0
回帖
0
RANK
关注
私信
他的文章
[原创]第二题:巳时·绿光幽语 — 解题 Writeup
10
关于我们
联系我们
企业服务
看雪公众号
专注于PC、移动、智能设备安全研究及逆向工程的开发者社区
看原图
赞赏
×
雪币:
+
留言:
快捷留言
为你点赞!
返回
顶部