Hey! Not your first time visiting our CTF Recaps? Go ahead and jump on down to the insights! If it is your first time, allow us to give a quick rundown of what these are. Wizer CTFs were launched to challenge developers to learn to think like a hacker in order to learn to code more securely. It's part of our new security awareness training we're designing focused on the dev team!
Once a challenge is retired the Wizer Wizard behind these creations - our very own CTO Itzik Spitzen - creates takeaways that provide clues into the challenge from the perspective of defending your script. Want to testdrive a CTF before reading the notes? Go ahead at wizer-ctf.com - it's free and there's something for all levels.
In this challenge, we identify an SSTI (Server-Side Template Injection) vulnerability which results in exposing a secret environment variable.
Description of code
What’s wrong with that approach?
The main flaw of the code is that it's passing through extended options as the 3rd argument to the `ejs.render()`, and by that, allowing the settings to be fully controlled through user input. If we read the manual, we can see that one could provide certain options which change the behavior of the library.
By reading the manual of that intended functionality here:
We can quickly spot an interesting setting which could be altered in order to potentially inject malicious code to run within the context of the app.
What would a successful SSTI attack look like in this case?
Once the attacker realizes that it's possible to alter the delimiters, the code which is restricting the arguments to specific ones is no longer relevant, an attacker could change the delimiter and then provide a new argument, one or more, which will be interpreted in the context of the app.
For example providing the following delimiters:
Then, providing a `[.<malicious code goes here>.]` argument, won't be restricted by the app code and will indeed run in the app. To achieve the goal of the game, a malicious code should read the `champ_key` and then, once known, the next API invocation could include the champ key and capture the flag.
Needless to point out that an SSTI is a remarkably capable attack, which allows an attacker to practically run malicious code within the context of a currently running app. Since it's a server side attack, an SSTI is a powerful entry point which could result in gaining unauthorized access to data from various sources (such as environment variables, database, other APIs which are accessible in that code etc.) and even executing shell commands remotely and potentially taking over the server.
- RTFM! Read The Freaking Manual!:
Seriously, whenever using a library to perform anything, read the manual to understand what type of risks could be imposed by taking advantage of the various options it provides, and especially if user input is involved. In this case, the ability to change the library options using user input slipped through the cracks.
- Avoid creation of template strings from user input:
Always preset templates on the server and feed arguments under strict control and sanitization of user inputs. Some apps may require more flexibility, so if there's absolutely no way around it, the user-input template should be strictly sanitized and we need to make sure that the user doesn't have control over any extended or more powerful than intended options. Always remember that a template engine might have such loopholes or powerful intended behaviors by the nature of its designed purpose.
- Attackers don't necessarily need access to the code to identify SSTI vulns:
Experienced attackers can fairly easily map code which is using a template engine. Then based on the type of template engine, they already have the risks mapped and could effectively exploit them. This article is a great resource by PortSwigger (the company behind Burp Suite) about some of the attack strategies and best practices
Wanna join us on our next challenge? Sign up for our mailing list at wizer-ctf.com.