pickle是python中用来进行序列化和反序列化的模块,pickle.dumps()可以将对象序列化字符串,而pickle.loads()可以将字符串序列化成对象,pickle不仅可以读写字符串,也可以读写文件:只需要采用pickle.dump()pickle.load()

常规手段

简单利用反序列化漏洞是通过class的reduce方法,这个方法在pickle反序列化的时候会被自动执行,reduce干了这样一件事情:

  • 取当前栈的栈顶记为args,然后把它弹掉。
  • 取当前栈的栈顶记为f,然后把它弹掉。
  • 以args为参数,执行函数f,把结果压进当前栈。

简单说来就是reduce把返回的元组的第一个元素作为函数,第二个元素作为函数的参数来执行这个函数。一种非常流行的攻击方式就是返回一个恶意元组。

1
2
def __reduce__(self):
return (os.system,("ls /"))

其底层的编码方法就是利用了R指令码,要么返回一个字符串,要么返回一个元组,后者对我们而言更有用。

reduce函数bypass

有一种过滤方式,没有进制R指令码,但是对R执行的函数有黑名单限制

面对这种题,一种思路是找到黑名单的漏网之鱼,另一种思路是利用map来逃避黑名单限制,与命令执行的利用GET逃避限制异曲同工。

1
2
3
class Exploit(object):
def __reduce__(self):
return map,(os.system,["ls"])

map函数通常不会被黑名单禁止,成功绕过,而对函数有黑名单限制,并没有对参数进行黑名单限制,从而成功执行命令。

顺便一提,map函数的用法是,第一个参数为function,第二个参数是一个可迭代对象,列表,元组,字典都可以,以可迭代对象中的每一个成员作为参数调用function。

参考

从零开始python反序列化攻击:pickle原理解析 & 不用reduce的RCE姿势