On this page
SSTI in an Unknown Language with a Documented Exploit
Lab
Server-side template injection in an unknown language with a documented exploit · Expert
Solution
Given
This lab is vulnerable to server-side template injection. To solve the lab, identify the template engine and find a documented exploit online that you can use to execute arbitrary code, then delete the morale.txt file from Carlos's home directory.
Analyzing the task
There's a site vulnerable to SSTI. We need to identify the engine, find a public exploit, and weaponize it. Delete the morale.txt file from carlos's home directory.
Recon
Let's poke the site looking for user input and try to find SSTI. We click on the first product — and a strange redirect happens. Let's look at it in Burp more closely.
GET /product?productId=1
→ 302 Location: /?message=Unfortunately this product is out of stock
The server accepts user input — the error message.
Let's try to check for SSTI. We throw the request into Repeater and send a polyglot payload:
GET /?message=${{<%[%'"}}%\
Response:
Internal Server Error
/opt/node-v19.8.1-linux-x64/lib/node_modules/handlebars/dist/cjs/handlebars/compiler/parser.js:267
throw new Error(str);
^
Error: Parse error on line 1:
${{<%[%'"}}%\
---^
Expecting 'ID', 'STRING', 'NUMBER', 'BOOLEAN', 'UNDEFINED', 'NULL', 'DATA', got 'INVALID'
at Parser.parseError (/opt/node-v19.8.1-linux-x64/lib/node_modules/handlebars/dist/cjs/handlebars/compiler/parser.js:267:19)
at Parser.parse (/opt/node-v19.8.1-linux-x64/lib/node_modules/handlebars/dist/cjs/handlebars/compiler/parser.js:336:30)
at HandlebarsEnvironment.parse (/opt/node-v19.8.1-linux-x64/lib/node_modules/handlebars/dist/cjs/handlebars/compiler/base.js:46:43)
...
Node.js v19.8.1
Entry point found. Moreover, we know the engine — Handlebars.
Let's read up on Handlebars. The docs say we can check {{this}}.
Z{{this}} → Z[object Object]
So the Handlebars context is visible.
Exploitation
Let's check PayloadsAllTheThings. Nothing useful.
Then HackTricks. We find a payload. And right away we put pwd instead of whoami to get the current directory:
Response:
e2[object Object]function Function() { [native code] }2[object Object]/home/carlos
OK, so the command will be something like: rm -f /home/carlos/morale.txt.
Final payload:
Response:
e2[object Object]function Function() { [native code] }2[object Object]
The file is deleted.
Lab solved!
More in this category
Web Shell Upload via Extension Blacklist Bypass (PortSwigger Lab)
.php is blacklisted, but .htaccess uploads without complaint — we slip our own Apache config in and make the server execute shell.bug as PHP.
Web Shell Upload via Obfuscated File Extension (PortSwigger Lab)
Extension blacklist rejects .php and a double-extension shell.php.jpg is served as an image — a null byte in shell.php%00.jpg bypasses both checks.
Remote Code Execution via Web Shell Upload (PortSwigger Lab)
Avatar upload has no validation — drop a PHP web shell and read /home/carlos/secret.