This is an old revision of the document!
Zadatak s Hacknite platforme - Zapamti me
Naši kolačići koriste najnovije sigurnosne tehnologije http://chal.platforma.hacknite.hr:14003
Uz zadatak je dan i izvorni kod.
Stranica ima samo Register/Login i stranicu kojoj se pristupa nakon što se ulogira s korisnikom, a koja ispisuje samo pozdrav.
Pregledom source koda vidi se da postoji Dockerfile u kojem je definirana ENV flag varijabla, ali nema ništa što na prvi pogled pokazuje ranjivost.
Osim Dockerfilea, jedini drugi izvorni kod je server.js, u kojem se nalazi sav kod koji pokreće stranicu.
Pri analizi koda vidi se da je adminov username “administrator0”:
const ADMIN_NAME = 'administrator0';
Također se vidi da stranica koristi secret varijablu koja je sastavljena od 22 nasumična bajta, generirana pomoću crypto.randomBytes modula, što znači da bi trebala biti sigurna.
Također, FLAG je definiran kao varijabla.
Nakon toga slijedi inicijalizacija baze podataka.
U inicijalizaciji baze podataka vidi se da svaki korisnik ima ID, username, password, token, *isAdmin* varijablu (koja je po defaultu 0) te vrijeme kada je korisnik stvoren.
Također se vidi da se administratorski korisnik postavlja s vrijednošću 1 za isAdmin.
Ključan dio koda je način na koji se generira token.
Token se generira kao string koji se sastoji od *secret* varijable, usernamea i ID-a korisnika, a zatim se ubacuje u bcrypt.hash funkciju, koristeći i BCRYPT_SALT.
BCRYPT_SALT varijabla se generira u initializeAuth funkciji koja se poziva samo jednom pri pokretanju servera. To znači da će ta varijabla biti ista tijekom cijelog životnog vijeka aplikacije.
Nadalje, u administratorskom tokenu nalazi se i adminId, koji se generira pomoću sljedećih linija koda:
17. linija koda: const UUID_NAMESPACE = '1b671a64-40d5-491e-99b0-da01ff1f3341'; 54. linija koda: const adminId = uuidv5(ADMIN_NAME, UUID_NAMESPACE);
Funkcija uuidv5 je deterministička — za isti par username i namespace svaki put će generirati isti UUID.
To znači da u generaciji administratorskog tokena (slika 3) od tri varijable — secret, ADMIN_NAME i adminId — poznajemo ADMIN_NAME (“administrator0”) i možemo lokalno rekreirati isti adminId kao onaj koji koristi aplikacija.
Budući da su i secret i BCRYPT_SALT varijable konstante dok aplikacija radi, token administratora uvijek se računa na isti način.
Ključna činjenica zadatka temelji se na ponašanju funkcije:
bcrypt.hash
Naime, bcrypt.hash uzima samo prvih 72 znaka danih kao ulaz i iz njih generira sažetak, dok sve znakove nakon 72. odbacuje. Zato dva unosa s istih prvih 72 znaka daju isti hash, bez obzira na razlike iza 72. znaka.
Pregledom tokenString varijable, koja se ubacuje u bcrypt.hash i generira administratorski token, vidi se njezina duljina.
Varijabla se sastoji od tri stringa: secret, ADMIN_NAME i adminId.
- secret = 22 znaka - ADMIN_NAME = 14 znakova (“administrator0”) - adminId = 36 znakova (UUID)
Zbrajanjem 22 + 14 + 36 dobiva se 72, što je točno broj znakova koje bcrypt.hash uzima u obzir.
—
Sada pogledajmo kako se generira token pri stvaranju novog korisnika, što se događa u “/register” endpointu.
Može se vidjeti da se token za novog korisnika generira na isti način kao i administratorski token.
Koristi se ista secret varijabla i ista BCRYPT_SALT vrijednost kao i kod generiranja administratorskog tokena.
Jedine dvije različite vrijednosti su username i userId.
Na userId nemamo utjecaj, ali username možemo kontrolirati.
Budući da je secret duljine 22, a bcrypt.hash uzima samo prvih 72 znaka, ako unesemo username duljine 50, on će “istisnuti” *userId* iz dijela koji bcrypt.hash koristi. To znači da userId uopće neće ući u generiranje korisničkog tokena.
Na taj način imamo potpunu kontrolu nad 50 znakova (nakon secret), koji će sudjelovati u generiranju tokena.
Pošto su secret i BCRYPT_SALT isti pri generiranju oba tokena (admin i user), ako uspijemo manipulirati tih 50 znakova da budu isti kao kod administratora, dobit ćemo identičan token.
Da bi to bilo moguće, mora vrijediti:
naš_username = admin_username + adminId
Vrijednosti admin_username i adminId su poznate ili se mogu rekonstruirati.
—
Preostaje pokrenuti aplikaciju lokalno kako bismo saznali *adminId* i napravili korisnika s odgovarajućim imenom.
Možemo dodati liniju koda koja će ispisati adminId:
Pokretanjem programa naredbom:
node server.js
vidjet ćemo adminId, koji će biti isti kao i na produkcijskom serveru.
a1653d44-7862-5db2-b60a-afce3f20ed74
Sada znamo sve potrebne informacije za generiranje istog tokena kao administrator.
Analizom token middleware funkcije vidi se kako se koristi token:
Middleware dohvaća token iz kolačića, traži prvog korisnika u bazi s tim tokenom i postavlja sesiju kao tog korisnika.
Pošto se uzima prvi user u bazi, a administrator je uvijek prvi kreirani korisnik, bilo koji kasniji korisnik s istim tokenom automatski postaje administrator.
—
Dakle, rješenje je kreirati novog korisnika s usernameom:
administrator0a1653d44-7862-5db2-b60a-afce3f20ed74
Možemo dodati još nekoliko znakova na kraj (koji ionako neće ući u prvih 72 znaka bcrypt.hash funkcije) da izbjegnemo grešku ako korisničko ime već postoji.
Dakle, svaki korisnik s usernameom oblika:
administrator0a1653d44-7862-5db2-b60a-afce3f20ed74<bilo_koji_znakovi>
imat će isti token kao administrator.
—
Pri pokušaju logina vidi se da postoji ograničenje maksimalnog broja znakova u korisničkom imenu (14 znakova), što bi onemogućilo ovu tehniku.
No to ograničenje nije implementirano na serverskoj strani, nego samo u HTML kodu (klijentskoj strani), pa se lako može zaobići — brisanjem dijela HTML-a prikazanog na slici 11. ili korištenjem *BurpSuite* alata.
Sada se može stvoriti korisnički račun koji će imati isti token kao administrator, što je prikazano na slici 12.