Golang中的SSTI
Go的标准库里有两个模板引擎, 分别是text/template
和html/template
, 两者接口一致, 区别在于html/template
一般用于生成HTML
输出, 它会自动转义HTML
标签, 用于防范如XSS
这样的攻击。
0x01 init...
从一个题目入手:
先把题目的代码敲出来。
package main
import (
"bufio"
"html/template"
"log"
"os"
"os/exec"
)
type Program string
func (p Program) Secret(test string) string {
out, _ := exec.Command(test).CombinedOutput()
return string(out)
}
func (p Program) Label(test string) string {
return "This is " + string(test)
}
func main() {
reader := bufio.NewReader(os.Stdin)
text, _ := reader.ReadString('\n')
tmpl, err := template.New("").Parse(text)
if err != nil {
log.Fatalf("Parse: %v", err)
}
tmpl.Execute(os.Stdin, Program("Intigriti"))
}
代码量很少, 很明显的模板注入, 问题是怎么构造payload
去调用Secret
方法执行命令。
0x02 loading...
快捷键进入html/template
的代码时vscode
自动打开了官方文档地址, 代码路径也提示了, 两者结合起来看。
https://pkg.go.dev/html/template?utm_source=gopls
一些从文档中了解到的常识:
- 模板的占位符为
{{语法}}
, 这里的语法
官方称之为Action
, 其内部不能有换行,但可以写注释,注释里可以有换行。 - 特殊的
Action
:{{.}}
,中间的点表示当前作用域的当前对象, 类似JAVA
中的this
关键字。 Action
中支持定义变量,命名以$
开头,如$var = "test"
,有一个比较特殊的变量$
,代表全局作用域的全局变量,即在调用模板引擎的Execute()
方法时定义的值,如{{$}}
在上面的题目中获取到的值就是Intigriti
.Action
中内置了一些基础语法,如常见的语法,如判断if else
,或且非or and not
,二元比较eq ne
,输出print printf println
等等,除此之外还有一些常用的编码函数,如urlescaper,attrescaper,htmlescaper
。Action
中支持类似unix
下的管道符用法,|
前面的命令会将运算结果(或返回值)传递给后一个命令的最后一个位置。
有一些前置知识后结合代码再看,测试单元里面能找到很多具体的用法。
比如内部方法调用:
查看对应的方法
参数名参数类型都对得上,在题目中进行尝试:
0x03 loaded
Done, 上面提到Action
中是支持管道符的, 所以答案可以是:
{{.Secret "whoami"}}
{{"whoami"| .Secret}}
0x04 in the end
一些思考:
1.假设代码中没有可命令执行的函数是否可以通过模板本身支持的语法到rce
?
不可以, 模板本身支持的语法很有限, 并不支持动态导入其他标准库并调用(
Go
是编译型语言...),不过可以关注一下其他函数,比如文件读写,网络请求等等,条条大路通RCE
...
2.白盒怎么挖掘?
关注代码是否导入
text/template
或html/template
,解析的文本或文件内容是否外部可控。值得一提的是gosec
有关注html/template
的安全问题,但只是检测输出的内容是否在做了转义,没有关注模板注入的问题,默认是扫不到这个漏洞的,基于原代码修改一下即可完成白盒扫描插件的编写。
3.黑盒怎么挖掘?
引擎中无网络请求相关的方法,无法通过dnslog/httplog的方式盲测漏洞,但其本身支持一些编码函数,有回显的场景可通过表达式判断是否存在漏洞。
payload
如下,执行后回显的值为95272022
{{println 0B101101011011011110001010110}}
rcefuzzer在配置
paramPollution.expr
中加一条payload
即可{{println 0B101101011011011110001010110}}|95272022
4.对抗相关
该模板引擎的占位符本身和其他语言是重叠的, 这个强特征在流量设备中应该有已知规则会拦截; 攻击方则可借助内置的一些函数就行敏感信息规避,比如上述题目中的答案还可以写成:
{{/*"}}{{"*/}}{{- printf `%sam%s` `who` `i`| .Secret -}}{{/*"}}{{"*/}}
多添加
{{
和}}
,扰乱正则匹配。
知识面覆盖有限, 以上提到的所有内容均可能有误,orz 日常被自己菜哭。
也无风雨也无晴