Server-Side Template Injection (SSTI) are vulnerabilities in web templating engines where attackers can inject code eventually leading to Remote-Code Execution (RCE).
I have discovered that the ASP.NET Razor templating engine can be vulnerable too when improperly used leading to execution of arbitrary code.
Description 🔗
The goal of this article is not to describe what SSTIs are. You can refer to the James Kettle’s “Server-Side Template Injection: RCE for the modern webapp” article that was published in 2015 and Portswigger’s article
This class of vulnerability is now well-known in several languages, frameworks and templating engines such as Ruby, Java, Twig, Smarty, Velocity, Jinja2… However ASP.NET and the Razor templating engine were left out until now!
Razor 🔗
The ASP.NET Razor templating engine is part of ASP.NET Core. Its syntax is remarkably based on the @
character.
This templating engine is very powerful for developers, but also for attackers, since it can make use of the whole .NET environment. Being able to inject code into a Razor template therefore leads to code execution on the system.
How to detect if a webapp is vulnerable? 🔗
Manually 🔗
Like other templating engines, Razor allows to perform arithmetic operations and obtain the result. For example the following sum can be processed by Razor:
@(1+2)
And it should display (prepare to be amazed 😉):
3
With tools 🔗
This detection technique was added to the Burp ActiveScan++ extension by its author James Kettle in the commit related to version 1.0.19. I hope that it will be added to the main Burp Scanner engine.
I created an issue for tplmap which is the main tool to exploit SSTI vulnerabilities. Please feel free to contribute if you want!
With code 🔗
Here is an example of vulnerable code, where a template is taken from a user-input and parsed with Razor:
[HttpPost]
[ValidateInput(false)]
public ActionResult Index(string razorTpl)
{
// WARNING This code is vulnerable on purpose: do not use in production and do not take it as an example!
ViewBag.RenderedTemplate = Razor.Parse(razorTpl);
ViewBag.Template = razorTpl;
return View();
}
How to exploit it? 🔗
As shown above, short arithmetic expressions can be inserted between parentheses. Longer C# expressions can be inserted between braces, e.g.:
@{
// C# code
}
The .NET System.Diagnostics.Process.Start
method can be used to start any process on the server and thus create a webshell.
How to test it? 🔗
I have created a simple ASP.NET webapp which implements this vulnerability.
Mitigations: how to protect against it? 🔗
I have not found any official guidance to restrict the expressiveness of Razor that would prevent code execution, without restricting it so much that it would lose most of its power and advantages.
However you should note that SSTIs only happen in specific cases: when the attacker has control over the template content. If malicious input is injected during the page generation, as data, it is not vulnerable. Therefore this vulnerability only happens when the template is dynamically built from user-controlled data. If possible, this should be avoided, or the allowed values should be filtered through a white-list.
It can happen too in a CMS that allows administrators to edit the templates. In this case a malicious administrator could inject code and execute commands on the system. However administrators are often trusted, since they usually have other possibilities to execute code anyway. Unfortunately, I do not have any proper recommendation in this case. But, you should be aware of this risk and restrict the kinds of administrators that are allowed to use this feature. For example if design or layout administrators are given this right they could abuse it.
I have discovered that variants of the Razor templating engine have been created, beyond the official one. One example is Razor Engine ⚠️ Unfortunately I would not advise to switch from the official Razor engine to this variant since it is not actively maintained:
This project is searching for new maintainers
But this variant caught my attention since it has an isolation API that:
provides an additional layer of security by allowing you to run the generated code within an secured sandbox
⚠️ However I did not check how easy or efficient it is against this attack, so I provide no guarantee.
However, it could be a possible solution to preserve Razor’s power while limiting the risks. Sandboxing the template processing in a locked-down container with the lowest privileges and accesses is an approach proposed in James Kettle’s article