ssti-server-side-template-injection
SSTI playbook. Use when template expressions, server-side rendering, preview features, or templating engines may evaluate attacker-controlled content.
By yaklang · 3,018 installs
npx skills add yaklang/hack-skills --skill ssti-server-side-template-injection
Source repository · Upstream listing
SKILL: Server Side Template Injection (SSTI) — Expert Attack Playbook
AI LOAD INSTRUCTION : Expert SSTI techniques. Covers polyglot detection probes, engine fingerprinting, Jinja2/FreeMarker/Twig/ERB RCE chains, client side Angular SSTI, and bypass techniques. Base models often miss sandbox escape MRO chains and non Jinja2 engines. For PHP CMS template eval, Jira SSTI, Confluence OGNL, and Spring Cloud Gateway SpEL, load the companion [SCENARIOS.md](./SCENARIOS.md).
0. RELATED ROUTING
Before using full engine specific exploitation, you can first load:
First use the polyglot probe sequence at the top of this file for low noise fingerprinting
[expression language injection](../expression language injection/SKILL.md) when ${7 7} or %{7 7} resolves in Java (SpEL/OGNL) — different attack surface from template engines
Extended Scenarios
Also load [SCENARIOS.md](./SCENARIOS.md) when you need:
Maccms 8.x PHP template eval — {if A:phpinfo()}{endif A} in vod search , base64 bypass for webshell write
Jira CVE 2019 11581 — "Contact Administrators" form → Velocity template injection → command output in admin email
Spring Cloud Gateway SpEL (CVE 2022 22947) — actuator route injection with StreamUtils.copyToByteArray for output capture
Struts2 OGNL S2 045 (CVE 2017 5638) — Content Type header OGNL injection with memberAccess / OgnlUtil blacklist clear
Confluence OGNL CVE 2021 26084 — createpage entervariables.action with \u0027 unicode bypass
SSTI vs EL injection disambiguation guide
Additional template engines: ASP.NET Razor, Elixir EEx, PHP Smarty/Latte/Blade, JS Pug/Handlebars/Nunjucks/EJS/Lodash + universal detection + blind SSTI + Flask PIN calculation
SCENARIOS.md reference (§7–§11): For expanded payloads and engine specific notes on Razor, EEx/LEEx/HEEx, PHP stacks, JavaScript template engines, the universal polyglot probe, mathematical fingerprinting, blind SSTI (boolean / time / OOB), and Flask debug PIN prerequisites, see [SCENARIOS.md](./SCENARIOS.md). This skill keeps a short checklist in §13–§15.
Engine Payloads Reference
For extended engine specific fingerprinting, payload matrices (Jinja2, Twig, Freemarker, Velocity, Pebble, Mako, Slim, Handlebars, Thymeleaf, Smarty, ERB, Jade/Pug), and blind SSTI detection techniques (timing based, DNS based), see [ENGINE PAYLOADS.md](./ENGINE PAYLOADS.md).
Universal detection & blind SSTI (pointer)
Use the polyglot payload and math probes in §1 and §13 first; when you need fuller blind test patterns and per engine examples (including non Python stacks), follow [SCENARIOS.md](./SCENARIOS.md) §11 and cross check §14 here for technique names (boolean, time, OOB, error based).
1. DETECTION — POLYGLOT PROBE SEQUENCE
First test: distinguish SSTI from XSS. Send these probes and check if math is evaluated server side:
Jinja2 vs Twig disambiguation :
Safe detection probe (no math, just boolean):
2. ENGINE TO LANGUAGE MAPPING
Template Engine Language Framework
Jinja2 Python Flask, FastAPI
Django Templates Python Django
Mako Python Pyramid
Twig PHP Symfony, Laravel
Smarty PHP Various
FreeMarker Java Spring MVC
Velocity Java Various Java
Pebble Java Various Java
Thymeleaf Java Spring Boot
ERB Ruby Rails
Slim / Haml Ruby Rails
Jade / Pug Node.js Express
Handlebars Node.js Express
Tornado Python Tornado
Identifying language from errors → then narrow to template engine.
3. JINJA2 (PYTHON FLASK) — RCE CHAINS
Chain 1: os module via globals
Chain 2: MRO subclass traversal (sandbox escape)
Chain 3: request object globals (works when config blocked)
(Uses hex encoding to avoid filtering)
Chain 4: lipsum function globals (Flask built in)
Chain 5: cycler object
Finding correct subprocess index dynamically:
4. JINJA2 SANDBOX BYPASS TECHNIQUES
When (underscore) is blocked:
When . (dot) is blocked:
When keywords (class, mro) are blocked:
Use hex/unicode in attr() :
When output encoding strips HTML entities:
Use safe filter to prevent auto escaping.
5. FREEMARKER (JAVA) — RCE
Execute Command via freemarker.template.utility.Execute
Alternative via ObjectConstructor:
6. TWIG (PHP) — RCE
7. VELOCITY (JAVA) — RCE
Or more directly:
8. ERB (RUBY RAILS) — RCE
9. THYMELEAF (JAVA SPRING) — RCE
Thymeleaf with Spring EL (SpEL):
10. CLIENT SIDE TEMPLATE INJECTION (AngularJS)
When AngularJS is used client side and user data flows into template expressions:
Detection : send {{1+1}} — if page shows 2 , AngularJS evaluates expressions in the DOM.
11. SSTI → FULL RCE PATH
Post RCE pivot :
1. Read /proc/self/environ — env vars with credentials
2. Read application config files — DB passwords, API keys
3. cat ~/.aws/credentials — cloud credentials
4. Reverse shell for persistence
12. COMMON INJECTION ENTRY POINTS
Where user data enters templates:
URL path: https://site.com/home?name={{7 7}}
Query parameters: ?message=Hello
HTML forms: profile name, bio, content fields
Error pages: 404 Not Found: /PAYLOAD
Email templates: name in password reset emails
Inline template rendering: render template string(user input)
Most dangerous : render template string() in Flask — entire user input used as template.
13. UNIVERSAL DETECTION PAYLOADS
Polyglot probe that triggers errors or evaluation in many engines:
Mathematical probes for blind/error confirmation:
Error based engine fingerprint (parser/stack traces often name the engine):
14. BLIND SSTI TECHNIQUES
Boolean based : Compare (3 4/2) vs 3 )2(/4 — if the first resolves and the second errors, evaluation is likely
Time based : {{sleep(5)}} or the engine specific equivalent for delay
OOB : DNS/HTTP callback via template expressions when direct output is not visible
Error based : Force different error messages based on true/false conditions
15. FLASK PIN CALCULATION
When Flask debug mode (Werkzeug debugger) is exposed but PIN protected , the PIN is derived from host specific values. Typical inputs for public PIN calculation scripts:
1. username — from /etc/passwd (the user running the Flask process)
2. Module name — often flask.app or Flask
3. Application path — app.py or the real main filename
4. MAC address — e.g. /sys/class/net/eth0/address , converted to decimal as Werkzeug expects
5. Machine ID — /etc/machine id , or /proc/sys/kernel/random/boot id combined with the first line of /proc/self/cgroup per Werkzeug’s algorithm
6. Compute PIN — use established open source PIN calculators that implement the same algorithm from these values
Use only on systems you are authorized to test; obtaining these values implies prior access or an additional info disclosure vector.