Tags: ssti rce jwt
Rating: 4.0
# Drink from my Flask#1
## 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](https://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`:**
```shell
┌[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](https://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](https://book.hacktricks.xyz/pentesting-web/ssti-server-side-template-injection/jinja2-ssti#rce-escaping), we could gain RCE via the following payload:**
Ahh... I now know why the "Anormaly long payload" exist...
```shell
┌[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>
Only routes / and /adminPage are available
┌[siunam♥earth]-(~/ctf/HeroCTF-v5/Web/Drink-from-my-Flask#1)-[2023.05.13|21:20:47(HKT)]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:**
```python
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:**
```python
{{ self._TemplateReference__context.cycler.__init__.__globals__.os.popen('ls -lah').read() }}
```
> Note: Once again, the above payload is from [HackTricks](https://book.hacktricks.xyz/pentesting-web/ssti-server-side-template-injection#jinja2-python)
**Let's read the flag!!**
```python
{{ self._TemplateReference__context.cycler.__init__.__globals__.os.popen('cat flag.txt').read() }}
```
- **Flag: `Hero{sst1_fl4v0ur3d_c0Ok1e}`**
## Conclusion
What we've learned:
1. Cracking JWT Secret & Exploiting RCE Via SSTI