首先提出payload,然后了解大致思路以后,了解一下这几个python中的所用到的几个魔术方法
flask中的最基础的模板注入:
[].__class__.__base__.__subclasses__()[80].__init__.__globals__['__builtins__']['__import__']('os').popen('whoami').read()
首先说一下大致思路,然后逐一看一下这些魔术方法都代表什么
- 我们可以通过普通数据类型的
__class__
成员属性得到所属类, - 再通过
__bases_
或__base__
或__mro__
可以得到object类 - 再次通过
__subclasses__()
来得到object下的所有基类 - 遍历所有基类检查是否存在指定的魔术方法,比如
__init__
或者__delete__
等,如果存在,那么即可获取__globals__['__builtins__']
,就可以调用任意函数了.
__class__
- 一个实例调用
__class__
属性时会指向该实例对应的类
我们都知道再python里面,所有的数据类型都存放在Object
这一个大类中,其中还包括int,str,dict等
__base__
,__bases__
,__mro__
首先我们运行一下这三个就知道了:
可以看到
__base__
内置类属性将打印类对象的基类__bases__
内置类属性将打印类对象的基类的元组__mro__
它是一个tuple, 装着方法解析时的对象查找顺序,越靠前的优先级越高
ps:在OOP(面对对象编程)程序设计中,当我们定义一个class的时候,可以从某个现有的class继承,新的class称为子类(Subclass),而被继承的class称为基类、父类或超类(Base class、Super class)
__subclasses__
- 获取Object下的所有子类:
__globals__
- 以字典的形式返回函数所在的全局命名空间所定义的全局变量。
__globals__
就是globals()
函数的返回值
例如我们在新开打开python里先定义一个函数,然后看一下全局变量
因为__globals__
返回的是函数所在的全局命名空间所定义的全局变量,所以我们才要在基类检查是否存在函数,一般基类中都存在__init__
初始化的魔术方法,所以我们可以找到有__init__
的基类,当然其他的也可以,然后使用函数找到全局变量中的__builtins__
__builtins__
我们在启动python而没有导入任何包时,依然可以使用一些函数,例如eval()
, hex()
, char()
等,这些函数被称为内建函数,都保存在__builtins__
。Python在启动时就直接为我们导入了。
有了__builtins__
,我们就可以调用其中的方法了。
__import__
这个我在之前的博客中也提到了
- 如果一个模块经常变化就可以使用
__import__()
来动态载入
例如:__import__('os').popen('whoami').read()
__import__('requests').get('https://yuaneu.ro')