==== 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}}