在ByteCTF2021与SCTF2021中,我们都可以看到GO语言下的SSTI的身影,借此机会深入学习一下GO语言下的SSTI,在ByteCTF的WP文档中有相应的链接来介绍GO语言下的SSTI利用方法的研究。
0x0前言
在ByteCTF2021与SCTF2021中,我们都可以看到GO语言下的SSTI的身影,借此机会深入学习一下GO语言下的SSTI,在ByteCTF的WP文档中有相应的链接来介绍GO语言下的SSTI利用方法的研究。
https://www.onsecurity.io/blog/go-ssti-method-research/
https://blog.takemyhand.xyz/2020/05/ssti-breaking-gos-template-engine-to.html
https://tyskill.github.io/posts/gossti/
本文也主要参考自上面的几篇文章。
0x1漏洞介绍
和其他像Python、PHP环境下的模板注入一样,Go语言下的模板注入也是因为未使用 Go 中渲染模板的预期方式来利用,用户传入的数据直接传递到了能够被模板执行的位置,导致了一系列的安全问题。
GO 语言下
GO 语言是一个正在兴起的编程语言,正在我们的视野范围内迅速崛起。
GO语言提供了两个模板包,一个是 html/template 模块,另一个是 text/template 模块,两个模块都可以在它的官网文档中找到。
这两个模板有很大的不同,例如,在 text/template 中,您可以使用call
值直接调用任何公共函数,但是在 html/template 中则不是这种情况,text/template 包对 XSS 或任何类型的 HTML 编码没有任何保护,第二个包 html/template 增加了 HTML 编码等安全保护。
0x2利用方法
我们编写如下代码来进行测试,代码中引入了text/template
,会导致SSTI漏洞出现
package main
import (
"fmt"
"net/http"
"strings"
"text/template"
)
type User struct {
Id int
Name string
Passwd string
}
func StringTplExam(w http.ResponseWriter, r *http.Request) {
user := &User{1, "admin", "123456"}
r.ParseForm()
arg := strings.Join(r.PostForm["name"], "")
tpl1 := fmt.Sprintf(`<h1>Hi, ` + arg + `</h1> Your name is ` + arg + `!`)
html, err := template.New("login").Parse(tpl1)
html = template.Must(html, err)
html.Execute(w, user)
}
func main() {
server := http.Server{
Addr: "127.0.0.1:8080",
}
http.HandleFunc("/login", StringTplExam)
server.ListenAndServe()
}
环境搭建
GO环境
推荐Go官网安装,也可以在Go中文网下载。
VSCode yyds
漏洞测试
信息泄露
进入login路由,会发现这样的一个页面
但是由于我们的源码中:
使用了 模板&User
因此\{\{.Passwd\}\}
模板使用 user 的 Passwd 属性,就会导致密码的泄露
模板User的定义
我们还可以直接利用\{\{ . \}\}
这种形式来返回全部的模板中的内容,在我们的例子中是 user 结构。这可以被认为是其他模板引擎中的 \{\{ self \}\} 的等价物。
tyskill师傅还给出了一个防御方法,tql
func StringTpl2Exam(w http.ResponseWriter, r *http.Request) {
user := &User{1, "tyskill", "tyskill"}
r.ParseForm()
arg := strings.Join(r.PostForm["name"], "")
tpl := `<h1>Hi, \{\{ .arg \}\}</h1><br>Your name is \{\{ .Name \}\}`
data := map[string]string{
"arg": arg,
"Name": user.Name,
}
html := template.Must(template.New("login").Parse(tpl))
html.Execute(w, data)
}
实现 RCE
Go语言中的SSTI可以和Python中的SSTI一样,进行方法的调用,在特定情况下,我们可以进行恶意的func调用,实现RCE
比如,我们在代码中引入"os/exec"
并添加如下func
我们就可以实现恶意的命令执行了
本质上这其实是一种代码审计发现不安全的方法定义的过程,在另一个例子中可以体现
这里就是在审计的过程中发现了一个可以进行任意文件读取的方法,并且存在模板注入的点,导致了文件信息的泄露,我们简化一下,引入"io/ioutil"
包
接下来就用和上面一样的调用方式就可以进行文件读取了
还可以进行\{\{printf "%s"\}\}
格式的输出
还有一些其他可以用于输出的payload: \{\{html "ssti"\}\}
, \{\{js "ssti"\}\}
实现的也是如上效果,实际上直接\{\{"ssti"\}\}
也可以... 我们后面的XSS就是这样进行的
XSS
我们可以利用这里的模板实现 XSS
这样不可以,这样只是单纯的输出,因为没有默认编码的行为,XSS不会实现,但是GO允许我们对模板进行定义,这样就出现了编码行为:
\{\{define "T1"\}\}ONE\{\{end\}\}\{\{template "T1"\}\}
即**\{\{define "T1"\}\}<script>alert(1)</script>\{\{end\}\} \{\{template "T1"\}\}
**
{template "name"\}\} 执行名为name的模板,提供给模板的参数为nil,如模板不存在输出为""
\{\{define "name"}模板内容\{\{end\}\}}定义一个名为name的模板
这里实际上就是一个我们进行模板的定义,并输出的过程,这样我们就可以顺利的实现XSS了
但是这种方法我目前还没有成功实践,页面无法接收这样格式的请求,以上内容来自https://blog.takemyhand.xyz/2020/05/ssti-breaking-gos-template-engine-to.html的分享。
0x3总结
模板注入作为一种攻击方式绝不是简单的flask,对各种语言的模板使用与规则进行研究面,对各种模板进行研究,都是必要的。
- 本文作者: sp4c1ous
- 本文来源: 奇安信攻防社区
- 原文链接: https://forum.butian.net/share/1286
- 版权声明: 除特别声明外,本文各项权利归原文作者和发表平台所有。转载请注明出处!