ctf

ctf writeup repo

View on GitHub

Aero CTF 2021

Author: p4w @ beerpwn

Twitter https://twitter.com/p4w16

Challenge description (Web category)

alt img

TL;DR

Server Side Template Injection on Thymeleaf template engine to gain RCE.

Solution

Discovery of the vuln

The challenge description says that the site is available in english and russian, this probably is written to point the attention to something involving the language. Also the challenge description tell that the flag should be located at / on the file system, this make me think that it is necessary to gain at least an arbitrary file read or RCE to get the flag. By inspection the site it is possible to notice that we can choose the language by clicking on a button. As it is possible to notice that when the button is clicked (onclick event), then the set_language(lang) function will be executed.

alt img

alt img

The function simply set a cookie named lang with the values en or ru and then reload the page. Let’s inspect the requests with burp-proxy.

alt img

The first thing that I tried during the CTF, was to modify the cookie with some simple directory traversal payloads.

alt img

alt img

alt img

The directory traversal seems working, but if we try to include some arbitrary file (such as /etc/passwd) we got a 500 internal server error. The error is verbose enough to show the server side exception: org.thymeleaf.exceptions.TemplateInputException and by googling this error, I come across to this template engine: thymeleaf.

alt img

The exception thrown seems to be related to loading the template, and that smells like SSTI to me. So I start searching for SSTI on Thymeleaf and I discovered a couple of related articles:

Exploitation

Reading these articles, we can see that it may be possible to do template injection in Thymeleaf if a template name or a fragment are concatenated with untrusted data. To get a better explanation and details I really council the readers to read the articles mentioned before. The proposed payloads to gain RCE are these:

At this point I simply tried one of these payloads into the lang cookie with a command such as wget <webhook-endpoint> to verify the command execution and it worked :=).

alt img

Now I had RCE, since the flag was located at /, I needed some way to enumerate the file system contents and extract the flag. Problem was that it was not possible to use all the bash functionality such us |, &, $, .... I also tried to extract or write files with wget, but no luck with that solution. To summarize I had the ability to run commands, but no way to build a payload (time based or OOB) that allow me to extract the output of an arbitrary command. At this point I start to read the thymeleaf documentation and some Java-doc for Java objects, the basic idea that I had was to insert the output of the executed command directly into the response, for example by using a crafted HTTP header response with the output. After a bit of pain, I was able to build this payload: __${#response.setHeader("cmd-out","test")}__::.x and it worked :)!
*[the above payload should work well on Thymeleaf 3.0, probably for Thymeleaf 2.1 could be: __${#ctx.httpServletResponse.setHeader("cmd-out","test")}__::.x]

alt img

alt img

alt img

Now that we have the ability to modify the response, I simply played a bit with the Java-doc to build a payload that reads the output of the command and save it into the crafted header. The final payload:

__${#response.setHeader(\"cmd-out\",#uris.escapeQueryParam(new java.io.BufferedReader(new java.io.InputStreamReader(T(java.lang.Runtime).getRuntime().exec(\"ls\").getInputStream())).lines().toArray()[0]))}__::.x

This payload will execute the ls command, read the first line, url-encode it and insert in the cmd-header of the HTTP response.

Here you can download a simple python script that I made during the CTF to automate all of these steps and read all the lines of the executed command.

alt img

That’s all folks, I think that was really an interesting challenge!
Cheers, p4w =)