web安全-Pickle反序列化
详解:https://zhuanlan.zhihu.com/p/89132768
1.相关函数
1 | pickle.dump(obj, file) :将对象序列化后保存到文件。#注:这里的file需要以wb打开(二进制可写模式) |
2.Python魔术方法
1 | __reduce__() :反序列化时调用。 |
3.PVM(Python虚拟机)
生成操作码序列 : pickle模块在序列化Python对象时,会生成一系列操作码(opcode)来表示对象的类型和值
反序列化操作码 : 在反序列化时,pickle模块读取操作码序列,并将其解释为Python对象
执行操作码
构造Python对象
4.opcode
通过对opcode的编写可以进行Python代码执行、覆盖变量等操作。直接编写的opcode灵活性比使用pickle序列化生成的代码更高,并且有的代码不能通过pickle序列化得到
常用的opcode:
指令 | 描述 | 具体写法 | 栈上的变化 |
---|---|---|---|
c | 取一个全局对象或import一个模块 | c[module]\n[instance]\n | 获得的对象入栈 |
o | 寻找栈中的上一个MARK,以之间的第一个数据(必须为函数)为callable,第二个到第n个数据为参数,执行该函数(或实例化一个对象) | o | 这个过程中涉及到的数据都出栈,函数的返回值(或生成的对象)入栈 |
i | 相当于c和o的组合,先获取一个全局函数,然后寻找栈中的上一个MARK,并组合之间的数据为元组,以该元组为参数执行全局函数(或实例化一个对象) | i[module]\n[callable]\n | 这个过程中涉及到的数据都出栈,函数返回值(或生成的对象)入栈 |
N | 实例化一个None | N | 获得的对象入栈 |
S | 实例化一个字符串对象 | S’xxx’\n(也可以使用双引号、'等python字符串形式) | 获得的对象入栈 |
V | 实例化一个UNICODE字符串对象 | Vxxx\n | 获得的对象入栈 |
I | 实例化一个int对象 | Ixxx\n | 获得的对象入栈 |
F | 实例化一个float对象 | Fx.x\n | 获得的对象入栈 |
R | 选择栈上的第一个对象作为函数、第二个对象作为参数(第二个对象必须为元组),然后调用该函数 | R | 函数和参数出栈,函数的返回值入栈 |
. | 程序结束,栈顶的一个元素作为pickle.loads()的返回值 | . | 无 |
( | 向栈中压入一个MARK标记 | ( | MARK标记入栈 |
t | 寻找栈中的上一个MARK,并组合之间的数据为元组 | t | MARK标记以及被组合的数据出栈,获得的对象入栈 |
) | 向栈中直接压入一个空元组 | ) | 空元组入栈 |
l | 寻找栈中的上一个MARK,并组合之间的数据为列表 | l | MARK标记以及被组合的数据出栈,获得的对象入栈 |
] | 向栈中直接压入一个空列表 | ] | 空列表入栈 |
d | 寻找栈中的上一个MARK,并组合之间的数据为字典(数据必须有偶数个,即呈key-value对) | d | MARK标记以及被组合的数据出栈,获得的对象入栈 |
} | 向栈中直接压入一个空字典 | } | 空字典入栈 |
p | 将栈顶对象储存至memo_n | pn\n | 无 |
g | 将memo_n的对象压栈 | gn\n | 对象被压栈 |
0 | 丢弃栈顶对象 | 0 | 栈顶对象被丢弃 |
b | 使用栈中的第一个元素(储存多个属性名: 属性值的字典)对第二个元素(对象实例)进行属性设置 | b | 栈上第一个元素出栈 |
s | 将栈的第一个和第二个对象作为key-value对,添加或更新到栈的第三个对象(必须为列表或字典,列表以数字作为key)中 | s | 第一、二个元素出栈,第三个元素(列表或字典)添加新值或被更新 |
u | 寻找栈中的上一个MARK,组合之间的数据(数据必须有偶数个,即呈key-value对)并全部添加或更新到该MARK之前的一个元素(必须为字典)中 | u | MARK标记以及被组合的数据出栈,字典被更新 |
a | 将栈的第一个元素append到第二个元素(列表)中 | a | 栈顶元素出栈,第二个元素(列表)被更新 |
e | 寻找栈中的上一个MARK,组合之间的数据并extends到该MARK之前的一个元素(必须为列表)中 | e | MARK标记以及被组合的数据出栈,列表被更新 |
5.漏洞利用
常出现位置:
通常在解析认证token, session的时候. 现在很多Web服务都使用redis、mongodb、memcached等来存储session等状态信息
可能将对象Pickle后存储成磁盘文件
可能将对象Pickle后在网络中传输
利用opcode
例:
1 | opcode=b'''cos |
详解:
1 | cos |
也可以使用picker:https://github.com/eddieivan01/pker
利用魔术方法(__reduce__()
)
反序列化后产生的对象会在结束时触发__reduce__()
函数从而触发恶意代码
__reduce__()
类似于php中的__wakeup()
魔术方法
- 构造payload:利用
os.system()
或者os.popen()
这两个函数只有以print输出时才会回显,如果是以return返回的就不会显示结果。
不能回显,可以将执行结果接入一个文件,再访问:
1 | import os |
- 反弹shell:
1 | import os |
注:不同操作系统pickle反序列化结果有略微差别,所以需要根据环境决定在哪里序列化出字符串
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 YTM's Blog!
评论