当前位置: 首页 > news >正文

python反序列化总结_Python 反序列化安全问题(二)

python pickle允许类定义__reduce__方法来声明如何进行序列化。其返回字符串或者tuple,前者可能代表着一个python的全局变量的名称,后者则是描述在反序列化过程中如何进行重构。安全问题也是主要出在后者,本文主要针对于该情况进行pickle模块源码分析。

一、源码分析

代码结构可以分为:基础变量、自定义异常类、操作变量、序列化以及反序列化类以及普通函数。

1.1 基础变量

代码(28-57行)最先定义了部分变量,如最高协议号还有代码中使用了struct.pack()以及marshal.loads()进行序列化和反序列化,并且解释了为何用这两个函数。

1.2 自定义异常类

代码(59-85行)中自定义了4个异常类,分别为PickleError、PicklingError、UnpicklingError以及_Stop.

PickleError:PickingError和UnpicklingError的基类

PicklingError:序列化过程中异常

UnpicklingError:反序列化过程中异常

_Stop:在反序列化过程中结尾处触发该异常

1.3 操作变量

代码(99-126行)定义了操作变量,我们可以理解为操作指令,每一个变量都对应着相关操作,这些指令在序列化的过程中写入,然后在反序列化过程中读取进行对应操作;我们主要理解如下操作指令。

c:读取新的一行作为模块名module,读取下一行作为对象名object,然后将module.object压入到堆栈中。

p:将堆栈中索引为-1的对应存储入内存。

(:将一个标记对象插入到堆栈中。

t:构建元组压入堆栈。

S:读取字符串进行处理之后压入堆栈。

R:将一个元组和一个可调用对象弹出堆栈,然后以该元组作为参数调用该可调用的对象,最后将结果压入到堆栈中。

.:调用_Stop结束反序列化。

1.4 序列化以及反序列化类

代码定义了Pickler和Unpickler类,这两个类是pickle模块进行序列化反序列化的核心,下面看其实现过程:

1.4.1 序列化过程

dumps函数接收参数后首先进行Pickler类的初始化,然后调用类中的dump函数进行序列化。

dump()函数首先调用save函数,save函数可以看做字典类型调度器,key为需要进行序列化的对象的type,value为对应type的存储函数名。例如如果序列化对象为[1, 2, 3],也就是list类型,save函数判断完类型之后,在调度器内查找对应的方法save_list,然后调用结束后将结果写入内存中,最后dump函数写入结束符号完成整个序列化过程。

如果上一步查询调度器并没有查询到对应的方法,即对象的type不在NoneType/bool/builtin/classobj/dict/float/function/instance/int/list/long/str/tuple/type/unicode这些类型中的时候,首先查看是否存在__reduce_ex__,如果存在则不再查找__reduce__,不存在的话则继续查找__reduce__;进而判断该函数返回值是string还是tuple,前者进入save_global;后者进入危险开始的save_reduce函数。

save_reduce会将__reduce__返回的tuple结果,调用save_tuple方法进行序列化存储

测试代码

import os

class A():

def __reduce__(self):

a = 'whoami'

return (os.system, (a,))

print type(A)

print dumps(A)

print type(A())

print dumps(A())

class B(object):

def __reduce__(self):

a = 'whoami'

return (os.system, (a,))

print type(B)

print dumps(B)

print type(B())

print dumps(B())

测试结果:

c__main__

A

p0

.

(i__main__

A

p0

(dp1

b.

c__main__

B

p0

.

cnt

system

p0

(S'whoami'

p1

tp2

Rp3

.

上述结果可以看出如果我们要达到执行任意代码的目的,需要使用的是第四种即dumps(B())才能进入到save_reduce方法,前三种只能调用save_global方法,只是对于命名引用进行序列化,所以也只能使用于相同环境中,否则在反序列化的过程中会报错。

1.4.2 反序列化过程

反序列化和序列化的过程挺相似,按字节读取然后在调度器中查找对应的处理函数;上面我们提到过一些操作指令,反序列化的调度器中将上述的操作指令作为key,处理函数作为value,此处主要分析上述最后一个实例的反序列化过程。

序列化的结果:

cnt

system

p0

(S'whoami'

p1

tp2

Rp3

.

反序列化过程:

读取第一个字符c,查询调度器,对应的方法为load_global;

调用load_global,读取该行将该行后面nt作为模块名,下一行system作为方法名,两者作为参数进入find_class;

find_class的目的就是返回nt.system方法,然后将返回结果压入堆栈中;该方法的代码如下所示:

def find_class(self, module, name):

__import__(module)

mod = sys.modules[module]

klass = getattr(mod, name)

return klass

继续读取字节p,调用load_put,load_put从堆栈中获取最后一个对象,放入内存中,p后面的数字,为key;

继续读取字节(,调用load_mark,将object()压入堆栈;

继续读取字节S,调用load_string,将'whoami'去除" '压入堆栈;

到目前堆栈中有3个对象,分别为nt.system、object()、whoami;继续读取p,将whoami存储到内存中,key为1;

读取字节t,调用load_tuple,其首先调用marker获取object()的索引号,此处为1,然后将stack[1:]变为('whoami',),也就是说执行完这一步操作之后,堆栈中只有nt.system和('whoami',);

读取字节p,调用load_put,将('whoami',)存储如内存,key为2,;

读取字节R,调用load_reduce,运行nt.system('whoami'),得出结果之后赋值给堆栈索引为-1;

读取p,调用load_put,将结果存储到内存;

读取.,即结束符号,清空堆栈,结束反序列化。

总结

序列化以及反序列化其实是给每种能够识别出来的类型的对象一个既定的方式去进行序列化或者反序列化,如果碰到不认识的,那就去查找__reduce__,将其序列化,然后在根据它去进行反序列化过程中的重构;

从上面的分析过程中可以看出,如果我们要在反序列化的过程中去执行命令,就要满足在序列化的时候能执行save_reduce,然后在反序列化的过程中才能执行load_reduce,进而执行命令;

相关文章:

  • python可以用于工业机器人编程与操作_如何实现工业机器人编程抓取
  • 前后落差大用什么词语_被双子座追到手,你能忍受恋爱前后的反差吗?
  • sheet中没有getcolumns()方法吗_Excel中Enter键使用技巧,这5种方法你都知道吗
  • 淮北市第四届机器人比赛_科技引领 | 沧浪中学承办2020年第四届苏州市青少年人工智能挑战赛...
  • 汽车人机工程学_7万块的国产宝骏530还想跟我谈人机工程学?
  • python干什么工作轻松点_学完Python能做什么工作?
  • 四参数坐标转换c++_写给测绘新手,四参数与七参数坐标转换含义及区别
  • nacos 配置不会动态刷新_真香系列:聊聊SpringCloud Nacos服务配置中心
  • eclipse配置python解析器_python编辑器:Eclipse PyDev安装的步骤解析
  • python生成列表作为全局列表_如何在python中定义全局列表
  • 如何保存十个以上配方_“前男友”放冰箱,配方师听了都流泪......
  • angular js创建表单_Angular-Formly:在用户单击时动态添加表单字段
  • 起始方位角怎么确定_起始方位角.PPT
  • ue4加载本地图片_ue4 C++ 导入图片
  • python爬虫类型_python爬虫主流存储类型实战
  • Angular数据绑定机制
  • Java IO学习笔记一
  • niucms就是以城市为分割单位,在上面 小区/乡村/同城论坛+58+团购
  • node.js
  • php中curl和soap方式请求服务超时问题
  • 关于Java中分层中遇到的一些问题
  • 模型微调
  • 配置 PM2 实现代码自动发布
  • 容器化应用: 在阿里云搭建多节点 Openshift 集群
  • 什么是Javascript函数节流?
  • 为什么要用IPython/Jupyter?
  • 一加3T解锁OEM、刷入TWRP、第三方ROM以及ROOT
  • 再谈express与koa的对比
  • 3月7日云栖精选夜读 | RSA 2019安全大会:企业资产管理成行业新风向标,云上安全占绝对优势 ...
  • #免费 苹果M系芯片Macbook电脑MacOS使用Bash脚本写入(读写)NTFS硬盘教程
  • #我与Java虚拟机的故事#连载18:JAVA成长之路
  • #中国IT界的第一本漂流日记 传递IT正能量# 【分享得“IT漂友”勋章】
  • (Matalb分类预测)GA-BP遗传算法优化BP神经网络的多维分类预测
  • (ZT) 理解系统底层的概念是多么重要(by趋势科技邹飞)
  • (板子)A* astar算法,AcWing第k短路+八数码 带注释
  • (超简单)构建高可用网络应用:使用Nginx进行负载均衡与健康检查
  • (超详细)语音信号处理之特征提取
  • (动态规划)5. 最长回文子串 java解决
  • (多级缓存)多级缓存
  • (二)c52学习之旅-简单了解单片机
  • (二)丶RabbitMQ的六大核心
  • (附源码)spring boot建达集团公司平台 毕业设计 141538
  • (附源码)springboot“微印象”在线打印预约系统 毕业设计 061642
  • (蓝桥杯每日一题)love
  • (学习日记)2024.03.25:UCOSIII第二十二节:系统启动流程详解
  • (一)为什么要选择C++
  • (转)EXC_BREAKPOINT僵尸错误
  • (转)IIS6 ASP 0251超过响应缓冲区限制错误的解决方法
  • (转)IOS中获取各种文件的目录路径的方法
  • .net 4.0 A potentially dangerous Request.Form value was detected from the client 的解决方案
  • .NET 回调、接口回调、 委托
  • .NET 中选择合适的文件打开模式(CreateNew, Create, Open, OpenOrCreate, Truncate, Append)
  • .NET版Word处理控件Aspose.words功能演示:在ASP.NET MVC中创建MS Word编辑器
  • .net和jar包windows服务部署
  • .NET开发不可不知、不可不用的辅助类(一)