go_ssti风险
字数 1163 2025-08-22 12:22:37
Go语言中的SSTI(服务器端模板注入)风险详解
1. SSTI基础概念
SSTI(Server-Side Template Injection,服务端模板注入)是一种Web应用漏洞,发生在应用程序使用不安全的模板引擎进行服务器端模板渲染时。攻击者通过在用户输入中注入恶意模板代码,服务器在渲染模板时执行了这些代码,从而导致执行任意代码、窃取数据或执行其他恶意操作。
常见易受攻击的模板引擎:
- Jinja2 (Python)
- Thymeleaf (Java)
- Smarty (PHP)
- Go的text/template (不安全使用情况下)
2. SSTI攻击流程
- 发现模板渲染位置:通过各种输入字段尝试注入模板表达式,观察输出变化
- 模板注入:注入模板引擎的特殊语法(如Jinja2中的
{{ 7*7 }}) - 代码执行:构造恶意模板表达式执行任意代码或获取敏感数据
3. Go语言中的SSTI风险
Go标准库提供两种模板引擎:
html/template:为防范XSS设计,默认对HTML自动转义,较为安全text/template:没有自动转义功能,不当使用可能导致SSTI或其他代码注入风险
3.1 基础示例
package main
import (
"os"
"text/template"
)
func main() {
tmpl, err := template.New("").Parse("你好, {{.}}")
if err != nil {
panic(err)
}
err = tmpl.Execute(os.Stdout, "冰镇")
if err != nil {
panic(err)
}
}
输出:你好, 冰镇
4. 漏洞靶场示例
4.1 基础靶场代码
package main
import (
"fmt"
"net/http"
"text/template"
)
type User struct {
Id int
Name string
Passwd string
}
func sstiHandler(w http.ResponseWriter, r *http.Request) {
userInput := r.URL.Query().Get("input")
user := &User{1, "admin", "laotie233"}
tmpl, err := template.New("ssti").Parse(userInput)
if err != nil {
http.Error(w, "Error parsing template", http.StatusInternalServerError)
return
}
err = tmpl.Execute(w, user)
if err != nil {
http.Error(w, "Error executing template", http.StatusInternalServerError)
return
}
}
func homeHandler(w http.ResponseWriter, r *http.Request) {
homeHTML := `<!DOCTYPE html>
<html>
<head><title>SSTI Vulnerable Web App</title></head>
<body>
<h1>SSTI Vulnerable Web App</h1>
<form action="/ssti" method="get">
<input type="text" name="input" placeholder="Enter your template">
<button type="submit">Submit</button>
</form>
</body>
</html>`
fmt.Fprint(w, homeHTML)
}
func main() {
http.HandleFunc("/", homeHandler)
http.HandleFunc("/ssti", sstiHandler)
fmt.Println("Server is running on http://localhost:8080")
http.ListenAndServe(":8080", nil)
}
4.2 攻击Payload示例
-
敏感信息泄露:
- 获取密码:
{{.Passwd}} - 获取全部用户信息:
{{.}}
- 获取密码:
-
XSS攻击:
<script>alert('xss')</script>
5. 高危功能扩展示例
5.1 扩展靶场代码(添加危险函数)
package main
import (
"fmt"
"net/http"
"os"
"os/exec"
"text/template"
)
// ... User结构体和homeHandler保持不变 ...
func sstiHandler(w http.ResponseWriter, r *http.Request) {
userInput := r.URL.Query().Get("input")
user := &User{1, "admin", "laotie233"}
tmpl, err := template.New("ssti").Funcs(template.FuncMap{
"exec": func(command string) string {
out, err := exec.Command("sh", "-c", command).Output()
if err != nil {
return err.Error()
}
return string(out)
},
"readFile": func(filePath string) string {
content, err := os.ReadFile(filePath)
if err != nil {
return err.Error()
}
return string(content)
},
}).Parse(userInput)
// ... 错误处理和模板执行保持不变 ...
}
5.2 高危Payload示例
-
命令执行:
{{ exec "ls" }}{{ exec "whoami" }}{{ exec "cat /etc/passwd" }}
-
文件读取:
{{ readFile "/etc/passwd" }}{{ readFile "/etc/shadow" }}
6. 防御措施
-
避免直接使用用户输入进行模板渲染
- 不要将用户输入直接作为模板内容
-
严格过滤用户输入
- 使用白名单限制允许的输入内容
- 对特殊字符进行转义处理
-
选择安全的模板引擎
- 优先使用
html/template而非text/template - 启用模板引擎的安全模式或沙盒功能
- 优先使用
-
安全审计和测试
- 静态代码分析
- 渗透测试
- 自动化漏洞扫描
-
最小权限原则
- 限制模板中可执行的函数和操作
- 避免在模板中暴露敏感信息
7. 总结
Go语言中的SSTI风险主要来自于不安全的text/template使用,虽然其杀伤力可能不如Jinja2等模板引擎,但仍然可能导致敏感信息泄露、XSS攻击甚至远程代码执行。开发者应当充分了解模板注入原理,采取适当的防御措施,确保应用程序的安全性。