Dear readers,
Recently I finished another web challenge called Templated on HackTheBox. It was a really short and fun Server Side Template Injection (SSTI) challenge created on 24th October 2020. Let’s go straight into the write-up.

Files provided
There are no files provided which is pretty rare for an challenges in HackTheBox.
Outlook of the website
The website is pretty empty as there is only some text on the website with no buttons, logos, or any thing clickable.

Analysis
I tried to look at the source code by inspecting elements but there is nothing interesting in the HTML source code that provided any hint. Neither were any cookies given by the website. Therefore, I decided to take a look at the HTTP response header in the Network Tab of Firefox and noticed something interesting. The website uses Werkzeug as shown in Fig 4a in the red box.

If we Google for Werkzeug’s common Remote Code Execution (RCE) method, it depends on the debugger by Werkzeug. Usually, the console is stored at http://www.xxx.com/console. You can even find scripts to search for the debugger online. However, when I manually input, it did not store the console and the default location (see Fig 4b). However, it shouldn’t be a dirbuster challenge.

However, notice that the website return us the exact text of what page or folder we searched. This relates to a common vulnerability on Jinja2 which is called Server-Side Template Injection (SSTI) which is just nice to the hint shown on the 1st page in Fig 3 as well as the challenge’s name which is Templated. You can read more about it in this blog post which is very informative.
Therefore, I tried to input another random page and it shows exactly what I inputted in Fig 4c.

Server-Side Template Injection
A brief summary of SSTI is shown in the example below. Based on the user’s URL, the website will directly copy the content and print the result in HTML back to the user. This allows the reusability of HTML templates and renders based on the variable.
<h1>Welcome to the page!</h1> <u>This page {{page_searched}} is not available</u>
Based on Fig 4a and 4b, we can see that the server uses our page’s input and print out the same content to us but updating the value of what page is not found.
Since we know that the server is running on Flask which is a Python library, we can make use of Method Resolution Order (MRO) to traverse up the request library in Flask to import os library as shown in the blog post I mentioned earlier. Once we have access to the os library, we basically have shell access in the server where we can execute any command and it will be printed on the template and render to us.
{{request.application.__globals__.__builtins__.__import__('os').popen('id').read()}}
Exploit testing
Trying out the exploit to access if we run the id command, the result in Fig 5a that we can access the os library and execute the id command.

Since we can run any command, we can now see the directory we are in to see if the flag’s file is there. Indeed, the ls command shows flag.txt.

Flag obtained
Finally, we can print out the content in the file shown in Fig 6 and obtain the flag.

Flag: HTB{t3mpl4t3s_4r3_m0r3_p0w3rfu1_th4n_u_th1nk!}
The challenge is quite straightforward as there is no filtering by tools such as Web Application Firewall (WAF) which we can read up more on the blog to see the different encoding methods to bypass those protections.
I hope this post has been helpful to you. Feel free to leave any comments below. You may also send me some tips if you like my work and want to see more of such content. Funds will mostly be used for my milk tea addiction. The link is here. š