==== 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 korisničkim računom, koja ispisuje samo pozdrav. \\ Pregledom source koda, vidi se da postoji **Dockerfile**, u kojem je definirana **ENV flag** varijabla i 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 source koda vidi se da je korisničko ime administratora: “administrator0”: const ADMIN_NAME = 'administrator0'; Također se vidi da stranica koristi varijablu **secret** sastavljenu od 22 nasumična bajta, generirana pomoću **crypto.randomBytes** modula, što znači da bi trebala biti sigurna. Također se vidi da je **FLAG** definiran kao varijabla. \\ {{ zapamtime:slika1.png?nolink&500 | Slika 1 – administrator username i secret varijabla}} Nakon toga slijedi inicijalizacija baze podataka. \\ {{ zapamtime:slika2.png?nolink&500 | Slika 2 – 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 korisnički račun 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. \\ {{ zapamtime:slika3.png?nolink&500 | Slika 3 – generiranje admin tokena}} 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**. {{ zapamtime:slika4.png?nolink&500 | Slika 4 – BCRYPT_SALT varijabla}} **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”), možemo lokalno reproducirati isti **adminId** kao onaj koji koristi aplikacija, dok za **secret** ne možemo znati vrijednost. Budući da su i **secret** i **BCRYPT_SALT** varijable konstante dok aplikacija radi, ove dvije varijable će imati istu vrijednost kada će se koristiti za generaciju tokena korisnika. 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, može se izračunati 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 funkcija **bcrypt.hash** uzima u obzir. --- Sada pogledajmo kako se generira token pri stvaranju novog korisnika, što se događa u “/register” endpointu. \\ {{ zapamtime:slika5.png?nolink&500 | Slika 5 – registracija novog korisnika}} Može se vidjeti da se token za novog korisnika generira na isti način kao i administratorski token. \\ {{ zapamtime:slika6.png?nolink&500 | Slika 6 – token novog korisnika}} 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 vrijednost **userId-a** 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 “izgurati” **userId** iz dijela koji **bcrypt.hash** koristi (prvih 72 znaka). 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. Budući da 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**: \\ {{ zapamtime:slika7.png?nolink&500 | Slika 7 – ispis adminId-a}} Pokretanjem programa naredbom: node server.js vidjet ćemo **adminId**, koji će biti isti kao i na produkcijskom serveru. \\ {{ zapamtime:slika8.png?nolink&500 | Slika 8 – adminId}} 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: \\ {{ zapamtime:slika9.png?nolink&500 | Slika 9 – token middleware}} Middleware dohvaća token iz kolačića, traži prvog korisnika u bazi s tim tokenom i postavlja sesiju kao tog korisnika. Budući da 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 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. \\ {{ zapamtime:slika10.png?nolink&500 | Slika 10 – ograničenje broja znakova u usernameu}} Međutim, 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. \\ {{ zapamtime:slika11.png?nolink&500 | Slika 11 – brisanje ograničenja za dužinu usernamea na korisničkoj strani}} Sada se može stvoriti korisnički račun koji će imati isti token kao administrator, što je prikazano na slici 12. \\ {{ zapamtime:slika12.png?nolink&500 | Slika 12 – stvaranje korisnika s istim tokenom kao administrator}} {{ zapamtime:slika13.png?nolink&500 | Slika 13 – riješen zadatak}}