2009. május 6., szerda

Webalkalmazások biztonsági hibái - 7. HTTP header injection

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.

A kódinjektálási problémák kapcsán vannak olyan támadástípusok (például az XSS, avagy az SQL injection), amelyek jóval nagyobb figyelmet kapnak, mint mások, annak ellenére, hogy a „nem agyonreklámozott” injektálási problémáknak is legalább akkora támadási potenciáljuk lehet. Az egyik ilyen, előadásokban/szakmai fórumokon kisebb figyelmet kapó támadás a http header injection.

A http header injection azon alapszik, hogy a böngészőnket http header mezőkkel meglehetősen sok mindenre utasíthatják. A felhasználó mindezekről általában nem is kap visszajelzést, csak a végeredményt látja, aminek eredményeképp megjelenik az oldal a böngészőben. A http üzenetekkel sok mást is meg lehet tenni az oldal standard megjelenítésén kívül, például hanyag webfejlesztési szokás a redirect, illetve a google által kedvelt formátumú URL-kezelés megvalósítása közvetlenül a http-válasz fejlécekbe történő írással. Rossz példa az alábbi kódrészlet:
Index.php:
< ?php header(„Location: http://webapp.hu/fomenu.php?lang=$_GET[’lang’]”); ? >
Alapesetben az alábbi http-választ kapja a böngészőnk a http://webapp/index.php?lang=en kérés kiadása után:
HTTP/1.0 302 Redirect
Location: http://www.webapp.hu/fomenu.php?lang=en
Connection: Keep-Alive
Content-Length: 0
A következő lépésként követi az átirányítást, és lekéri a Location: mezőben szereplő oldalt, mindezt általában a felhasználó interakciója nélkül. Meglehetősen gyakori a megoldás, de milyen hibát rejt magában? Ha például a trükkös támadó az alábbi értéket adja a „lang” paraméternek:
Index.php?lang=a%0d%0aConnection:%20Keep-Alive%0d%0aContent-Length:%200%0d%0a%0d%0aHTTP/1.0%20200%20OK%0d%0aContent-Type:%20text/html%0a%0aContent-Length:%2020%0d%0a%0d%0a<> ÁRTÓ, GONOSZ, ROSSZINDULATÚ KÓD < /html>
akkor a HTTP válasz az alábbi lesz:
HTTP/1.0 302 Redirect
Location: http://www.webapp.hu/fomenu.php?lang=a
Connection: Keep-Alive
Content-Length: 0

HTTP/1.0 200 OK
Content-Type: text/html
Content-Length: 20

<> ÁRTÓ, GONOSZ, ROSSZINDULATÚ KÓD< /html> Connection: Keep-Alive
Content-Length: 0
A fenti példában tehát egy http válasz helyett a böngészőnk két legitim, értelmes választ kap –innét a támadás neve, a HTTP response splitting attack. Ez önmagában még nem túl izgalmas (jó, igaz, meglehetősen sokat lehet játszani „idegen” domainekből letöltött javascriptekkel, de ez igazából klasszikus XSS), de gondoljuk végig, mi történik akkor, ha mondjuk cache funkciót is megvalósító http proxy-n keresztül netezünk: ebben az esetben a proxy URL és néhány egyéb paraméter alapján eltárolja a letöltött oldalakat, és a következő felhasználónak a cache-ben található példányt adja vissza. A http másrészről lehetőséget ad arra is, hogy egyszerre (azaz egy TCP-s kapcsolattal) több HTTP-kérést is kiadjunk, azaz kötegeljük a kéréseket. Kombináljuk össze a két oldalt, és már meg is van az alap proxy cache poisoning támadásunk:
  1. A támadó egy kiválaszt egy oldalt, amelyet meg kíván mérgezni a proxy cache-ében. Legyen ez mondjuk az admin.php.
  2. A támadó talál egy http header injection sebezhetőséget, mondjuk a fenti, nyelvkiválasztós-redirectes problémát. Összeállít egy olyan http response splitting exploitot, amely két http választ csinál az eredetiből: az első egy ártatlan, a második viszont az admin.php-t lecserélő html kódot tartalmazza (a mérget).
  3. A http proxy-n keresztül felépít egy http-s kapcsolatot a sebezhető webalkalmazás felé, és a felépített kapcsolatban két http-kérést is kiad: az első tartalmazza az előzőekben összeállított exploitot, és egy másodikat, amely a lecserélni kívánt admin.php-t kéri le.
  4. A cache proxy-n a fenti péla alapján három http válasz fog keresztülmenni a felhasználó felé: az első az „ártatlan” kérésre adott válasz, a második az admin.php-re „adott” mérgező válasz, és egy harmadik (amely voltaképpen az „igazi” admin.php), amellyel a proxy nem tud mit kezdeni, ezért eldobja. A trükk az, hogy mivel cache-el, eltárolja a másodikként kapott admin.php-t, és pont ez az, amit a fenti példában az ÁRTÓ, GONOSZ KÓDot tartalmazza.
A következő felhasználók, akik a cache-ből kapják az admin.php-t, bizony az ártó kódot töltik le.

Mit lehet tenni a dolog megelőzésére? Nem világrengető újdonság a megoldás: megfelelően kell kezelni a felhasználótól érkező inputokat.

2 megjegyzés:

  1. Nagyon jó cikk, sokkal érthetőbb, mint a legtöbb angol nyelvű ezzel a témával kapcsolatban. Írtam egy cikket (https://github.com/inf3rno/weblabor-cikkek/blob/master/biztonsagos%20webalkalmazasok/injektalasos%20tamadasok/cikk.md) az injektálásos technikákról, utólagos engedelmetekkel beemeltem a lang=qs-param-os példátokat.

    VálaszTörlés
  2. Közben utánanéztem, hogy PHP 4.4.2-től a header és setcookie függvények védettek a response splitting ellen, illetve csak egyetlen sor header-t tartalmazhatnak.

    VálaszTörlés

Kommentek