Hoppa yfir í efnið

Auðkenning og endurheimt aðgangs

Við fyrstu sýn virðist innskráningarsíða harla einföld: notandi sendir nafn og aðgangsorð og þjónninn svarar aðeins játandi eða neitandi. En utan um þessa einu beiðni er oft heilt kerfi. Notendur stofna reikninga, gleyma aðgangsorðum, fá endurheimtartákn, staðfesta annað auðkenningarþrep, og jafnvel skrá sig inn í gegnum annan þjónustuaðila.

Í CTF leitum við ekki að raunverulegum aðgangsorðum. Við rannsökum frekar viljandi galla í rökfræði heimilaðra verkefna: Gefa svörin til dæmis til kynna hvaða gervinotandi er til staðar? Er endurheimtartáknið ef til vill fyrirsjáanlegt, eða er jafnvel unnt að sleppa heilu skrefi sem viðmótið gerir annars ráð fyrir?

Verkefnið Endurheimt norðurs fylgir okkur í gegnum kaflann. Það veitir okkur fremur lítið mengi af tilbúnum notandanöfnum. Fyrst þarf að greina hvaða gervireikningur er skráður. Því næst er brýnt að átta sig á hvernig endurheimtartákn hans er myndað, og ljúka loks sjálfu endurheimtarferlinu.

Engar raunverulegar lykilorðatilraunir

Prófaðu aðeins gervireikninga og tákn sem verkefnið gefur skýra heimild til að rannsaka. Ekki flytja aðferðirnar yfir á raunverulegar innskráningar- eða endurheimtarsíður, ekki senda orðalista og ekki reyna að finna reikninga fólks. Hraðatakmörk og skilmálar þjónustu gilda þótt beiðni sé tæknilega einföld.

Hver ert þú og hvað mátt þú gera?

Auðkenning (e. authentication) svarar spurningunni hver stendur að baki beiðninni? Aðgangsorð, einnota kóði eða innskráning hjá auðkennisveitu getur lagt fram sönnun sem þjónninn samþykkir.

Heimilun (e. authorization) og aðgangsstýring (e. access control) svara annarri spurningu: hvað má þessi aðili lesa eða gera?

Anna getur til dæmis sannað hver hún er með réttu aðgangsorði. Sú staðreynd ein og sér veitir henni þó engan veginn sjálfkrafa leyfi til að lesa reikning Bjarna eða opna stjórnendasíðu.

auðkenning                           aðgangsstýring
„Þetta er Anna.“  ───────────────►  „Má Anna lesa /account/42?“

Í vefverkefnum ruglast þessi hugtök oft vegna þess að bæði geta endað með 401, 403 eða framsendingu á /login. Við spyrjum því mun nákvæmar: Hafnaði þjónninn beiðninni sökum þess að hann þekkti ekki notandann, eða þekkti hann notandann en hafnaði tiltekinni aðgerð?

Þessi kafli fjallar um fyrri spurninguna. Í sérstökum kafla um aðgangsstýringu skoðum við síðar hvað gerist eftir að gervinotandi hefur verið auðkenndur.

Innskráning er HTTP-beiðni

Hefðbundið eyðublað gæti sent:

POST /login HTTP/1.1
Host: nordurmarkadur.example
Content-Type: application/x-www-form-urlencoded

username=anna&password=lopapeysa

Þjónninn les reitina, finnur notandann og ber framlagt aðgangsorð saman við það sem hann sjálfur hefur tök á að sannreyna. Ef innskráning tekst gæti svarið stofnað lotu:

HTTP/1.1 302 Found
Location: /account
Set-Cookie: session=abc123; Path=/; HttpOnly

Ef hún mistekst gæti svarið verið:

HTTP/1.1 401 Unauthorized
Content-Type: text/html

Ógilt notandanafn eða aðgangsorð.

Viðmótið kann oft og tíðum að hylja þessi smáatriði með rauðum textaboðum eða framsendingum. Network og Burp HTTP history sýna hins vegar stöðukóðann, lengdina, hausana, kökuna og milliskrefin.

Auðkenni er ekki endilega notandanafn

Forrit geta auðkennt fólk með netfangi, símanúmeri, lykli, vottorði eða aðgangslykli forritaskila. Í CTF er notandanafn og aðgangsorð algengt vegna þess að flæðið er auðskilið, en rannsóknarspurningin er sú sama: Hvers kyns sönnunargögn samþykkir þjónninn?

Hvað geymir þjónninn um aðgangsorð?

Þjónn þarf leið til að sannreyna að framlagt aðgangsorð sé rétt. Í vel þekktum gagnasniðum sérðu að jafnaði ekki aðgangsorðið sjálft heldur afrakstur sérhæfðrar lykilorðakössunar (e. password hashing).

Lykilorðakössun (e. password hashing) er einátta útreikningur. Þjónninn tekur framlagða aðgangsorðið, notar sömu stillingar og ber nýja gildið saman við vistaða gildið. Salt gerir það að verkum að tveir notendur með sama aðgangsorð þurfa ekki að hafa sama vistaða streng. Hægar aðferðir eins og Argon2, bcrypt, scrypt og PBKDF2 eru hannaðar fyrir aðgangsorð og sjást oft á auðþekkjanlegu sniði.

Við höfum þegar lagt grunninn að skilningi á tætiföllum og salti í kaflanum um tætiföll. Fyrir vef-CTF er hagnýta spurningin ekki aðeins „get ég keyrt hashcat?“ heldur fyrst:

  • Er þetta yfirleitt aðgangsorðakássa?
  • Hvaða aðferð og stillingar sjást í strengnum eða kóðanum?
  • Gefur verkefnið lítið, heimilað mengi frambjóðenda?
  • Eða bendir sterk, söltuð kássa til þess að lausnin liggi annars staðar?

Strengur sem byrjar á $2b$ bendir til dæmis oft á bcrypt. $argon2id$ bendir á Argon2id. Slík vísbending þýðir ekki að ómögulegt sé að giska á mjög veikt aðgangsorð, en í byrjenda-CTF er hún oft merki um að skoða endurheimt, lotu eða rökfræði áður en ráðist er í þrautleit.

Öðru máli gegnir ef verkefnið afhendir sérstaklega kássu og fimm möguleg gerviaðgangsorð. Þá er afmarkaður samanburður hluti af verkefninu. Við notum ekki sama rökstuðning til að prófa lista gegn lifandi innskráningu.

Notandaupptalning: mismunur í svörum

Notandaupptalning (e. user enumeration) felst í að greina hvort auðkenni, til dæmis notandanafn, sé skráð. Vefur getur lekið því með texta:

Enginn notandi heitir bjarni.

á móti:

Rangt aðgangsorð.

En munurinn getur líka falist í stöðukóða, svarlengd, framsendingu, haus eða því hvort CAPTCHA eða næsta skref birtist. Endurheimtarsíður eru algengur staður fyrir slíkan mun.

Skoðum tvær gervibeiðnir:

POST /reset HTTP/1.1
Host: nordurmarkadur.example
Content-Type: application/x-www-form-urlencoded

username=anna
HTTP/1.1 200 OK
Content-Type: application/json

{"message":"Endurheimtarleiðbeiningar voru útbúnar."}

Önnur beiðni fær:

POST /reset HTTP/1.1
Host: nordurmarkadur.example
Content-Type: application/x-www-form-urlencoded

username=bjarni
HTTP/1.1 404 Not Found
Content-Type: application/json

{"message":"Notandi fannst ekki."}

Einn samanburður sýnir mismun, en við þurfum að endurtaka hann áður en við ályktum. Tilviljanakennd netseinkun eða tímabundin villa er veik sönnun. Stöðugur munur á efni eða stöðukóða er sterkari.

Berum saman afmarkað mengi

Endurheimt norðurs gefur aðeins nokkur gervinöfn. Settu eitt þeirra í /reset, vistaðu stöðukóða og svarlíkama og endurtaktu fyrir hin nöfnin. Með curl gæti ein beiðni litið svona út:

BASE_URL='https://slod-verkefnisins.example'

curl -i -X POST "$BASE_URL/reset" \
  --data 'username=<eitt gervinafn úr verkefninu>'

Ekki bæta við nöfnum sem verkefnið gaf ekki. Markmiðið er að bera saman lítið, heimilað mengi, ekki að finna raunverulega notendur.

Tími getur verið vísbending ef þjónn framkvæmir dýran samanburð aðeins fyrir skráðan notanda. En ein beiðni sem tekur 180 ms og önnur 220 ms segir lítið. Vefir, gámar og net sveiflast. Í byrjendaverkefni ætti skýrari vísbending að styðja tímamun áður en þú skrifar sjálfvirka mælingu.

Hraðatakmörk breyta næstu skrefum

Hraðatakmörkun (e. rate limiting) takmarkar fjölda beiðna á tíma. Þjónn getur svarað:

HTTP/1.1 429 Too Many Requests
Retry-After: 60

Í CTF er þetta ekki merki um að senda hraðar eða dreifa beiðnum. Það er vísbending um að núverandi leið sé líklega röng eða að verkefnið ætlist til mun minna mengis. Lestu Retry-After, stöðvaðu sjálfvirknina og skoðaðu lýsingu, JavaScript og svör aftur.

Veikbyggð aðgangsorðastefna kann vissulega að vera hluti af afmörkuðu verkefni, til dæmis ef eitt gerviaðgangsorð er valið úr fimm gefnum orðum. Hins vegar er raunveruleg orðalistaárás alls ekki nauðsynleg til að koma hugmyndinni til skila, og á hreint ekki heima á þessari námsleið.

Endurheimt aðgangs er önnur innskráningarleið

Notandi sem gleymir aðgangsorði þarf að sanna með öðrum hætti að hann eigi reikninginn. Einfalt flæði getur verið:

1. biðja um endurheimt
2. fá einnota tákn
3. senda táknið til baka
4. velja nýtt aðgangsorð
5. skrá sig inn

Endurheimtartákn (e. password reset token) gegnir tímabundið hlutverki leyndarmáls. Þjónninn getur sett það í tengil:

https://nordurmarkadur.example/reset/confirm?token=...

Í CTF spyrjum við hvernig táknið tengist notandanum og hvort við getum spáð fyrir um gilt gildi úr upplýsingum sem verkefnið veitir. Algengar vísbendingar eru stutt talnaruna, tímastimpill, notandanafn sem er aðeins Base64-kóðað eða venjulegt tætifall af fyrirsjáanlegum texta.

Að tákn líti út eins og 64 sextándastafir sannar ekki að það sé ófyrirsjáanlegt. SHA-256 skilar einmitt 64 sextándastöfum, en ef inntakið er aðeins:

anna:nordur

getur hver sem þekkir uppskriftina reiknað sama gildi. Tætifall eitt og sér getur aldrei umbreytt fyrirsjáanlegu inntaki í öruggt leyndarmál.

import hashlib

username = "anna"
suffix = "nordur"
token = hashlib.sha256(f"{username}:{suffix}".encode()).hexdigest()
print(token)

Þetta er gervidæmi; nöfn, afmarkari og fasti textinn í verkefninu kunna að vera önnur. Nákvæm bætaruna skiptir máli. anna:nordur, anna-nordur og Anna:nordur gefa þrjú ólík tætigildi.

Afkóðun er ekki alltaf rétta sögnin

Base64 má afkóða vegna þess að það er kóðun. SHA-256-gildi er ekki „afkóðað“. Í verkefni með fyrirsjáanlegt SHA-256-tákn endursmíðum við inntakið, reiknum tætigildið og berum það saman.

Göngudæmi: Endurheimt norðurs

Byrjaðu á því að skrá eina venjulega /reset-beiðni í Network eða Burp. Sendu hana í Repeater og breyttu aðeins username milli gervinafnanna sem verkefnið gefur. Berðu saman stöðukóða, svarlíkama, svarhausa og framsendingar. Þegar eitt nafn fær stöðugt annað svar hefurðu frambjóðanda að skráðum gervireikningi.

Næst þarftu að finna nákvæma uppskrift endurheimtartáknsins. Verkefnið á að gefa hana í afmarkaðri vísbendingu; leitaðu í svarinu og þeim skjölum eða JavaScript-skrám sem síðan tengir sjálf. Skráðu notandanafnið, fasta textann, afmarkarann og kóðun textans áður en þú reiknar nokkuð.

Með Python má smíða táknið án þess að senda margar tilraunir:

python3 - <<'PY'
import hashlib

username = "<skráði gervinotandinn>"
separator = "<afmarkarinn úr verkefninu>"
suffix = "<fasti textinn úr verkefninu>"
message = f"{username}{separator}{suffix}".encode("utf-8")
print(hashlib.sha256(message).hexdigest())
PY

Þetta dæmi skilur afmarkarann eftir sem sýnilegan staðgengil. Settu strenginn saman nákvæmlega eins og vísbending verkefnisins segir; ekki bæta tvípunkti við nema hann sé hluti uppskriftarinnar.

Sendu táknið síðan á /reset/confirm með þeirri aðferð og því gagnasniði sem eyðublaðið notar. Geymdu kökur svo endurheimt og innskráning haldist í sömu gervilotu:

curl -i -c cookies.txt -b cookies.txt \
  -X POST "$BASE_URL/reset/confirm" \
  --data 'token=<reiknað tákn>&new_password=<tímabundið gerviaðgangsorð>'

Ef staðfestingin tekst skaltu nota sama cookies.txt þegar þú skráir gervinotandann inn:

curl -i -c cookies.txt -b cookies.txt \
  -X POST "$BASE_URL/login" \
  --data 'username=<gervinotandi>&password=<tímabundið gerviaðgangsorð>'

Að þessu loknu máttu fylgja framsendingunni eftir, eða sækja /account með sömu kökugeymslunni. Kaflinn gefur ekki upp notandann, fasta textann, nákvæma táknið eða fánann; þau eiga að koma úr þinni rannsókn á lifandi verkefninu.

Ef táknið er hafnað skaltu ekki breyta mörgum atriðum í einu. Notaðu repr() til að prenta út strenginn sem þú ætlar að tæta, athugaðu há- og lágstafi, afmarkara og hvort línuskipti hafi slæðst með. Berðu svo aðferð, slóð og reita staðfestingarbeiðninnar saman við venjulega beiðni vafrans.

Fjölþátta auðkenning

Fjölþátta auðkenning (e. multi-factor authentication, MFA) biður um sönnun úr fleiri en einum flokki. Algengir flokkar eru eitthvað sem notandinn veit, eitthvað sem hann hefur og eitthvað sem hann er. Aðgangsorð og öryggisspurning eru bæði þekking; og verða alls ekki talin til tveggja ólíkra þátta, þó svo að tveir innsláttarreitir birtist á skjánum.

Einfalt vefstreymi gæti verið:

POST /login  →  tímabundin mfa-lota  →  POST /mfa  →  full lota

Í CTF liggur veikleikinn oft í tengingunni milli skrefanna fremur en sex stafa kóðanum sjálfum. Hagnýtar spurningar eru til dæmis:

  • Er unnt að hoppa beint á síðuna sem kemur á eftir /mfa með því einu að styðjast við tímabundnu lotuna?
  • Er kóðinn bundinn við sama gervinotanda og hóf innskráninguna?
  • Má endurnota kóða sem verkefnið gaf?
  • Gefur eitt svar upp kóðann eða staðfestir of mikið um hann?

Varastu að beita þrautleit (e. brute force) á kóða gegn raunverulegum þjónustum. Ef gagnaglíma gerir sérstaklega ráð fyrir sjálfvirkri leit þarf verkefnið að afmarka hana skýrt, nota tilbúna reikninga og þola álagið. Að öðrum kosti er yfirgnæfandi líklegt að ætlast sé til þess að finna rökfræðilega hjáleið.

OAuth og OpenID Connect í stórum dráttum

Þegar vefur býður Skrá inn með ... þarf hann ekki sjálfur að taka við aðgangsorði notandans hjá hinni þjónustunni. OAuth er rammi til að veita forriti afmarkaðan aðgang, en OpenID Connect, oft skammstafað OIDC, bætir við auðkennislagi sem hentar innskráningu.

Við skulum nefna hlutverkin áður en við skoðum flæðið:

  • Notandinn á gögnin og samþykkir aðgerð.
  • Biðlarinn er vefurinn sem vill fá auðkenni eða aðgang.
  • Auðkennisveitan (e. identity provider, IdP) auðkennir notandann og gefur út kóða eða tákn.
  • Vefforritaskil afhenda gögn þegar viðeigandi aðgangstákn (e. access token) fylgir.

Einfalt heimildarkóðaflæði lítur svona út:

1. Vefurinn sendir vafrann til auðkennisveitunnar.
2. Notandinn auðkennir sig þar.
3. Auðkennisveitan sendir vafrann á skráða framsendingarslóð með stuttum kóða.
4. Vefurinn skiptir kóðanum fyrir tákn beint við auðkennisveituna.
5. OIDC-upplýsingar segja vefnum hvaða notandi var auðkenndur.

Fyrsta framsending gæti innihaldið:

https://id.example/authorize?
  client_id=nordurmarkadur&
  redirect_uri=https%3A%2F%2Fnordurmarkadur.example%2Fcallback&
  response_type=code&
  state=RANDOMT_GILDI

client_id auðkennir biðlarann. redirect_uri segir hvert auðkennisveitan má senda vafrann aftur. state tengir svarið við flæði sem sami vafri hóf.

Í CTF lesum við hvaða aðili bjó hvert gildi til og hvar það er sannreynt. Sé engum skorðum reist um hvert redirect_uri má vísa, gæti kóðinn auðveldlega ratað á óæskilegan áfangastað. Ef state vantar eða er ekki bundið við lotuna getur svar úr einu flæði blandast við annað. Treysti forritið svo einfaldlega á notandanafn beint úr vafranum í stað staðfests OIDC-svars, er þar á ferðinni enn ein alvarleg traustbrestur.

OAuth/OIDC er flókið og raunverulegar þjónustur hafa mörg afbrigði. Í byrjendaverkefni á lýsingin að afmarka eitt lítið flæði og gefa gervireikninga. Við prófum ekki framsendingarslóðir eða reikningatengingar hjá lifandi auðkennisveitum.

Að lesa vísbendingar gegn tilgátum

Óþarfi er að ætla að hvert einasta innskráningarverkefni verði leyst með notandaupptalningu. Ef tvær reset-beiðnir fá sama stöðukóða, sömu hausa, sama líkama og sambærilegan tíma eftir endurtekningu er lítil ástæða til að halda áfram að giska á nöfn. Leitaðu að annarri vísbendingu.

Sterk, söltuð Argon2- eða bcrypt-kássa ásamt engu afmörkuðu orðamengi bendir sömuleiðis gegn einfaldri kássuleit. 429 og Retry-After benda gegn hraðri sjálfvirkni. Rétt bundið state og nákvæm framsendingarslóð draga úr líkum á einfaldri OAuth-hjáleið.

Góð færni í gagnaglímum felst ekki síst í því að kunna að loka rangri tilgátu. Skráðu vandlega niður hvaða samanburður mælti gegn henni og færðu þig yfir á næsta inntaksstað, fremur en að sóa frekara púðri á ranga leið.

Samantekt

Auðkenning segir til um hver stendur á bak við beiðnina; aðgangsstýring segir til um hvað viðkomandi aðila sé yfirleitt heimilt að gera. Innskráning, endurheimt aðgangs, fjölþátta auðkenning og OIDC eru alltsaman ólíkar leiðir að auðkenndri lotu, og í raun gildir hér að sú leiðin sem hefur veikustu rökfræðina mun ákvarða öryggi heildarinnar.

Í CTF berum við saman afmörkuð svör, lesum stöðukóða og hausa, endursmíðum aðeins tákn sem verkefnið gefur uppskrift að og varðveitum kökur milli skrefa. Við sendum ekki orðalista á raunverulegar innskráningar og túlkum hraðatakmörk sem skilaboð um að endurmeta leiðina.

Næsti kafli tekur við þar sem innskráningu lýkur. Við skoðum hvernig lotuauðkenni og kökur tengja beiðnir við notanda, hvernig lotur breytast við innskráningu og hvernig JWT-tákn eru byggð og sannreynd.