[Practical Guide] Hacking with RCE from SSTI Vulnerability on HackTheBox! Learn the Causes and Countermeasures of Vulnerabilities | Spookifier Writeup

[Practical Guide] Hacking with RCE from SSTI Vulnerability on HackTheBox! Learn the Causes and Countermeasures of Vulnerabilities | Spookifier Writeup

Template engines are widely used in web applications to combine HTML and data to generate displays. For example, template engines are used in the backend to embed usernames, post contents, etc. into HTML.

user input values are directly included in such template processing , the entire template syntax may be evaluated. This is a vulnerability known as "SSTI (Server-Side Template Injection)."

If an SSTI occurs, depending on the type of template engine, there is a risk that it could lead to internal variable access or, in the worst case, arbitrary OS command execution (RCE). In particular, in Python-based systems, Jinja2 and Mako have a vulnerable implementation, they can become a convenient "entrance" for attackers.

Mako the subject of this verification , is one of the template engines commonly used in Python, but it is also prone to accidentally embedding user input directly

We will look at a concrete example to see how this vulnerability can be exploited in a real application.

📹: You can also see how it's done in practice on YouTube!

table of contents

About HackTheBox

This time, we are actually HackTheBox (HTB) to verify vulnerabilities.

HackTheBox is a hands-on CTF platform where participants can practice in a variety of security fields, including web applications, servers, and networks.
Its greatest feature is that participants can learn by actually accessing the machines and applications that will be attacked and getting their hands dirty.

is one of the Challenge categories that was previously offered on HackTheBox , and is currently only accessible to users with a VIP plan or higher

There are also machines and challenges in a variety of categories, including Web, Reversing, Pwn, and Forensics, so you can tackle them at a level that suits you.

If you want to seriously hone your skills with HackTheBox, be sure the VIP plan and take full advantage of past machines and challenges.

👉 Visit the official HackTheBox website here

Security can only be mastered by practicing from an attacker's perspective

Simply reading the reference is not enough. actually attacking can you truly understand why something is vulnerable and how to protect it.

HackTheBox provides a training environment where you can safely experience vulnerabilities on a virtual machine.
Even beginners can learn how to think like an attacker while progressing step by step.

  • Virtual machine exercises based on realistic attack scenarios
  • Addresses a wide range of vulnerabilities, including RCE, SQLi, and XSS
  • VIP plan gives you access to older machines

*HackTheBox Academy (teaching materials type) and Labs (practice environment type), and the billing structures are different.
For those who want to prioritize practice, we highly recommend the Labs VIP plan or higher.

👉 For detailed information on how to register for HackTheBox and the differences between plans, please click here.

Challenge Summary: Spookifier

The challenge we tackled this time, " Spookifier is classified in HackTheBox's Web category is set to VERY EASY

On the surface, the application is very simple: a web service that simply converts text you enter into different font styles and displays them. At first glance, it doesn't appear to have any security vulnerabilities.

However, the application the Python template engine "Mako," and the string entered by the user was evaluated directly within the template.

This design flaw can lead to Server-Side Template Injection (SSTI) and ultimately arbitrary command execution (RCE)

👉 https://app.hackthebox.com/challenges/Spookifier

Challenge Points

  • Technologies used: Python, Flask, Mako
  • Notable behavior: Input is displayed in multiple fonts
  • Attack vector: Unsanitized input in template → SSTI
  • Target: Retrieve flags from /flag.txt

In this way, behind the functionality that appears safe on the surface a weakness in the template evaluation process , and the structure allows you to experience a typical ``pattern from SSTI to RCE.''

Hacking in practice: From SSTI to RCE

From here, we will actually play around with the app and look for loopholes.
If the template is handled carelessly, it could become an entry point for an attack.
We will verify whether SSTI is valid and ultimately aim for RCE.

Scouting 1: First, try out the app

First, access the target application and check what functions it has and what input it accepts

The screen has a simple input form, and it appears to have only the function of "entering text and converting it to a decorated font style and outputting it."
The appearance and structure are very simple, with no authentication functions or complex routing.

The important thing to note here is the string entered by the user is processed in some way and then displayed as a template .
It seems that somewhere in the process of "displaying in multiple fonts" the string is being manipulated by a template engine.

I checked the request information using devtools, but there doesn't seem to be any significant information there.

Reconnaissance 2: Identifying the template engine from the source code

When investigating vulnerabilities in actual web applications, it is rare to have access to the source code.
Penetration testing and bug bounty testing rely on black box testing (observing behavior from the outside).

Therefore, we usually check for the presence of a template engine and whether there are any vulnerabilities through the following process.

  • In the text field, try out some common template syntax such as ${7*7} , {{7*7}} , <%= 7*7 %>
  • the result shows 49 or 7*7
  • Any unusual template errors or evaluation results can provide clues to the template engine.
  • Infer the template engine used from its output and behavior (Mako, Jinja2, Twig, etc.)

This time, the source code was provided as a special challenge aimed at learning about vulnerabilities,
allowing me to directly examine the internal structure and quickly understand how template processing works.

In the provided source code, you can find the following template rendering description:

from mako.template import Template ... return Template(result).render()

This sentence clearly shows that
Mako is being used as the template engine Mako is a Python template engine, and the ${...} syntax is evaluated directly as a Python expression, which poses a risk of SSTI (Server-Side Template Injection)

will try to evaluate ${} in user input

Now that we know that Mako is used as the template engine, the next thing to check is
the ${} in the string entered by the user is actually evaluated as a template expression , which is the first step in determining whether SSTI (Server-Side Template Injection) exists.

try entering Mako's basic template syntax, ${7*7},

${7*7}

If the template engine evaluates this input as an expression, it should output the number
49. Conversely, if it is not evaluated and treated as a string, it will simply be displayed on the screen as ${7*7}

When I sent it, the following message was displayed on the screen:

The result 49 the ${7*7} entered by the user has been evaluated by the template engine (Mako).

In other words, Mako processes user input as a template , and it was confirmed that SSTI was in effect.

Intrusion: Check for RCE ⇒ Try to see how far you can execute it from the template formula

With SSTI confirmed, our next goal was clear:
to see if we could leverage template expressions to execute arbitrary code on the server side (RCE)

Confirmation of command execution

First, let's test whether we can actually execute an OS command from a template expression.
To check, we will use the simple whoami command.

${__import__('os').popen('whoami').read()}

When I submitted this formula, I got the following result:

The execution result of whoami shows root which confirms that any OS command can be executed through a template expression , and that the command is executed with root privileges

At this point, it is clear that a remote code execution (RCE) vulnerability exists, allowing an attacker to execute commands with elevated privileges

Checking file read

Now that we know we can execute commands, we can check
whether we can read any file A typical example /etc/passwd file, which is familiar in Linux environments.

${open('/etc/passwd').read()}

The output included the user information, such as:

This result shows that
it is possible to call Python's open() , giving you full control over read operations on the server.

Execution: Search and get flags

So far, through template injection

  • Running Python Code
  • Execute OS commands
  • Arbitrary file reading


This means that a complete remote code execution (RCE) has been achieved .

The next step to find the target flag file and retrieve its contents .

Find the location of the flag file

First, let's look at the contents of the root directory / and see what directories and files are there.

${__import__('os').listdir('/')}

As you can see, it's fine if you can find the desired file ( flag.txt ), but if you can't find it, you'll need to dig deeper into home or root

Reading the flag

If the search finds a file such as /flag.txt open() to retrieve its contents:

${open('/flag.txt').read()}

When I ran this expression, I got the following output:

We successfully obtained
the flag, which was the final goal of the HackTheBox challenge Through this process, we were able to gain a deeper understanding of the extent to which the SSTI vulnerability can be exploited through actual testing.

Why did this vulnerability occur? How to use templates safely

The main cause of this vulnerability (SSTI → RCE) the inappropriate use of the template engine

In particular, the Python side dynamically constructed template strings containing user input , leading to template injection (SSTI) and eventual remote code execution (RCE).

Solution – Don’t pass dynamic strings to templates

One of the typical patterns in which SSTI (Server-Side Template Injection) occurs
when a string is constructed in Python and then evaluated as a template .

Creating template strings using str.format() , as in the code below,

def generate_render(converted_fonts): result = '''<tr><td> {0}</td></tr><tr><td> {1}</td></tr><tr><td> {2}</td></tr><tr><td> {3}</td></tr> '''.format(*converted_fonts) return Template(result).render()

For example, converted_fonts contains the following user input:

${__import__('os').popen('id').read()}

Passing this template to Mako creates a serious vulnerability Mako will evaluate ${...}

Safe usage: Separating template structure from data

To prevent this issue, it's important
to separate the template structure from the user input (variables) You can safely handle this by explicitly passing variables to render() , like this:

def generate_render(converted_fonts): template = '''<tr><td> ${font1}</td></tr><tr><td> ${font2}</td></tr><tr><td> ${font3}</td></tr><tr><td> ${font4}</td></tr> ''' return Template(template).render( font1=converted_fonts[0], font2=converted_fonts[1], font3=converted_fonts[2], font4=converted_fonts[3] )

With this method, font1 through font4 contain ${} , Mako will treat them as ordinary strings and will not evaluate them as template expressions.

Mako's ${...} syntax evaluates expressions within templates,
and if user input is passed in verbatim, there is a risk of code execution.

On the other hand, if you pass variables explicitly using
Template(...).render(var=value) In this case, var } can safely be used as a placeholder in the template , but will not be executed as code.

Summary: SSTIs are vulnerabilities caused by "usage habits"

In this "Spookifier" challenge, improper handling of Mako templates
allowed us to exploit a vulnerability that led to Server-Side Template Injection (SSTI) and ultimately to Remote Code Execution (RCE).

These vulnerabilities are caused by
implementation mistakes made by developers They are particularly dangerous when template strings are dynamically constructed.

To use template engines safely:

  • Always separate templates and data (variables)
  • Pass variables as placeholders and do not evaluate expressions
  • Do not pass untrusted input directly to templates

By simply following these basic principles, many SSTIs can be prevented.

Security can only be mastered by practicing from an attacker's perspective

Simply reading the reference is not enough. actually attacking can you truly understand why something is vulnerable and how to protect it.

HackTheBox provides a training environment where you can safely experience vulnerabilities on a virtual machine.
Even beginners can learn how to think like an attacker while progressing step by step.

  • Virtual machine exercises based on realistic attack scenarios
  • Addresses a wide range of vulnerabilities, including RCE, SQLi, and XSS
  • VIP plan gives you access to older machines

*HackTheBox Academy (teaching materials type) and Labs (practice environment type), and the billing structures are different.
For those who want to prioritize practice, we highly recommend the Labs VIP plan or higher.

👉 For detailed information on how to register for HackTheBox and the differences between plans, please click here.

Share if you like!

Who wrote this article

This is a blog I started to study information security. As a new employee, I would be happy if you could look with a broad heart.
There is also Teech Lab, which is an opportunity to study programming fun, so if you are interested in software development, be sure to take a look!

table of contents