tom@home.htb:~$

Blog o HTB

24 December 2020

OAuth a zneužití autorizačního toku

Úvod a kontext

OAuth se často vysvětluje zkratkou “přihlášení přes třetí stranu”, ale to je jen část reality. Ve skutečnosti jde o delegaci: klientská aplikace získá omezený přístup k nějakému zdroji nebo identitě na základě autorizačního toku mezi několika stranami. Bezpečnostní problém proto málokdy vzniká tím, že by “OAuth byl rozbitý”. Vzniká spíš tím, že aplikace špatně váže dohromady redirect, session, vydaný kód, lokální účet a výsledná oprávnění.

Na Oouch je to vidět velmi čistě. Consumer aplikace, autorizační server a interní API vytvářejí řetězec, kde útočník nemusí lámat kryptografii ani obcházet login formulář. Stačí pochopit, kdo komu v daném toku věří a kde se privilegovaný výsledek autorizačního procesu přelévá do jiného kontextu. Schooled je naopak užitečný kontrast: tam nejde o čistý OAuth bug, ale o session theft a role abuse. Právě tím pomáhá oddělit, co je ještě OAuth problém a co už jen podobně vypadající chyba ve vazbě mezi identitou a lokální rolí.

Co OAuth řeší a co už ne

Prakticky dává smysl držet v hlavě čtyři role:

Bezpečnostní chyba obvykle nevzniká při samotném vystavení tokenu. Vzniká ve chvíli, kdy některá strana udělá jeden z těchto skoků:

Jinými slovy: OAuth řeší delegaci a přenos oprávnění mezi komponentami. Neřeší automaticky, jestli aplikace správně interpretuje identitu, roli a hranice mezi jednotlivými toky.

Kde se autorizační tok nejčastěji láme

1. Slabá vazba mezi requestem a callbackem

Autorizační kód musí být svázaný minimálně s:

Jakmile aplikace přijme code jen proto, že “přišel z autorizačního serveru”, je to málo. Útočník pak může docílit toho, že se kód vystavený v privilegovaném kontextu zpracuje jinde, než měl.

Typický tvar toku vypadá nevinně:

GET /oauth/authorize?client_id=consumer&redirect_uri=https://consumer.htb/callback&state=abc123
GET /callback?code=SplxlOBeZQQYbYS6WxSbIA&state=abc123

Bezpečnostní otázka ale není jen “přišel platný code”. Správná otázka zní: přišel tenhle code správnému klientovi, pro správnou session a na správný callback?

2. Redirect nebo callback v privilegovaném browser kontextu

OAuth často počítá s tím, že uživatel projde autorizací ve vlastním browseru. Pokud ale tok navštíví admin browser, review robot nebo server-side komponenta volaná přes SSRF, privilegovaný kontext se může nechtěně přelít do toku, který ovládá útočník.

To je přesně ten moment, kdy se z běžného callbacku stává útoková plocha. Ne proto, že by byl špatně podepsaný token, ale proto, že autorizační server vydal výsledek ve špatném kontextu.

3. Lokální role se odvozují příliš přímo

Token nebo callback obvykle obsahuje identitu, scope nebo jinou formu potvrzení autorizace. Pokud klientská aplikace bez další lokální kontroly z toho rovnou odvodí:

pak se z autorizačního toku stává přímý zdroj privilegovaného rozhodnutí.

4. Servisní tokeny žijí ve stejném trust modelu jako uživatelé

Zvlášť nebezpečné je, když aplikace vydává tokeny typu client_credentials, ale následně je používá k operacím, které jsou ve skutečnosti silnější než běžná servisní delegace. V tu chvíli už nejde o OAuth jako pohodlné API. Jde o interní privilegovaný kanál.

Oouch: když se OAuth tok propojí s SSRF a interním API

Oouch je dobrý příklad právě proto, že se na něm potkají skoro všechny výše popsané chyby. Zvenku je vidět consumer aplikace, ale anonymní FTP hned na začátku prozradí architekturu: Flask consumer a oddělený Django authorization server. To je první důležitý krok, protože od té chvíle dává smysl vnímat /oauth ne jako detail přihlášení, ale jako samostatnou hranici důvěry.

První kritický moment vznikne ve chvíli, kdy kontaktní mechanizmus dovolí server-side návštěvu zadané URL. Tím se z něj stane SSRF. V kombinaci s OAuth tokem to znamená, že server nebo privilegovaná obsluha navštíví autorizační URL v kontextu, který útočník sám nemá. Výsledkem není rovnou shell, ale mnohem důležitější artefakt: autorizační code vydaný v cizím, silnějším kontextu.

Další chyba neleží v samotném kódu. Leží v tom, co s ním systém dovolí dělat dál. Přístupové údaje develop:supermegasecureklarabubu123! otevřou registraci vlastní OAuth aplikace, následně lze přes stejný trust chain získat administrátorskou sessionid na authorization serveru a vytvořit klienta s grantem client_credentials.

To je rozhodující zlom. client_credentials se zde nechovají jako úzce omezený servisní token. Chovají se jako klíč k internímu API:

curl -X POST 'http://authorization.oouch.htb:8000/oauth/token/' \
  -H "Content-Type: application/x-www-form-urlencoded" \
  --data "grant_type=client_credentials&client_id=...&client_secret=..."

Takto získaný token už stačí na interní endpoint:

/api/get_ssh/?access_token=...

který vrátí SSH klíč pro účet qtc. To je výborný příklad špatně navržené hranice. OAuth tok zde nechrání jen přístup k běžnému API. Chráněná operace přímo vydává dlouhodobý systémový přístup.

Na Oouch je proto důležité pojmenovat problém přesně:

To není “jedna OAuth chyba”. Je to řetězec trust assumptions kolem OAuth.

Schooled jako důležitý kontrast

Schooled je užitečné zmínit právě proto, že pomáhá scope článku ohraničit. Na Moodle 3.9 došlo ke krádeži MoodleSession cookie a následnému role abuse, který vedl k převzetí účtu carter_lianne. Výsledek zvenku vypadá podobně jako OAuth compromise: útočník se ocitne v cizím, privilegovaném webovém kontextu a z něj pokračuje k dalším oprávněním.

Technicky je to ale jiná chyba.

Právě to je hranice, kterou je užitečné držet i při review. Ne každý případ “ukradl jsem cizí session a mám víc práv” je OAuth problém. Ale stejné otázky o vazbě mezi autentizací a autorizací se tam vracejí.

Jak podobné chyby poznat při analýze

Při review OAuth nebo OIDC integrace má smysl jít po velmi konkrétních otázkách.

Jak pevně je svázaný callback

Co přesně se děje po úspěšné autorizaci

Kdo může autorizaci navštívit místo běžného uživatele

Jak oddělené jsou servisní a uživatelské toky

Obrana a hardening

1. Callback musí být silně svázaný s requestem

state, jednorázovost kódu, pevné redirect URI a kontrola clienta nejsou “doporučené drobnosti”. Jsou to základní vazby, bez kterých se z callbacku stane přenosový kanál mezi cizími kontexty.

2. OAuth výsledek nesmí automaticky určovat lokální roli

Úspěšná autentizace nebo delegace má vést k identifikaci uživatele nebo klienta. Teprve potom má aplikace rozhodnout, co tato identita smí dělat lokálně. Pokud role vznikne přímo z toho, že autorizace proběhla, je to příliš silné.

3. Registrace klientů a servisní granty musí být tvrdě omezené

Samoregistrace klienta, široké scope nebo volné použití client_credentials zvyšují hodnotu každého dílčího compromise kroku. Oouch dobře ukazuje, že právě z toho vznikne most do interního API.

4. Interní API nesmí vracet dlouhodobé přístupy jen na základě OAuth tokenu

Endpoint, který vrací SSH klíč, tajemství nebo jiný dlouhodobý credential, potřebuje výrazně tvrdší model oprávnění než běžné API. Samotný access token je pro takovou operaci slabá bariéra.

5. OAuth a OIDC je potřeba reviewovat jako trust graph

Nestačí auditovat jednu knihovnu. Je potřeba projít:

Shrnutí klíčových poznatků

Co si odnést do praxe

tags: oauth - web - auth - session - oidc