2009. március 31., kedd

Amikor visszanyal a fagyi

Tegnapra (2009. március 29.) datálódik annak a sebezhetőségnek a nyilvánosságra kerülése, amely a Checkpoint tűzfal egy HTTP szolgáltatásához kapcsolódik: amennyiben a támadó eléri a 18264-es TCP portot, remote buffer overflow-t tud támadni a Referer, illetve az Authorization mezőkön keresztül. További színt hoz a történetbe, hogy a sebezhetőség leírásának történetében az első bejegyzés 2006-ra (!) nyúlik vissza.

Gyakran találkozunk azzal a hozzáállással, hogy "van drága hardveres tűzfalunk, biztonságban vagyunk". Több ok miatt is veszélyes egyetlen eszközre bízni egy informatikai infrastruktúra teljes biztonságát: egyrészt a drága, nehéz, rackbe építhető eszköz egyfajta hamis biztonságérzetet teremt azzal, hogy ott búg a gépterem legnagyobb rackszekrényében, ugyanis a legtöbb tűzfal körültekintő beállítás hiányában nem jelent számottevő védelemet, legfeljebb könnyen megkerülhető kellemetlenséget az elszánt támadó számára.

Másrészről nem szabad elfeledkezni arról, hogy a tűzfal is voltaképpen ugyanolyan eszköz (számítógép), mint a többi: nem tökéletes benne dolgozó kód, ugyanúgy derülnek ki sebezhetőségei, mint bármely más szoftvernek (ld. például a fenti bekezdésbeli linket). A nehézséget az ilyen céleszközök esetében az jelenti, hogy az esetek nagy részében jóval körülményesebb és nehezebb befoltozni a rést, mint egy update funkcióval ellátott szoftver esetében, másrészt a (viszonylag) alacsony eladott példányszám miatt a gyártókon sincs akkora nyomás a patch elkészítésére. Nem mellékesen számos esetben nem is lehetséges egyszerűen befoltozni az eszközök biztonsági réseit (emlékezzünk itt például arra a hírhedt cisco ip telefon sebezhetőségre, amikor ICMP csomagokkal lehetett megfektetni a hardveres telefonokat: firmware upgrade nélkül nem lehetséges kijavítani a hibát, ez pedig egy ezer készülékes hálózat esetében nem elhanyagolható idő és pénz. A másik klasszikus példát a HP hálózati nyomtatói jelentik, amelyekről IronGEEK 2006-ban tartott előadást - nos, a bemutatott támadásokat ma is végre lehet hajtani az üzemelő HP nyomtatók 90%-án).

A cégek biztonsági megbízottainak tudomásul kell venniük, hogy a feladatuk nem merül ki a drága integrált hálózatvédelmi megoldás megvásárlásában. A biztonság nem állapot, amelybe az eszköz révén eljuthatnak, hanem folyamat, amit az eszköz helyesen használva támogat.

2009. március 19., csütörtök

Firefox forensics

Forensics jellegű munkáknál alapvető (ám nem mindig kimondott) követelmény, hogy a helyszínre megérkezve azonnal elő tudjunk venni néhány olyan eszközt, amellyel rövid idő alatt nagy mennyiségű információt tudunk kinyerni a kompromittált, illetve a vizsgálatok során fókuszba kerülő rendszerekről.

Felhasználók munkaállomásai esetében legtöbbször nagyon jó képet lehet alkotni a felhasználó(k)ról pusztán a böngészők által tárolt, megjegyzett adatok alapján. Következtetni lehet a felhasználó bönégszési, levelezési szokásaira, érdeklődési körére,... Hasznos emiatt, ha van az eszköztárban egy olyan eszköz, amely különösebb beállítás, telepítés nélkül kinyeri az összes információt, ami a böngészővel kapcsolatos: a Firefox Forensics zseniális kis eszköze, a Firefox3 Extractor tökéletes választás.

A Firefox3 egyik legnagyobb újítása az, hogy az összes, a felhasználóval kapcsolatos adatot (browsing history, formok elmentett értékei, jelszavak, letöltési előzmények stb.) SQLite adatbázisban tárolja. A Google Chrome a másik olyan böngésző, amely szintén ilyen megoldással dolgozik, így az eszköz a Chrome előzményeihez is biztosít támogatást (igaz, hogy erősen experimental állapotú a bejegyzés időpontjában).

Hol találhatóak maguk az adatbázisok? Linux/Solaris alatt a ~/.mozilla/firefox/{profile folder}/, Windows XP esetében a C:\Documents and Settings\{user id}\Application Data\Mozilla\Firefox\Profiles\{profile folder}\, Vista alatt C:\Documents and Settings\{user id}\AppData\Roaming\Mozilla\Firefox\Profiles\{profile folder}.

A F3E használata triviális: a könyvtárakban elindítva csv, illetve HTML fájlokat generál, amelyekben időbélyegekkel együtt kidumpolja a firefox által készített adatokat. A készítők szerint Linux alatt is működik wine-vel, emiatt nem jelenthet gondot forensic célú linux disztribúciókkal, pl. a Helix-szel történő integrálás.

2009. március 18., szerda

The Security Public Relations Excuse Bingo


A cím önmagáért beszél, a bullshitbingo mintájára biztonsági események bejelentésekor is lehet bőszen karikázni.

A bingo elérhető itt:
http://www.crypto.com/bingo/pr

Webalkalmazások biztonsági hibái - 4. Kliensoldali input kontrollok

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.

Minden webalkalmazás fogad valamilyen formában klienstől (felhasználótól) származó inputokat. A felhasználói inputokkal kapcsolatos első számú aranyszabály az, hogy a webalkalmazásnak soha nem szabad bennük vakon megbíznia bennük: a felhasználótól érkező, nem várt formátumú inputok könnyen hibát okozhatnak az alkalmazásban (hibaüzenetet generálva ezzel), esetleg lehetőséget adhatnak klasszikus injection támadásra (SQL, script, LDAP, XML,...) Nyilvánvaló, hogy az alkalmazásnak szerveroldalon kell eldöntenie egy kérésről, hogy érvényes, vagy ártó szándékú inputokat tartalmaz-e, de gyakori megoldásként kliensoldali kontrollokat is alkalmaznak a fejlesztők az inputok szűrésére.

Sok biztonsági tesztelő a kliendoldali kontrollokat egyértelműen "felfedezésként" azonosítja a jelentésben, ugyanis a legtöbb módszert több-kevesebb energia belefektetésével ki lehet kerülni. Jelen sorok írója szerint azonban megvan a kliensoldali ellenőrzéseknek is a maguk létjogosultsága, azonban nem biztonsági kontrollként, hanem a felhasználói élményt javító "fícsör"-ként. Lássuk, milyen tipikus kliensoldali kontrollokkal találkozunk a tesztelési munka során!

A felhasználó számára (egyszerű eszközökkel) módosíthatatlan adatok.
A leggyakoribb és legegyszerűbb megoldásban a kliensnek küldött oldallal adatokat küld az alkalmazás, és arra épít, hogy a kiküldött adatokat változatlan formában kapja vissza. Session azonosító, felhasználói név, egyéb hitelesítési adatok - minddel találkoztunk már. Tipikusan az alábbi megoldási módokat akalmazzák széles körben:
  • Hidden html form mezők. A html lehetőséget biztosít arra, hogy hidden mezőket tegyünk a formokra, amik a felhasználó számára láthatatlanok, viszont a form elküldésekor a webalkalmazás megkapja.
  • Http cookie-ban tárolt információk. A cookie-k egyszerű lehetőséget kínálnak arra, hogy az alapból állapotmentes http protokollba állapotokat csempésszünk. Működésük egyszerű: a http válasz headerjében a set-cookie paranccsal lehet írni őket, a kliens pedig minden, az adott domainbe küldött http kérésbe beleteszi a domainben érvényes cookie-k adatait. Két fajtájuk van: permanens (a böngésző bezárása után is érvényes marad) és átmeneti (a böngésző bezárása után törlődik).
  • Flash cookie-k. A http-s cookie sok problémával küzd: implementációtól függ, hogy mekkora lehet a maximális méretük, emiatt komplex adatok tárolására nem igazán alkalmas. Emiatt a flash technológiában újfajta "cookie"-kat vezettek be: ezek nem a böngésző http cookie-jai között tárolódnak, hanem egy külön mappában (%APPDATA%\Macromedia\Flash Player Windowsban, ~/.macromedia linuxban és /Preferences/Macromedia/Flash Player Mac OSX-ben). Forensic munkáink tapasztalatai szerint a felhasználók és a felhasználói azonosíthatatlanságot védő egyszerű eszközök nem törlik a flash-es cookie-kat.
  • URL paraméterek. A legegyszerűbb mód az a megoldás, amikor a linkek és feldolgozó php-k az URL-ben kapják meg az adatokat, GET paraméterként.
  • A referer mező. A böngészők nagy része egy form elküldésekor a küldő oldal címét beleteszi a referer mezőbe. Nem túl gyakori megoldás, de találkoztunk már azzal, hogy ebben a mezőben küldik el a sessionazonosítót GET paraméterként.
Javascriptes input validáció. Gyakori, hogy az oldal valamilyen javascript segítségével ellenőrzi, hogy a felhasználó megfelelő hosszúságú, típusú stb. inputot ad az egyes beviteli mezőkhöz. Ez a megoldás azzal jár, hogy a teljes validációs logika elérhető a kliensoldalon a forrás megtekintésével, ezáltal módosítható, hiszen a böngésző futtatja.

Obfuszkált inputok. Sok esetben alkalmaznak obfuszkálást a felhasználónak küldött, majd változatlanul (illetve legitim módon megváltoztatva) visszavárt inputokkal való machinálás megnehezítésére. A sessionazonosító gyengeségeit tárgyaló részben több esetet is mutattunk, amelyben a sessionazonosító valamilyen obfuszkált információt is tartalmaz az adott sessionről. Az ott tárgyalt problémás megoldások tetszőleges felhasználó oldali input egyfajta validációs techikáiként is felfoghatóak: gyakori megoldásként valamilyen értelmes, az alkalmazás logikáját befolyásoló adatot base64-gyel kódolva teszik ki a klienshez.

Hibrid biztonsági kontrollok helytelen használata. Az ASP-ben bemutatott ViewState technológia megfelelő használat esetén egyfajta hibrid kontrollként is felfogható a felhasználói interakció kezelése során. A ViewState-et használó oldalak egyetlen, rendszerint hidden paraméterként átadott változóban tárolják a felhasználó/oldal a megvalósított logika szerinti teljes állapotát (tehát ide tartozik minden azonosítási adat és minden olyan adat, ami fontos a megvalósított logika szempontjából). A ViewState mező base64-encodinggal kerül továbbításra, emiatt önmagában nem tekinthető biztonsági kontrollnak: azonban az ASP lehetőséget ad arra is, hogy "aláírják" egy kulcsolt hashfüggvénnyel ezt az értéket, amit az EnableViewStateMac="true" sorral kapcsolhatunk be az oldal forrásában - ez az opció már védelmet nyújt a felhasználó oldalán történő megváltoztatás ellen (legalábbis jelzi, hogy nem érvényes a hash).

Mi a gond a fenti megoldásokkal, ha biztonsági kontrollként alkalmazzák őket? Az, ami a legtöbb kliensoldali kontrollal: triviálisan kikerülhetők, ugyanis ezen kontrollok csak addig a pontig működnek, amíg a felhasználó meg nem nyomja a "submit" gombot. Számos olyan eszköz elérhető (pl. owasp webscarab, burp suite, paros proxy), amelyek a localhoston http proxyként működnek, ezáltal lehetőséget adnak a http-kérés tetszőleges részének módosítására, emiatt a felhasználó felől érkező (akár kliensoldali kontrollokon is túljutott) adatokat alapvető biztonsági hiba "jól formáltnak" feltételezni.

2009. március 13., péntek

Webalkalmazások biztonsági hibái - 3. Hibakezelés

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 hibakezelés gyakran elhanyagolt terület webalkalmazások fejlesztése során: a fejlesztők sokszor nem foglalkoznak vele, az üzemeltetők pedig egészen egyszerűen, egy könnyed vállrándítással a fejlesztőkhöz dobják vissza a problémát, mondván, hogy nekik kellene megfelelően megírt kódot kommitálni. Nagyon veszélyes a fenti hozzáállás, ugyanis a támadót számtalan módon segíthetik a hibakezelés hiányosságai. Lássunk néhány tipikus példát.

A hibakezelés kihagyása az alkalmazásból. Naiv, nem kellőképp biztonságtudatos fejlesztési folyamat egyenes következményei az olyan alkalmazások, ahol nem várt helyen, nem várt formátumú felhasználói inputok (vagy akár a legitim használattal előhozható bugok) eredményeként igencsak bőbeszédű hibaüzenetek jelennek meg. Milyen típusú hibaüzenetekkel találkozhatunk?
  • A webalkalmazás saját debug üzenetei. Sok esetben előfordul az, hogy az üzembe állítási határidők miatt a webfejlesztők "ott felejtik" azokat a kódokat, amelyek a hibák detektálását, javítását megkönnyítik. Tipikusan ilyen eset az, amikor az oldal forrásában html kommentben debug üzenetek, TODO címkék olvashatóak, néhány (tesztelési szempontból) szerencsés esetben még fel is hívják a figyelmet az alkalmazás nem befejezett funkcióira. Egyik auditunk során találtunk egy nem kellőképpen validált input paramétert, amely segítségével blind SQL injection támadást tudtunk indítani. A támadással kinyerhető a teljes adatbázistartalom - elég hosszú idő alatt, de "szerencsére" a fejlesztő gondoskodott arról, hogy az AJAX-os hívás során lefutó PHP állomány közvetlenül meghíva kidumpolja az adatbázisquery eredményét, így két-három nagyságrenddel lerövidült a támadás időtartama.
  • A háttérben futó adatbázis-kezelő rendszer hibaüzenetei. A leghálásabb forrása a hibaüzeneteknek, ugyanis az adatbázis-kezelő rendszerek többnyire meglehetősen bőbeszédű hibaüzenetekkel segítik az alkalmazások fejlesztőit: ODBC alapú kapcsolódásnál a teljes hibás query kidumpolását is tapasztaltuk már. Ez amiatt roppant hálás, ugyanis a támadó egyrészt felmérheti, hogy milyen input validációs kontrollokon mennek keresztül a felhasználói inputok és hol kötnek ki végül az adatbázis-kezelő által feldolgozott queryben (ezáltal eldöntheti, hogy milyen módon tud kitörni az SQL query programozó szabta keretei közül), másrészt megkönnyíti az adatbázistáblák feltérképezését. A legtöbb esetben nem ilyen szerencsés a tesztelő, de kellő mértékben adva teljesen értelmetlen inputokat (azaz magyar kifejezéssel élve fuzzolva az alkalmazást), a legtöbb adatbázis-kezelőből ki lehet facsarni valamilyen hibaüzenetet. A hibaüzenet többnyire pedig hibát, sebezhetőséget enged megsejteni: a leggyakoribb esetben a hibaüzenet ismeretében ki lehet következtetni valami módot, amivel SQL injectionnel sebezzük az alkalmazást.
  • A PHP/ASP .net/JSP/stb. motor hibaüzenetei. Elsősorban az oldal felépítésének, az alkalmazás architektúrájának felderítésében hasznosak: amikor valamilyen szkriptfeldolgozó motor hibára fut, valamilyen rövid hibaüzenetben jeleníti meg a hiba okát, többnyire a hibát okozó forrás adott sorának megjelölésével. Ez segíti a támadót abban, hogy leszűkítse a támadás fókuszát, hibás/sebezhető pontokat keressen az alkalmazásban. Tesztelés során azt a stratégiát követjük, hogy hibaüzenet esetén más típusú inputot adva ellenőrizzük, hogy nagyjából azonos kódrészletben történik a hiba (a sorok számozása jó támpont erre), vagy különböző komponensekben. A hibaüzenetek jó kiindulási pontot adnak arra is, hogy megállapítsuk a háttérben futó szolgáltatás (pl. portálmotor) szállítóját.
  • Exceptionök. Bár szorosan kapcsolódnak a motor hibaüzeneteihez, mégis fontosságuk miatt érdemes külön kezelni a kivételeket. Az exceptionök olyan, strukturált hibaüzenetek, amelyek rendszerint több részből állnak: ha eljutnak a felhasználóhoz, bőbeszédű stacktrace-t adnak vissza, amelyből pontosan megállapítható az elhasaló függvény hívási lánca, megállapítható, hogy milyen külső java-s/.net-es csomagokat használnak a fejlesztők, továbbá sok esetben információt árulnak el magáról a kódról, illetve a környezetről (pl. .net framework verziószáma)
  • A webszerver hibaüzenetei. A webszerver hibaüzenetei gyakran elárulják, hogy milyen típusú/verziójú az adott webszerver, PHP motor, adatbázis-kezelő stb., emellett (főleg a régi verziójú webszerverek) XSS-sel is sebezhetőek: például a http://www.portal.hu/<script>alert("XSS")</script>.html cím esetén visszajövő hibaüzenet sokszor feldobja az árulkodó alert ablakot. A webszerverek hibaüzeneteivel *NIX rendszereken gyakran enumerálhatóak a felhasználók olyan módon, hogy a http://1.2.4.5/~felhasználónév kérések kiadására létező felhasználóra 200-as, illetve 403-as üzenettel, nem létezőre pedig 404-essel válaszolnak.
  • A webalkalmazás köré épített architektúra hibaüzenetei. Sok esetben előfordul, hogy nem egy (fizikai v. logikai) webszerveren fut a tesztelt webalkalmazás, hanem valamilyen egyéb eszközön keresztül érünk el hozzá: proxy szerverek, load balancerek gyakran érzékelhetőek azzal, ha érvénytelen HTTP-kérést küldünk a webalkalmazásnak, és például egy Squid által generált hibaüzenet jelenik meg.
A fenti példákból érzékelhető, hogy a hibaüzenetek információval szolgálnak az oldal felépítéséről, architektúrájáról, a háttérrendszerekről. Sőt: időzített bombaként működhetnek, ugyanis sok keresőmotor megtalálja és rögzíti a hibákat, ezekkel pedig specifikus verziójú alkalmazások, speciális típusú hibák kereshetőek nagyon egyszerűen.

2009. március 6., péntek

Webalkalmazások biztonsági hibái - 2. Hitelesítési bakik

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.

Hitelesítés során a felhasználót azonosítjuk: klasszikus definícióban a hitelesítés olyan információ felmutatását jelenti a hitelesíteni kívánt felhasználótól, amit a felhasználó ismer (jelszó), birtokol (token, smart card), vagy a felhasználóhoz egyértelműen köthető (pl. ujjlenyomat). Első közelítésben tehát pofonegyszerűnek tűnhet a dolog: a felhasználó regisztrál, megadja a jelszavát, aztán belépés előtt ellenőrizzük, hogy a belépési felületen megadott jelszó megfelelő-e.

A gyakorlatban számos buktatója lehet ennek az "egyszerű" sémának, lássunk néhány példát.

Jelszavak bedrótozása a kódba. Az egyik leggyakoribb hiba az, amikor az alkalmazás fejlesztője beleírja explicit módon a jelszót (kevésbé durva esetben annak lenyomatát) az alkalmazás kódjába. A probléma nem csak a felhasználók jelszavaira vonatkozhat (mondjuk ott többnyire az adminisztrátori account van kőbe vésve), hanem az adatbázishoz történő kapcsolódás connect stringjeivel, az esetleges backendekhez történő authentikáció során használt hitelesítési információkkal mind-mind találkoztunk már. A legdurvább hiba, amibe belebotlottunk, az volt, amikor egy on-line payment(!) rendszerhez történő kapcsolódás éles felhasználóneve(!!) és jelszava(!!!) volt beleírva a PHP kódba.

Miért jelent ez biztonsági kockázatot? Egyrészt azért, mert nem lehet menedzselni központilag (vagy a kézzel történő átírástól különböző módon) a jelszavakat, másrészt ha a támadó valamilyen módon hozzáfér az alkalmazás forráskódjához (mondjuk egy file inclusion sebezhetőséggel, vagy ugyanazon szerver egy másik alkalmazásának kompromittálásával), automatikusan hozzáférést szerez az alkalmazás által megvalósított logikához is.

Nem átgondoltan megvalósított "emlékeztető kérdés"-funkció. Emlékeznek Sarah Palinre? Tavaly év végén volt óriási botrány abból, hogy "feltörték" a yahoo-s postafiókját, és a benne található információkkal járatták le a hölgyet. A probléma az volt, hogy a Yahoo a regisztrációs eljárás során csak néhány, tipikus kérdést tesz lehetővé arra az esetre, amikor a felhasználó elfelejti a jelszavát: anyja neve, hol lakott két éve, mi volt a kutyája neve stb. Ezen információk könnyen kideríthetőek a különféle social networking alkalmazások segítségével, vagy akár egyszerű social engineeringgel is.

Másrészről gyakran előkerülő hiba, hogy a különféle brute-force támadások elleni intézkedések (már ha vannak egyáltalán) csak a "főbejáraton" vannak érvényben: találkoztunk olyan esettel, amikor az "elfelejtettem a jelszavam" funkció a felhasználó e-mailcímének bevitele után megkérdezte, hogy mi a kedvenc színünk. Színből márpedig nincs túl sok, a keresési tér így triviálisan leszűkíthető volt néhány (tíz) elemre, ezek végigpróbálgatása pedig rövidebb ideig tartott, mint ezt a bekezdést végigolvasni (bordó volt a kedvenc színe az illetőnek egyébként). Az ilyen jellegű támadásokat megkönnyíti az is, hogy számtalan tematizált szólistát lehet letölteni a netről (filmszínészek, cégnevek, kutyanevek, városok stb.)

A regisztrációs felületen enumerálható felhasználók. Nem szorosan hitelesítéshez kapcsolódik, de gyakori hiányosság, hogy a felhasználók szabadon megválaszthatják a felhasználónevüket, a felületen pedig nincs védelem viharszerű próbálkozások ellen. A támadó a regisztrációs felületen végigpróbálgathat egy szólistát az érvényes felhasználónevek után kutatva.

Nem megfelelő belépési logika. A belépési felület mögött található logika több szempontból is érzékeny pont. Néhány példa a hibás implementációkra.

Fail-open hitelesítési logika. Tipikusan hibás implementáció az alábbi kód:
public Response checkLogin(Session session) {
try {
String uname = session.getParameter("username");
String passwd = session.getParameter("password");
User user = db.getUser(unamepublic Response checkLogin(Session session) {
try {
String uname = session.getParameter("username");
String passwd = session.getParameter("password");
User user = db.getUser(uname, passwd);
if (user == null) {
// invalid credentials
session.setMessage("Login failed.");
return doLogin(session);
}
}
catch (Exception e) {}
// valid user
session.setMessage("Login successful.");
return doMainMenu(session);
}, passwd);
if (user == null) {
// invalid credentials
session.setMessage("Login failed.");
return doLogin(session);
}
}

catch (Exception e) {}
// valid user
session.setMessage("Login successful.");
return doMainMenu(session);
}

Mi itt a gond? Ha a felhasználó pl. manuálisan kitörli az elküldött HTTP-kérésből az "username" mezőt, exceptiont dob a kód, viszont az exception kezelése után belépteti a felhasználót. Igaz, hogy az esetek nagy részében nem lesz valid felhasználóhoz köthető a session, de valószínűleg elérhetőek lesznek a támadó számára tiltott funkciók is.

Többlépcsős beléptetési folyamat során közvetlenül elérhető az elsőtől különböző lépést implementáló felületek. Ez a hiba abból adódik, hogy a login logika implementálásakor a fejlesztő abból a feltételezésből indul ki, hogy a felhasználó, amikor a harmadik lépéshez ér a folyamatban, sikeresen túllépett az első kettőn. Főleg akkor jelent súlyos biztonsági kockázatot a hiba, ha az utolsó lépésben pl. egy rövid, számokból álló kód beütése szükséges, a többi adatot (pl. a felhasználónevet) hidden mezőkből, vagy cookie-ból veszi a logika: meghamisítva a szükséges adatokat, könnyen végig lehet próbálgatni a kód lehetséges értékeit.

A hitelesítés nem terjed ki minden funkcióra. Sok esetben felmerül az a probléma, hogy bár van hitelesítési eljárás érvényben, a logika nem minden elemére terjed ki. Gyakori példa erre az, amikor webalkalmazásból megvásárolható tartalmak (pl. videók, pdf-ek) közvetlenül, hitelesítés nélkül elérhetőek, ha ismerjük az URL-t. Majdnem minden tesztelési munka során használjuk azt a módszert, hogy a kapott HTML-kódból kigyűjtjük a hivatkozásokat css fájlokra, javascriptes forrásokra, php, jsp lapokra stb., és mindenféle paraméterezés nélkül meghívjuk őket. Sok esetben (bár be kellene jelentkezni a funkciók használatához) elérhető funkciókat biztosítanak, másrészről pedig hasznos és beszédes hibaüzeneteket lehet így kisajtolni az alkalmazásból.

Gyakori baki az is, ha a például a felhasználókat regisztráló form nem saját magának postolja el a bevitt adatokat, hanem másik php (jsp, asp, cgi,...) végzi a feldolgozást. Ha ilyen megvalósítással találkozunk, azonnal felmerül a kérdés, hogy vajon a feldolgozószkript végez-e ellenőrzést a forrás hitelessége felől, illetve a front-end felületen működő logikai kontrollok érvényben vannak-e a feldolgozásnál is: találtunk már olyan sebezhetőséget, ahol egy on-line foglalási rendszerben a felületen csak az elkövetkezendő két hétre lehetett foglalni, viszont a feldolgozószkript nem végzett ellenőrzést. Ezzel a módszerrel tetszőleges időpontra tudtunk foglalást feladni.

Egyszerű jelszavak használatának engedélyezése. Rengeteg esetben egyszerűen ki lehet találni(!) az adminisztrátor vagy egyéb felhasználó jelszavát. Toplista néhány tipikusról, ezeket használva meglepően sokat ki lehet találni:
  • Születési idő
  • Cégnév
  • Loginnévvel megegyező
  • "Jelszo123", "admin",...
  • a webalkalmazás neve
  • egybetűs jelszó
Plain-text jelszótárolás. Triviálisnak tűnhet, de ennek ellenére újra és újra előjön az egyik legsúlyosabb "időzített bomba", amit webalkalmazásba a fejlesztés során tenni lehet. Egy esetben meg is indokolták a fejlesztők, hogy miért volt tudatos döntés ilyen módon tárolni a jelszavakat: a felhasználók időről időre elfelejtik a jelszót, ezért ekkor e-mailben ki kell küldeni nekik...

A felhasználói hitelesítés hibái igen súlyos következményekhez vezethetnek, ugyanis a támadó ekkor illetéktelenül hozzáférhet az alkalmazás funkcióihoz, és sok esetben további sebezhetőségek kihasználásával akár a teljes szervert is kompromittálhatja.

Sorozatunk következő részében a webalkalmazások hanyag inputvalidációs hibáit vesszük sorra.

2009. március 4., szerda

Webalkalmazások biztonsági hibái - 1. Sessionök kezelése

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.

Mi a session?

Klasszikus definícióban a session olyan objektum, amely elkülöníti az egyes felhasználók tevékenységét. Vannak olyan esetek, amikor fontos a felhasználó azonosítása is (pl. összetett webes dokumentumkezelő rendszerek esetében), de adódhat olyan eset is, amikor annyi a feladat, hogy különítsük el az egyes felhasználóktól érkező kéréseket, a konkrét felhasználó személye lényegtelen (pl. regisztrálást nem igénylő webáruházak, ahol a „kosár” tartalmát tartjuk nyilván).

A sessionkezelés majdhogynem minden webalkalmazás esetén előjön tehát – lássuk, hogy hol szokták elkövetni a fejlesztők a leggyakoribb hibákat.

Nem megfelelő sessionkezelési módszer kiválasztása. Sessionöket (állapotokat) többféleképp is tárolhatunk. Néhány lehetőség:
  • Minden kérés elküldésekor azonosítjuk a felhasználó nevét és a felhasználót hitelesítő adatokat. Hasonlít a módszer a HTTP-s hitelesítés legegyszerűbb formájához - egyszerű, könnyen implementálható, viszont több szempontból is aggályos biztonságilag, ugyanis ekkor szerveroldalon nem tárolunk sessionazonosítót.
  • A szerveroldalon tárolunk mindent, ami a session kezeléséhez szükséges, a felhasználótól a cookie-ban található sessionazonosítót várjuk.
  • Az ASP .NET-ben jelent meg a ViewState funkció, amely egy hidden html paraméterben tartalmaz mindent, ami a session leírásához szükséges, ezt minden kérés mellé elküldi.
A sessionazonosító gyengeségei. Sok esetben tapasztaljuk, hogy hitelesítés után a sessionazonosító az a "titok", ami a felhasználót egyedül azonosítja a webalkalmazás számára. Ez esetben nagyon veszélyes az, ha a sessionazonosító sérülékenységet jelent.
  • A sessionazonosítónak a session azonosításán kívül más funkciója is van. Ilyen eset például az, amikor az alábbi a sessionazonosító: dXNlcj1iZWxhO2FkbWluPW5vO2lkPTIyMzIzMQ== ,ez ugyanis base64-gyel kódolt formája az alábbinak: user=bela;admin=no;id=223231. A támadó megpróbálhatja módosítani a sessionazonosítót (az alkalmazás által értelmezhető formátumban), illegitim horizontális, ill. vertikális jogosultsághoz jutva ezzel.
  • A sessionazonosító nem véletlenszerű, hanem időfüggő. A támadó sok kérés kiadásával felfigyelhet arra, hogy az időbélyeg közvetlenül szerepel a session azonosításában - ez esetben más felhasználók sessionjét is kompromittálhatja azzal, hogy predikálja az érvényes sessionazonosítókat.
  • A session nincs felhasználóhoz rendelve. Sokszor előfordul, hogy a sessionkezelés hanyag implementációjában a szerveren csak az érvényes sessionazonosítókat tároljuk, a hozzájuk tartozó felhasználót nem. Ez főleg akkor hasznáható ki könnyen, ha a sessionazonosító szerkezete kitalálható (pl. a fenti base64-encodinggal készült példában), ugyanis a támadó átírja a felhasználónevet, és mivel a sessionazonosító továbbra is érvényes, más jogosultsági szintet ér el.
  • Hibásan implementált "remember me"-funkció. A legegyszerűbb, naiv implementációban a sessionazonosítót beletesszük egy permanens cookie-ba, aminek jó hosszú lejárati időt adunk meg, amikor pedig a felhasználó visszalátogat az oldalra, visszalép a saját sessionjébe. Ez persze azzal jár, hogy a szerveren nem követjük az aktuális sessionöket (vagy ha követjük is, nagyon nehézkes tárolni az egyes sessioncookie-k lejárati idejét is, és ha lejár, megszüntetni az adott sessionazonosítót. Sokkal egyszerűbb úgy implementálni a funkciót, hogy ha ismeretlen, de értelmesnek tűnő (pl. parszolható) azonosítót kapunk, érvényesnek fogadjuk el). A támadónak itt nincs más dolga, mint készíteni egy parszolható azonosítót.
Sessionazonosító kiadása a hálózaton. Gyakori hiba, hogy a sessionazonosítót nem cookie-ban, vagy POST paraméterként adja át a kliens, hanem egyszerűen beleteszi az URL-be GET paraméterként: user.jsp?SESSID=lwjer23rayxcyxcydfsef. Miért jelent ez problémát? Egyrészt azért, mert a sessionazonosítók triviálisan kompromittálódnak a legitim használat során is: a böngészők átadják külső képek, állományok, oldalak stb. letöltésekor a kiadott HTTP-kérés fejlécében a referer mezőben. A támadónak nincs más dolga, mint (fórum esetén pl.) feltenni egy saját szerveren lévő képet, és a webszerver logjaiból kibányászni az aktuálisan érvényes sessionazonosítókat.

Gyakori hiba az is, hogy performanciaokokból HTTP-s felületű a nem hitelesített felhasználók által elérhető oldal, viszont HTTPS-en keresztül működik a belépés után elérhető felület. Ez esetben elenyésző azon oldalak száma, amelyek új sessionazonosítót adnak belépéskor a felhasználónak: leggyakrabban egyszerűen módosítják a session szerveroldali leírását azzal, hogy ezentúl Gipsz Jakab felhasználóhoz tartozik.

Szintén jellemző, hogy a HTTPS-en elérhető oldal tartalmaz elemeket (pl. tracking kód, vagy céglogo), amelyek HTTP-n keresztül érhetőek el. Ez esetben szintén kompromittálódhat a sessionazonosító.

A sessionkezelés megvalósításának logikai hibái. Gyakori baki az, hogy nem ellenőrzi az alkalmazás logikája azt, hogy egy felhasználónak csak egy sessionje lehet. Mivel minden azonosításon sikeresen átment a felhasználó, hacsak nem fordított külön gondot az alkalmazás készítője, a felhasználóhoz két külön session és két külön sessionazonosító is tartozni fog. Ez egyrészt legitim használat során nagyon ritkán fordul elő, másrészt versenyhelyzet kialakítása is nagyon egyszerű (pl. a felhasználó az A sessionben elkezd egy többlépcsős folyamatot, pl. új felhasználó felvitelét, és a B sessionben módosítja az A session első lépésben felvitt adatait).

Session lezárása. Meglepő, de a legtöbb hiba itt fordul elő. Sokszor előfordul, hogy a készítők egész egyszerűen megfeledkeznek(!) a sessionök lezárásáról, tehát nincs ilyen funkció az alkalmazásban.

Másrészről tipikus problémát jelent a lezárással kapcsolatosan az, ha a logout funkció egyszerűen törli a felhasználó cookie-jának tartalmát: ez esetben a session továbbra is él, ha a támadó ismeri az azonosítót. Nagyon egyszerűen meg lehet győződni erről: a logout után nyomjunk egy back-et a böngészőben, és küldjük újra az adatokat. Ha ekkor visszaenged az alkalmazás a belépés utáni felületre, hibás a sessionkezelés.

Látható, hogy ilyen "egyszerű" témánál is, mint a sessionkezelés, mennyi a hibázási lehetőség... a sorozat következő részében a felhasználók azonosításával összefüggő tipikus hibákat vesszük sorra.

2009. március 3., kedd

Damn Vulnerable Linux

Sok eszköz elérhető, amelyek segítségével a betörési tesztek során használt eszközöket kockázatmentesen (azaz adatvesztés, szolgáltatásleállás) veszélye nélkül lehet „próbálgatni”. Ezen eszközök közül az egyik legjobban használható a Damn Vulnerable Linux, amelynek nemrégiben készült el a legfrissebb, 1.5-ös verziója.

A DVL koncepciója újszerű, ugyanis nemcsak sebezhető szolgáltatások garmadáját teszik elérhetővé rajta, hanem mellékelik ugyanazon disztribúcióban a sebezhetőségek kihasználásához szükséges eszközöket is. A DVL a BackTrack2-n alapul, emiatt az eszközpark jó közelítéssel megegyezik a BT2-n elérhetővel, viszont egyrészt számos eszközt integráltak a DVL-be, ami a BT2-ből hiányzik, másrészt a Firefoxhoz előre telepítettek rengeteg plugint, ami elsősorban webalkalmazások terén teszi erősebbé a DVL-t.

Ami az „oktató” szekciót illeti, megtalálható a sebezhető szolgáltatások csokrában számos phpBB verzió, jónéhány közkedvelt webalkalmazási motor sebezhető verziója, valamint elolvashatjuk az OWASP Testing Guide-jának legújabb verzióit. A DVL-ben helyet kapott a WebGoat csomag legfrissebb változata is: ebben már-már e-learning-szerű tárgyalással kerülnek terítékre a webalkalmazásokban található klasszikus biztonsági hiányosságok (OSRF, XSS, SQL injection stb.) egy szándékoltan sebezhető J2EE alapú webalkalmazásban.

A legjobb választás az, ha vmware-ben futtatjuk a DVL-t: a készítők jelzik is, hogy bár teljes értékű operációs rendszer, nem javasolják fizikai gépen történő futtatását a (szándékosan) belepakolt rengeteg sebezhetőség miatt.

A DVL-t szándékosan oktatási célú eszköznek szánják, és több egyetemen is oktatási segédanyagként használják biztonsági szakemberek képzésekor. A Budapesti Műszaki és Gazdaságtudományi Egyetemen ebben a félévben kísérleti jelleggel BSc-s végzős hallgatók kapják önálló kutatási területként az eszközben található webalkalmazások tesztelését, a munkát a Stratis tanácsadói külső konzulensként segítik.