HacktheBox TryOut — Guild CTF Writeup

Welcome back to my writeup! Apologies for the delay, I’ve been quite busy lately. Today, I’ll walk you through how I successfully exploited the Guild machine from HackTheBox Tryout. I’ll break down the entire process, from identifying vulnerabilities to exploiting them step by step. If you’re interested in web security, this writeup will give you insights into the methodology and tools used in real-world scenarios. Let’s get started!

Challenge Description

“Welcome to the Guild ! But please wait until our Guild Master verify you. Thanks for the wait”

Let’s visit the page

As you can see at the top, there’s a Login and Sign Up options. Let’s try to create an account!

After creating an account, I logged in using the registered credentials and was prompted to upload a file, seemingly for verification purposes. To proceed, I uploaded a JPG file.

As you can see, the verification request was successfully sent after file upload. All I have to do is to wait for the approval of “Guild-Master”.

While exploring the website, I navigated to the Profile tab and noticed an option to add a bio. I entered some text to see how the site would handle and process the input.

The outcome was that the text I entered was displayed exactly as I had typed it. Additionally, the site provided a link, allowing me to share my bio with others.

When I visit the link, here’s the result

The one with the circle is the bio.

This is where things start to get interesting. The Profile tab allows users to write and publish a biography, generating a shareable link. However, the backend processes this profile using the Jinja web template engine, making it vulnerable to Server-Side Template Injection (SSTI).

I attempted to input a bio designed to exploit this vulnerability, starting with the classic SSTI payload:

{{7 - 1}}

And here’s the result

It’s confirmed!!! Not what?

Here’s my plan, we can trick Jinja into retrieving data we normally wouldn’t have access to, like the admin’s randomly generated email. Luckily, HackTheBox provides the server’s source code, allowing us to analyze its functionality instead of working blindly. By inspecting the database structure in models.py, we can design an injection string to extract the admin’s email address.

{{User.query.filter_by(username="admin").first().email}}

After adding this to our bio, when I visit the link, here’s the result:

We now have the email of the admin user! Now all we need to do is to find a way to get the password.

I attempt to logout and forgot the password

But this is the result

If email is registered then you will get a link to reset password!

I guess we need to dig deeper here.

After lots of time analyzing the code, this part caught my eye:

As you can see, the password reset link is generated by simply hashing the user’s email with SHA-256, making it predictable. This means that if we know a user’s email, we can generate the corresponding reset link, change their password, and take over the account. Using this weakness, we can gain access to the admin account and fully manipulate the system.

On the “Forgot Password” page, submitting the admin email obtained earlier triggers a message stating that a reset link will be sent if the email is registered. However, no actual email is sent. Instead, a valid reset link is generated in the background. To take advantage of this, we can manually hash the submitted email using SHA-256 to determine the exact URL needed to reset the password.

Now we can use that hash and modify the URL to /changepasswd/<hash>

We can now change the password for the admin user!

Once I successfully reset the admin’s password, I logged in using the newly created credentials!

Now, how do we ge the flag?

I noticed that the admin can verify the files that has been uploaded by the new accounts, when I click verify to the first user, this is the output

Hmm, why it’s not verified??

What I’ve did is to analyze the code again and I saw this endpoint

This is quite intriguing. It turns out that the verification process depends on EXIF metadata within the uploaded image. Specifically, it extracts a “security code” from the Artist metadata field. However, upon closer inspection, we spot a familiar weakness, the use of the .format() method within the template. This indicates that Jinja Server-Side Template Injection (SSTI) is once again possible! While we've identified the vulnerability, the real challenge lies in determining the injection vector and crafting an effective exploit payload.

To double-check the vulnerability, I modify the Artist metadata of the image with {{7 * 7}}

After that, we need to make a new user in order for us to upload this image.

After uploading, log in as admin and verify the second account with the payload in it

It works!!!!

But now comes the real question, what kind of payload can we craft to retrieve the flag? Since we’ve identified Jinja SSTI as the vulnerability, we need to carefully construct an injection string that allows us to access restricted data. Our goal is to navigate the system, bypass security measures, and extract the flag efficiently. This requires analyzing the server’s environment, identifying useful objects, and leveraging them to execute the right command.

After numerous adjustments, trial and error, and debugging, I finally crafted the ideal payload to successfully retrieve the flag.

{% for i in ''.__class__.__mro__[1].__subclasses__() %}{% if i.__name__ == 'Popen' %}{{ i(['cat', 'flag.txt'], -1, None, None, -1).communicate()[0] }}{% endif %}{% endfor %}

We will leverage Python’s object hierarchy to dynamically locate and invoke the Popen class from the subprocess module. The payload iterates through all subclasses of BaseException (since object.__mro__[1] refers to BaseException), looking for Popen, which allows command execution. Once found, it spawns a new process to execute cat flag.txt, effectively reading and exposing the contents of flag.txt.

Now modify the -Artist section again and replace {{7 * 7}} with our new payload! After that, make a new user account to upload the third photo with our new payload to get the flag! After that, verify the third photo and it should give you the flag!

Now we’re done!!! We’ve successfully pwned the Guild!

Last updated