在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/
本文也主要参考自上面的几篇文章。
和其他像Python、PHP环境下的模板注入一样,Go语言下的模板注入也是因为未使用 Go 中渲染模板的预期方式来利用,用户传入的数据直接传递到了能够被模板执行的位置,导致了一系列的安全问题。
GO 语言是一个正在兴起的编程语言,正在我们的视野范围内迅速崛起。
GO语言提供了两个模板包,一个是 html/template 模块,另一个是 text/template 模块,两个模块都可以在它的官网文档中找到。
这两个模板有很大的不同,例如,在 text/template 中,您可以使用call
值直接调用任何公共函数,但是在 html/template 中则不是这种情况,text/template 包对 XSS 或任何类型的 HTML 编码没有任何保护,第二个包 html/template 增加了 HTML 编码等安全保护。
我们编写如下代码来进行测试,代码中引入了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中文网下载。
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)
}
Go语言中的SSTI可以和Python中的SSTI一样,进行方法的调用,在特定情况下,我们可以进行恶意的func调用,实现RCE
比如,我们在代码中引入"os/exec"
并添加如下func
我们就可以实现恶意的命令执行了
本质上这其实是一种代码审计发现不安全的方法定义的过程,在另一个例子中可以体现
这里就是在审计的过程中发现了一个可以进行任意文件读取的方法,并且存在模板注入的点,导致了文件信息的泄露,我们简化一下,引入"io/ioutil"
包
接下来就用和上面一样的调用方式就可以进行文件读取了
还可以进行{{printf "%s"}}
格式的输出
还有一些其他可以用于输出的payload: {{html "ssti"}}
, {{js "ssti"}}
实现的也是如上效果,实际上直接{{"ssti"}}
也可以... 我们后面的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的分享。
模板注入作为一种攻击方式绝不是简单的flask,对各种语言的模板使用与规则进行研究面,对各种模板进行研究,都是必要的。
11 篇文章
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!