This writeup covers the steps taken to complete the Templated challenge in the Web category on HackTheBox. The challenge involved exploiting a Template Injection vulnerability to achieve Remote Code Execution (RCE) and ultimately retrieve the flag.

Upon starting the challenge, we are provided with the following:

Screenshot from the site.

Testing for Template Injection

The first thing that stood out was the potential for a Jinja2 Template Injection vulnerability, which is common in web applications that render user input using Jinja2 templates.

To test for a possible template injection, I started experimenting with basic Jinja2 syntax. One simple test payload was {{7*7}}, which is a common payload to check if template injection is possible. This payload should return 49 (the result of the multiplication) or instead 7777777 (seven 7’s).

However, when I submitted it, the result was 7777777, which indicates that template injection was indeed possible and that the application was evaluating Jinja2 expressions.

What is Template Injection?

Jinja2 is a popular templating engine used in Python-based web frameworks like Flask and Django. It allows for dynamic content generation by embedding variables and logic in HTML templates.

Template Injection occurs when an attacker is able to inject arbitrary code into a Jinja2 template. If the input from a user is directly rendered by Jinja2 without proper input sanitization, then it becomes possible for attackers to execute arbitrary code on the server.

For the purpose of this challenge, the template injection allows us to insert Python expressions directly into the template. These expressions can perform operations like accessing global variables, invoking built-in functions, or executing system commands — leading to potential Remote Code Execution (RCE).

Investigating the Vulnerability

Now that we have confirmed that the website is vulnerable to template injection, its time to gather more information about the enviroment we have been given. I did this by testing with the following payload: {{config.items()}, this gave the following output:

config.items output.

In a typical web application (especially those built with frameworks like this), the config object holds important configuration settings for the application, such as database settings, debug mode, secret keys, and other environment-specific data. These settings are often stored in the form of key-value pairs.

config.items() is a Python method that returns all the key-value pairs in the configuration as a list of tuples. In the context of this challenge, the output of config.items() helped us confirm that the application was running in a Python environment, it also gave valuable information into what modules and settings were available.

Finding and Executing a Valid Remote Code Execution Payload

Now that I knew the application was vulnerable to template injection, I needed a payload that would provide Remote Code Execution (RCE). I searched for known Jinja2 RCE payloads and found the following Python one-liner:

{{request.application.__globals__.__builtins__.__import__('os').popen('id').read()}}

This payload works by accessing the Python os module via the globals dictionary, executing the id command, and returning the result.

By submitting the above payload, I got the following output, which was very suspicious:

Example of what id gave.

The output from the id command showed that the attack was successful, and I had executed a system command on the server. This confirmed that I had Remote Code Execution.

To gather a bit more information about the system we had to work with, I replaced the id command with ls. To see where we were and what files were stored in the enviroment:

Example of ls.

As we can see here, there exists the file flag.txt, so now we replace ls with cat flag.txt and we get the following returned:

The flag.

And with that, we have successfully exploited the provded challenge using a Jinja2 Template Injection Vulnerability by obtaining Remote Code Execution.