While this may not be the most exciting way to spend your time, it is important not to underestimate what a useful source of information the documentation can be.
Learn the Basic Template Syntax
Learning the basic syntax is obviously important, along with key functions and handling of variables. Even something as simple as learning how to embed native code blocks in the template can sometimes quickly lead to an exploit.
Lab: Basic Server-side Template Injection
Abstract
This lab is vulnerable to server-side template injection due to the unsafe construction of an ERB template.
To solve the lab, review the ERB documentation to find out how to execute arbitrary code, then delete the morale.txt file from Carlos’s home directory.
There is a server side redirect when viewing details of some products:
The message param will be rendered like this:
Try {{7*7}} and the application reflects the same.
Try <%= 7*7 %> and the application renders 49, which confirms the SSTI vulnerability.
This lab is vulnerable to server-side template injection due to the way it unsafely uses a Tornado template. To solve the lab, review the Tornado documentation to discover how to execute arbitrary code, then delete the morale.txt file from Carlos’s home directory.
You can log in to your own account using the following credentials: wiener:peter
Hint
Take a closer look at the “preferred name” functionality.
Login and found the request used for updating the prefered name that users want to display in the comment:
Add {{7*7 after user.first_name and comment to any blog post. After that, request to the blog post that we have commented and the server responds like this:
This response indicates that user.nickname could be used as input for Tornado template engine.
Update payload to {{7*7}}:
Reload the blog post page and the expression is evaluated like this:
This confirms the SSTI vulnerability.
Try to execute id command with this payload:
The application returns a 500 error:
It seems like we need to escape the context.
Use this payload instead:
We need to add 7*7}} at the beginning of the payload or the application will throw this error:
The application renders like this:
Final payload:
Read About the Security Implications
In addition to providing the fundamentals of how to create and use templates, the documentation may also provide some sort of “Security” section. The name of this section will vary, but it will usually outline all the potentially dangerous things that people should avoid doing with the template.
Even if there is no dedicated “Security” section, if a particular built-in object or function can pose a security risk, there is almost always a warning of some kind in the documentation.
For example, in ERB, the documentation reveals that you can list all directories and then read arbitrary files as follows:
Lab: Server-side Template Injection Using Documentation
Log in using the provided credentials. Navigate to the first product, where it is possible to edit, preview, and save the template. The template includes the following line:
Change product.stock, which probably a number, to abc and send a request to preview the template. Got this error message:
The message reveals that the template engine being used is Freemarker.
Try with the ${7*191} payload:
Response shows that the payload is evaluted by the server:
<p>Hurry! Only 1,337 left of Beat the Vacation Traffic at $69.90.</p>
freemarker.template.utility.Execute: full qualified name of the class
?new(): it is a directive in Freemarker that initiates a new object of the specified class
("id"): after the object is created, it is invoked as a method with "id" as an argument.
Response:
Change id to rm /home/carlos/morale.txt for solving the lab:
Look for Known Exploits
Once you are able to identify the template engine being used, you should browse the web for any vulnerabilities that others may have already discovered.
Lab: Server-side Template Injection in an Unknown Language with a Documented Exploit
URL encode it and send the request for solving the lab:
Explore
Many template engines expose a “self” or “environment” object of some kind, which acts like a namespace containing all objects, methods, and attributes that are supported by the template engine.
For example, in Java-based templating languages, you can sometimes list all variables in the environment using the following injection:
Developer-supplied Objects
Websites include built-in objects from the template and custom objects added by the developer. Pay close attention to these custom objects, as they may contain sensitive information or exploitable methods.
Lab: Server-side Template Injection with Information Disclosure via User-supplied Objects
This lab has a “Preview Template” feature that allows logged-in user can preview a template of a blog.
The original template has the following line:
Change product.stock into 191*7 and hit the “Preview” button. The response has an error message:
From the error message, we know that the programming language is Python and the framework is Django. Change the template line into this:
The response reveals that the template engine being used is Jinja:
Sometimes you will need to construct a custom exploit. For example, you might find that the template engine executes templates inside a sandbox, which can make exploitation difficult, or even impossible.
After identifying the attack surface, if there is no obvious way to exploit the vulnerability, you should proceed with traditional auditing techniques by reviewing each function for exploitable behavior.
Constructing a Custom Exploit Using an Object Chain
The first step is to identify accessible objects and methods.
By exploring the documentation, you can find ways to chain objects and methods together. This can sometimes unlock access to sensitive data or dangerous functionality that seems out of reach.
For example, in the Java-based template engine Velocity, you have access to a ClassTool object called $class, you can chain the $class.inspect() method and $class.type property to obtain references to arbitrary objects:
Lab: Server-side Template Injection in a Sandboxed Environment
Try this payload:
Response shows that the expression is evaluated:
Try to read my_password.txt with "freemarker.template.utility.Execute"?new()("cat /home/carlos/morale.txt") payload:
Output of toURI().resolve("/home/carlos/my_password.txt").toURL():
As we can see, by converting URL to URI and using the resolve method of URI, we can change the URL from /opt/jars/freemarker.jar to /home/carlos/my_password.txt.
Now, we can invoke openStream() method of the URL class to open an InputStream instance for reading the file’s content. From Java 11, the InputStream class includes the readAllBytes() method, which reads and returns the file’s content as a byte array.
Run the above payload and get the following byte array:
Write a script to convert into ASCII (excluding non-visible characters):
Result:
Constructing a Custom Exploit Using Developer-supplied Objects
Some template engines run in a secure, restricted environment by default to reduce risks. While this limits the potential for remote code execution, developer-created objects exposed to the template may provide a weaker attack surface.
While template built-ins are usually well-documented, site-specific objects often lack documentation. To exploit them, you’ll need to analyze the website’s behavior, identify the attack surface, and create a custom exploit.
Lab: Server-side Template Injection with a Custom Exploit
The logged-in user can change email, prefered display name and avatar. Input malicious data into all of those features.
Login and try to comment any post with the ${7*7} payload. Then, request to the post and the following error is displayed:
So, the programming language is PHP and the template engine is Twig.
Additionally, it turns out that the injection point is not the comment parameter. Instead, it is the blog-post-author-display parameter:
Where the original value of blog-post-author-display is user.firstname.
It will be rendered in the comment section of any blog post:
However, aside from _self and _context, I can hardly execute anything. It turns out that if we upload some invalid image as an avatar, the application will throw the following error message:
The above error message reveals that there is a method named setAvatar that has two parameters.
Intercept the upload request and change the MIME type into image/png, we can upload successfully.
After that, we can get it content via the following request:
Try to read /etc/passwd via the setAvatar() function by injecting the following payload:
Comment any post and the content of /etc/passwd is leaked:
Source code of /home/carlos/User.php:
Apart from setAvatar(), we have identified three other functions along with some properties:
delete(): overwrites the content of the disabled file with an empty string, effectively clearing it.
gdprDelete(): deletes the file that links to the avatar file as well as the avatar file by invoking rm() and then invoke delete().
rm(): used for removing file and it is a private function.
Clearly, we will use the gdprDelete().
To exploit, we will do the following steps:
Use user.setAvatar('/home/carlos/.ssh/id_rsa', 'image/png') as the SSTI payload to link ~/.ssh/id_rsa to the avatar file (via symlink() function).
Use user.gdprDelete() to delete the file that links to the avatar file (the ~/.ssh/id_rsa file) as well as the avatar file.