利用的关键点就是如何构造我们的反序列化的payload ,这个时候不得不提到
__reduce__
官方介绍 reduce
当序列化 以及反序列化的过程中 碰到一无所知的扩展类型的时候。就可以通过类中定义的 reduce 方法来告知如何进行序列化 或者反序列化
也就是说 只要在这个新式类中 定义一个reduce方法 我们就能在序列化 的使用让 这个类根据我们在 reduce 中指定的方式序列化 那这就非常好
那我们该如何指定呢?实际上关键就在这个方法的返回值上,这个方法可以返回两种类型的值,String 和 tuple ,我们的构造点就在令其返回 tuple 的时候
当他返回值是一个元祖的时候,可以提供2到5个参数,我们重点利用的是前两个,第一个参数是一个callable object(可调用的对象),第二个参数可以是一个元祖为这个可调用对象提供必要的参数,
PVM 操作码
pvm操作码 都是单字节的
s操作码 代表后面这一串 是字符串 V操作码 代表后面这一串是 unicode 编码 I 操作码 代表 后面这一串是整数
这里面比较重要的是 ( ,它相当于 做个标记
上面的 ( 标记 ,与 l t d s 结合使用 ,就可以将两个 标记中的元素取出来 放入栈 中 d 表示 字典 l 表示这个元素 是个列表 而t 代表 是个元组
举个简单的例子
(s'/bin/sh' t
就是说 先下个标记 然后把 字符串 /bin/sh 放入栈中 然后遇到 t 之后 就会从 栈上弹出数据 一直弹到 ( , 也就是 将 ( 到 t 的 内容 全部弹出来 转化成元组 再存入栈中,同时标记消失
c 指令 后面 跟的是模块 名 和类名 这俩之间用回城 作为分割
而R
指令一般都在最后,它会将元组和可调用的对象callable
从堆栈中弹出来
后以该元组作为参数调用该callable
对象,比如说os.system()
中的system()
就是一个callable
对象
. 点号 是结束符 执行到这里代表 结束
例子
cos //c指令 后面跟得到是模块名和 类名
system
(S'/bin/ls /' //从( 开始标记 然后 到 t 结束
t R.//`R`指令一般都在最后,它会将元组和可调用的对象`callable`从堆栈中弹出来 . 点号 是结束符 执行到这里代表 结束
标签:标记,python,reduce,元组,callable,操作码,序列化
From: https://www.cnblogs.com/kkkkl/p/16755368.html