sir

Pickle 反序列化漏洞分析

序列化与反序列化基础

我们知道各大语言都有其序列化数据的方式,Python当然也有,官方库里提供了一个叫做pickle/cPickle的库,这两个库的作用和使用方法都是一致的,只是一个用纯py实现,另一个用c实现而已。使用起来也很简单,基本和PHP的serialize/unserialize方法一样:

同样pickle可以序列化python的任何数据结构,包括一个类,一个对象:

但我们发现序列化的字符串中并没有A类的a,b属性的值,因为序列化存储的是对象的数据,而不是类的数据, 我们在构造函数中用self添加一个对象的成员数据

可以看到序列化字符串中多了一个(dp5\nS'c'\np6\nS'test'\np7\nsb 的数据,就是我们存储的成员数据

继承object和不继承的区别

demo: 继承object类

demo2 : 不继承object

__reduce__

官方文档中说过,pickle是个不安全的模块,永远别去反序列化不信任的数据。

这一切都是因为reduce 魔术方法,它在序列化的时候会完全改变被序列化的对象,这个方法相当的强大,官方建议不要直接操作这个方法,用更高级的接口 getnewargs(), __getstate() and setstate() 等代替。

这个方法有两种返回值方式:

如果返回值是一个字符串,那么将会去查找字符串值对应名字的对象,将其序列化之后返回。
如果返回值是元组(2到5个参数),第一个参数是可调用(callable)的对象,第二个是该对象所需的参数元组,剩下三个可选。
第一种方式先暂且不谈,重要的是第二种方式,看下面例子:

 但该模式方法需要继承object类

我们利用reduce做一个测试:

成功执行了我们的代码

我们来理解一下发生了什么:
1. 我们将恶意代码插入一个对象中,并将其序列化,得到字节序列

从字节序列我们就能看出来,序列化之后的数据已经完全和Test类没有关系,只剩下了os.system和参数了

  1. 我就着pickle模块看了一下,发现它是基于词法和语法分析(想想编译原理)来完成解析的,对每一个字符都注册相应的处理函数,挨个分析,分行读取处理(所以你会看到那么多 \n),最后在 R 标志符的时候执行调用操作

防御

对于 pickle ,我觉得可以尝试去为Unpickler 添加一个自己写的装饰器,HOOK刚刚的 load_reduce 函数 ,用白名单的思想去解决。

HITBCTF 2018 Python's revenge

这里考察的就是pickle发序列化的问题,我们可以控制反序列化的内容,就可以直接构造__reduce__魔术方法任意命令执行

但这里加了一个hook函数对callback进行过滤,然后用的确实黑名单,我们可以用map函数去绕过黑名单的限制

思路:

  1. 访问/reminder生成location, 本地爆破secret
  2. 利用map函数绕过黑名单任意命令执行

直接上脚本了:

没有回显的命令执行,直接用weblog方式带出来

image.png

总结:

  1. Pickle反序列化知识之前没太深入了解,但通过看了很多资料最后还是成功做出了这题,CTF如果出现了你不了解的知识,可以先去看各种资料大概了解后再去做题,这才是CTF的魅力,也是CTFer需要掌握的本领
  2. 本地复现环境很重要。

参考:

https://blog.csdn.net/yanghuan313/article/details/65010925

喜欢 0