> 文章列表 > SSTI模板注入小结

SSTI模板注入小结

SSTI模板注入小结

文章目录

  • 一、漏洞简述🍺
  • 二、flask模板注入🍺
  • 三、shrine(攻防世界)🍺
  • 四、SSTI注入绕过🍺

一、漏洞简述🍺

1、SSTI(Server-Side Template Injection,服务器端模板注入)指的是一种攻击技术,攻击者通过向服务器发送恶意代码,从而在服务器端执行任意代码并获取敏感信息,SSTI攻击通常发生在服务器端模板渲染引擎中,攻击者在模板中注入恶意代码,从而导致服务器端执行该代码

2、SSTI攻击的目标通常是使用模板引擎的Web应用程序,例如Flask、Django、Jinja2等,攻击者可以利用这些模板引擎的弱点,将恶意代码注入到模板中,然后将其发送到服务器执行

3、常见的SSTI攻击载荷如:

  • {{7*7}}:将会输出49,则存在SSTI
  • {{config}}:将会输出服务器端的配置信息

二、flask模板注入🍺

1、不同框架有不同的渲染模板

2、如:flask支持使用Jinja2来作为渲染引擎

  • Flask是一个Python Web框架,它使用Werkzeug工具箱和Jinja2模板引擎,它被设计成易于扩展和灵活的,并且可以很好地处理小到大的Web应用程序
  • Jinja2是一个Python模板引擎,它允许你以灵活和安全的方式构建HTML页面

3、flask的渲染方法有render_template和render_template_string两种,其中render_template_string则是用来渲染一个字符串的,SSTI与这个方法密不可分

三、shrine(攻防世界)🍺

1、弄个环境理清一下思路,开启环境访问,即发现一段源代码,Flask 框架

import flask
import osapp = flask.Flask(__name__)
app.config['FLAG'] = os.environ.pop('FLAG')@app.route('/')
def index():return open(__file__).read()@app.route('/shrine/')
def shrine(shrine):def safe_jinja(s):s = s.replace('(', '').replace(')', '')blacklist = ['config', 'self']return ''.join(['{{% set {}=None%}}'.format(c) for c in blacklist]) + sreturn flask.render_template_string(safe_jinja(shrine))if __name__ == '__main__':app.run(debug=True)

2、路由作用

route装饰器的作用是将函数与url绑定,如代码中就是当你访问http://61.147.171.105:57667/shrine的时候,flask会执行shrine函数

3、对代码简单分析

(1)、将环境变量中的FLAG值存储到应用程序对象的配置中,然后从环境变量中移除FLAG值:
app.config['FLAG'] = os.environ.pop('FLAG')

(2)、定义/shrine/路由处理函数,使用safe_jinja函数处理输入的模板字符串shrine,然后渲染模板并返回结果

s = s.replace('(', '').replace(')', '')
blacklist = ['config', 'self']
return ''.join(['{{% set {}=None%}}'.format(c) for c in blacklist]) + s

使用replace方法替换掉字符串中的左右括号,设置黑名单过滤config、self字符

最后一行代码负责将黑名单的东西遍历并设为空,即进行过滤

(3)、在Jinja模板语言中,{{…}}用于表示需要被替换的变量或执行的表达式,而{%…%}用于表示控制流语句,比如if、for、set等,因此,{{%…%}}就是将控制流语句转义,表示这部分内容不需要被替换,将控制流语句转义,即是使用{{%…%}}可以将一段Python代码作为字符串输出,而不会被解释器当成控制流语句执行,这样可以方便在模板中使用包含了Python语法的代码段

在这个代码中,{{% set {}=None%}}是用于定义一个变量,表示将黑名单中的变量设置为None,从而防止黑客利用这些变量进行注入攻击

(4)、就是将过滤后的变量进行渲染HTML页面并返回

return flask.render_template_string(safe_jinja(shrine))

4、操作过程

/shrine/目录下执行

在这里插入图片描述
由于黑名单的过滤,我们输入config的值为None

在这里插入图片描述

为了获取信息,可以读取例如current_app这样的全局变量,python的沙箱逃逸这里的方法是利用python对象之间的引用关系来调用被禁用的函数对象,有两个函数包含了current_app全局变量,url_forget_flashed_messages

利用{{url_for.__globals__}}注入

在这里插入图片描述

出现了**current_app**变量,**{{url_for.__globals__['current_app']}}**

在这里插入图片描述

**app** 变量为Flask应用程序实例

然后注入当前**app****config****{{url_for.__globals__['current_app'].config}}**

在这里插入图片描述

成功找到**flag**

利用**get_flashed_messages**注入的方法同步

同时,Flask的所有接口文档可参考:API — 烧瓶文档 (1.1.x) (palletsprojects.com)

参考学习文章:

  • 从零学习flask模板注入 - FreeBuf网络安全行业门户
  • [WesternCTF2018]shrine - 春告鳥 - 博客园 (cnblogs.com)

四、SSTI注入绕过🍺

1、出现以下情况的;

  • 过滤了敏感字符,如**eval**,**os**等
  • 过滤了中括号**[]、引号'"**
  • 过滤双下划线**__**
  • 删除built下的一些函数,不能执行命令存在
  • 过滤了**{{**

参考文章:SSTI注入绕过(沙盒逃逸原理一样) - 冬泳怪鸽 - 博客园 (cnblogs.com)

2、常见不同模板引擎的姿势

(1)、Smarty模板引擎,PHP
(2)、Twig模板引擎,PHP
(3)、JinJa模板引擎,Python
(4)、Django框架,Python
(5)、Tornado框架,Pyhon

参考文章:SSTI模板注入 | Err0r的小站

3、还有经典

参考文章:一篇文章带你理解漏洞之 SSTI 漏洞 | K0rz3n’s Blog