Aðgangsstýring og IDOR
Í síðustu köflum auðkenndum við gervinotanda og fylgdum lotunni hans milli beiðna. Nú veit þjónninn hver sendir beiðnina. Það leysir samt ekki næstu spurningu: má þessi notandi nálgast einmitt þessi gögn eða framkvæma einmitt þessa aðgerð?
Vefur getur krafist innskráningar á öllum reikningssíðum en þó engu að síður afhent Önnu pöntun Bjarna ef hún svo mikið sem breytir einni tölu í slóðinni. Innskráningin virkar þá nákvæmlega eins og að var stefnt; hins vegar skortir sárlega á aðgangsstýringu gagnvart einstöku gögnunum.
Í verkefninu Pöntun annars skráum við okkur inn sem Anna, finnum beiðnina sem sækir hennar eigin pöntun og notum pöntunarauðkenni sem verkefnið gefur vísbendingu um. Markmiðið er alls ekki að giska á þúsundir talna út í bláinn, heldur þvert á móti að prófa eina afmarkaða og skýra tilgátu um eignarhald.
Aðeins tilbúnir reikningar og auðkenni
Prófaðu aðeins gervireikninginn og pöntunarauðkennin sem verkefnið veitir. Ekki telja upp auðkenni, viðskiptavini eða skjöl á raunverulegri þjónustu. Sú staðreynd að vera skráð(ur) inn veitir alls engar heimildir til þess að prófa sig áfram með gögn annarra.
Auðkenning kemur á undan aðgangsstýringu
Auðkenning svarar því hver notandinn í raun er. Aðgangsstýring svarar því aftur á móti hvað téðum notanda er heimilt að gera.
Cookie: session=ANNA
│
▼
auðkenning
„beiðnin er frá Önnu“
│
▼
aðgangsstýring
„á Anna pöntun 1002?“
Sé lotukakan ógild vísar þjónninn notandanum gjarnan rakleiðis á /login. Ef kakan er gild en pöntunin tilheyrir öðrum þarf þjónninn að taka sérstaka ákvörðun um aðgang. Sú staðreynd að fyrra skrefið hafi heppnast gefur engar vísbendingar um hver niðurstaða þess síðara verður.
Þessi aðgreining hjálpar við villugreiningu. Framsending á /login bendir oft og tíðum til þess að eitthvað sé athugavert við lotuna. 403, 404 eða tómt svar aðeins fyrir pöntun annars notanda getur hins vegar bent til eignarhaldsathugunar. Stöðukóðarnir einir og sér sanna vissulega ekki til fulls hvað átti sér stað, en þeir koma þó að góðum notum við að ákveða næsta samanburð.
Hvað er hlutur og hvað er tilvísun?
„Hlutur“ í þessu samhengi er gagnahlutur sem forrit vinnur með: pöntun, reikningur, skjal, skilaboð, mynd eða API-færsla. Forritið útheimtir skýra leið til að segja fyrir um hvaða hlut beiðnin á við hverju sinni. Slík tilvísun getur tekið á sig margvíslegar myndir:
/account/42
/orders/1002
/download?file_id=731
Hún getur líka verið falinn eyðublaðsreitur:
<input type="hidden" name="account_id" value="42">
eða reitur í JSON:
{
"order_id": 1002,
"status": "cancelled"
}
Allt telst þetta til notandastýrðra gagna þegar keppandinn getur átt við sjálfa beiðnina. Orðið hidden í HTML-kóðanum þýðir einungis að vafrinn teikni ekki reitinn á skjáinn; það veitir gildinu enga sanna leynd og gerir það alls ekki traust.
IDOR, Insecure Direct Object Reference, er aðgangsstýringarveikleiki þar sem forrit notar slíka beina tilvísun án þess að tryggja að núverandi notandi megi nálgast hlutinn. Í API-um er sama hugmynd oft kölluð BOLA, Broken Object Level Authorization.
Auðkennið þarf ekki nauðsynlega að vera tala. Eftirfarandi getur einnig flokkast sem IDOR:
/documents/550e8400-e29b-41d4-a716-446655440000
UUID er erfiðara að giska á en 42, en ef verkefnið afhendir UUID Bjarna og Anna getur sótt hlutinn er aðgangsstýringin enn brotin. Það að auðkennið sé fyrirsjáanlegt getur óneitanlega auðveldað fundinn, en rót tilgátunnar liggur alltaf í heimildinni sem tengist sjálfum hlutnum.
Lárétt og lóðrétt réttindaaukning
Lárétt réttindaaukning (e. horizontal privilege escalation) felur í sér að færast á milli aðila sem búa yfir sambærilegum réttindum. Anna les pöntun Bjarna; báðir eru venjulegir notendur.
Anna (user) ─────► gögn Bjarna (user)
Lóðrétt réttindaaukning (e. vertical privilege escalation) merkir aftur á móti færslu upp í öflugra hlutverk eða meiri réttindi. Gott dæmi er þegar venjulegur notandi fær opnað fyrir stjórnendaaðgerðir eða tekur upp á því að breyta sínu eigin role í admin.
Anna (user) ─────► stjórnendaaðgerð (admin)
Sama verkefni getur innihaldið bæði. Slóðin /account/43 gæti verið lárétt próf, en /admin/users lóðrétt. Gerðu glögga grein fyrir því hvaða mörk þú ert að reyna á; að fullyrða aðeins að „aðgangsstýring virki ekki“ er algerlega ónóg og of óljós niðurstaða.
Grunnbeiðnin kemur fyrst
Áður en við breytum auðkenni þurfum við beiðni sem á að virka. Anna sækir eigin pöntun:
GET /orders/1001 HTTP/1.1
Host: nordurmarkadur.example
Cookie: session=ANNA_LOTA
HTTP/1.1 200 OK
Content-Type: application/json
{
"id": 1001,
"owner": "anna",
"item": "Lopapeysa"
}
Næsta tilraun breytir aðeins auðkenninu:
GET /orders/1002 HTTP/1.1
Host: nordurmarkadur.example
Cookie: session=ANNA_LOTA
Ef svarið afhendir pöntun sem greinilega tilheyrir Bjarna höfum við láréttan aðgangsstýringarmun. Sama lota, sama aðferð og sama leiðarmynstur lágu þar til grundvallar; það eina sem breyttist var auðkennið sjálft.
Þessi aðferð, að breyta aðeins einni breytu í einu, skiptir sköpum. Ef við breytum samtímis köku, Host, aðferð og auðkenni vitum við ekki hvaða breyting hafði áhrif. Í Repeater er gagnlegt að hafa grunnbeiðnina í einum flipa og prófbeiðnina í öðrum.
Tvö auðkenni gefa betri mynd en eitt
Þegar prófanir eru heimilaðar reynist afar gagnlegt að hafa yfir að ráða tveimur tilbúnum aðilum og þekktum hlutum. Þá má búa til litla fylki:
| Lota | Hlutur | Vænt niðurstaða |
|---|---|---|
| Anna | Pöntun Önnu | Aðgangur |
| Anna | Pöntun Bjarna | Höfnun |
| Bjarni | Pöntun Bjarna | Aðgangur |
| Bjarni | Pöntun Önnu | Höfnun |
Í kennsluverkefni þarf ekki alltaf að framkvæma allar fjórar beiðnir. Fylkið sýnir samt hvað fullyrðingin merkir. Tilvist pöntunar Bjarna er auðvitað enginn veikleiki. Veikleikinn kristallast hins vegar í því að lota Önnu geti nálgast efni hennar.
Pöntun annars gefur aðeins innskráningu Önnu en lætur pöntunarauðkenni Bjarna koma fram í afmörkuðu gerviefni. Slíkt afmarkar verkefnið tryggilega við eina, heimilaða samanburðartilraun og afstýrir því að lausnin breytist í innantóma talnaskönnun.
Ekki rugla opinberu efni við IDOR
Ef /products/1002 er opinber vörusíða er aðgangur Önnu að henni ekki réttindaaukning. Leitaðu frekar að skýrum merkjum sem benda til ætlaðs eignarhalds eða takmarkana: eigandanafn, einkaskjal, reikningsgögn eða hegðun við eigin hlut.
Slóðin er ekki eini inntaksstaðurinn
API getur tekið hlutauðkenni úr fyrirspurnarstreng:
GET /api/order?order_id=1002 HTTP/1.1
Host: nordurmarkadur.example
Cookie: session=ANNA_LOTA
Eyðublað getur sent það í líkama:
POST /download HTTP/1.1
Host: nordurmarkadur.example
Cookie: session=ANNA_LOTA
Content-Type: application/x-www-form-urlencoded
file_id=731
Og JSON getur innihaldið fleiri en eina tilvísun:
PATCH /api/orders/1001 HTTP/1.1
Host: nordurmarkadur.example
Cookie: session=ANNA_LOTA
Content-Type: application/json
{"owner_id":43,"shipping_address_id":88}
Þarna gæti viðkomandi API-leið vissulega flett upp eignarhaldi á pöntun 1001 en flaskað alfarið á því að tryggja að heimilisfangið 88 tilheyri sama notanda. Prófa þarf hvert hlutverk auðkennis sérstaklega, með gögnum sem verkefnið gefur.
Nöfn eins og user_id, account, owner, tenant, team, project_id, document og invoice eru góðar vísbendingar í Network og JavaScript. Tilkoma þeirra er vitaskuld engin lokasönnun fyrir veikleika; þau hjálpa okkur hins vegar við að kortleggja á hvaða hluti beiðnin beinist.
Falinn hnappur og óþekkt slóð
Við sáum í JavaScript-kaflanum að óvirkur hnappur er viðmótsregla. Sama á við um að fela stjórnendatengil:
<!-- aðeins birt ef role == "admin" -->
<a href="/admin/export">Flytja út notendur</a>
Venjulegur notandi getur samt skrifað /admin/export í slóðarstikuna eða sent beiðni í Repeater. Spurningin er hvort þjónninn athugi hlutverkið.
Slóð getur komið fram í JavaScript, HTML-athugasemd, Location-haus eða fyrri beiðni. Að rannsaka slíka verkefnissértæka slóð er allt annar handleggur en að láta dæluna ganga á langan lista af hugsanlegum stjórnendaslóðum. Við reiðum okkur á tækar vísbendingar og afmarkað umfang, ekki einskæra handahófsskönnun.
Opni falinn tengill fyrir sömu stjórnendasíðu undir lotu venjulegs notanda, horfumst við í augu við lóðréttan veikleika. Skili hann á hinn bóginn stöðukóða á borð við 403, framsendi á innskráningu eða sýni einungis opinbera innskráningarsíðu, hefur beiðnin með engu móti getað staðfest neina réttindaaukningu.
Aðferðir geta farið í ólíkan kóða
Þjónn getur athugað aðgang fyrir GET /admin/users en gleymt samsvarandi athugun fyrir POST, PUT eða DELETE. 405 Method Not Allowed og Allow geta sagt hvaða aðferðir leiðin styður.
Við rjúkum þó ekki til og breytum um aðferð að óþörfu. Leitaðu að eyðublaði, JavaScript-kalli, API-skjali eða Allow-haus sem sýnir eðlilega aðferð. Sú iðja að beita DELETE á handahófskenndar slóðir ber ekki aðeins vott um afleita rannsóknarvinnu heldur getur hún reynst beinlínis skemmdarverk. Æfingarnar í þessari leið nota annaðhvort lesaðgerðir eða endurstillanleg gervigögn.
Sum forrit styðja aðferðayfirskrift eins og formreitinn _method=DELETE eða hausinn X-HTTP-Method-Override. Slíkt er einungis fýsilegt rannsóknarefni ef verkefnið sjálft eða veframminn gefur einhverjar vísbendingar um slíka hegðun. Að öðrum kosti telst mun hreinlegra að breyta aðferðinni beint innan Repeater.
Fjölleigukerfi bæta við einu eignarhaldslagi
Í fjölleigukerfi (e. multi-tenant system) deila mörg lið, fyrirtæki eða verkefni sama forriti en gögn þeirra eiga að vera aðskilin. Heimild til aðgangs kann í slíkum tilfellum að ráðast af samspili fleiri en eins þáttar:
notandi → aðild að teymi → hlutur innan teymis
Beiðni gæti sent bæði tenant_id og document_id:
{
"tenant_id": "north-team",
"document_id": "budget-2026"
}
Sé þjónninn svo auðtrúa að hann leggi fullt traust á tenant_id beint upp úr líkamanum, opnast fyrir þann möguleika að notandi geti flakkað á milli leigjenda án þess svo mikið sem að skipta um lotu. Ef hann athugar teymið en sækir skjalið aðeins eftir document_id gæti skjal úr öðru teymi runnið í gegn.
Í CTF þarf verkefnið að gefa gerviteymi og þekkt auðkenni. Ekki reyna að finna raunveruleg fyrirtækjanöfn eða UUID. Sú kerfisbundna spurning sem við þurfum að leggja fyrir okkur er: Hvaða tengsl á þjónninn með réttu að staðfesta fyrir þennan tiltekna hlut, og hvaða tengsl virðist sárlega vanta upp á?
Kóðavísbendingar í verkefni með frumkóða
Ef verkefni afhendir Flask-kóða gæti viðkvæm leið litið svona út:
@app.get("/orders/<int:order_id>")
@login_required
def order(order_id):
row = db.execute(
"SELECT * FROM orders WHERE id = ?",
(order_id,),
).fetchone()
return render_template("order.html", order=row)
@login_required segir að einhver innskráður notandi þurfi að senda beiðnina. Fyrirspurnin velur hins vegar pöntun aðeins eftir id. Í þessu broti finnst nákvæmlega ekkert sem tryggir tengsl pöntunarinnar við auðkenni núverandi notanda.
Sama mynstur getur falist á bak við ORM-kall:
order = Order.query.get(order_id)
ORM gerir leitina þægilega en bætir ekki sjálfkrafa við eignarhaldi. Í lausnum okkar útskýrum við ekki einungis að um „IDOR“ sé að ræða, heldur afhjúpum við sjálfa röklegu villuna: Forritið gengur einfaldlega út frá því sem gefnu að innskráður notandi muni aldrei senda neitt annað en auðkenni sinna eigin pantana.
Kóðabrotið er tvímælalaust sterk vísbending, en það er fyrst og fremst HTTP-prófið sjálft sem dregur raunveruleg áhrif þess fram í dagsljósið. Innifeli gagnagrunnurinn til að mynda einungis gögn sem notandinn á nú þegar sjálfur, eða ef eitthvert annað kerfislag tekst á við að sía svarið, getur stakt og einangrað kall teiknað upp afskaplega ófullkomna mynd af stöðunni.
Göngudæmi: Pöntun annars
Opnaðu verkefnið og skráðu þig inn með gervireikningi Önnu. Geymdu kökuna með vafranum, Burp eða curl:
BASE_URL='https://slod-verkefnisins.example'
curl -i -c cookies.txt -b cookies.txt \
-X POST "$BASE_URL/login" \
--data 'username=<notandi Önnu>&password=<aðgangsorð úr verkefninu>'
Sæktu /orders með sömu kökugeymslu og finndu tengilinn á pöntun Önnu. Opnaðu hana og varðveittu beiðnina sem grunnbeiðni:
curl -i -c cookies.txt -b cookies.txt \
"$BASE_URL/orders/<auðkenni pöntunar Önnu>"
Staðfestu að svarið nefni Önnu. Finndu síðan pöntunarauðkenni Bjarna í þeirri gervivísbendingu sem verkefnið býður upp á. Endursendu sömu beiðni með aðeins því auðkenni:
curl -i -c cookies.txt -b cookies.txt \
"$BASE_URL/orders/<auðkenni pöntunar Bjarna>"
Í Repeater er gott að setja beiðnirnar hlið við hlið. Cookie, aðferð og allt leiðarmynstrið eiga að vera eins; auðkennið er eina breytan. Ef seinna svarið sýnir eiganda Bjarna og einkagögn hans hefur lota Önnu fengið hlut sem hún á ekki.
Ef beiðnin framsendist á /login skaltu fyrst athuga hvort lotukakan fylgi. Ef hún skilar 404 eða 403 skaltu bera svarið saman við örugglega óþekkt auðkenni aðeins ef verkefnið heimilar slíkt. Gættu þess þó að túlka ekki hverja einustu höfnun sem „falið IDOR“; markmiðið er að sýna óheimilað efni, ekki aðeins ólíkan kóða.
Fáninn er í athugasemd pöntunar Bjarna. Kaflinn gefur hvorki auðkennið né fánann. Hvort tveggja muntu þurfa að grafa upp í hinu lifandi verkefni.
Hvenær tilgátan stenst ekki
Sú athöfn ein að breyta 1001 í 1002 og fá 403 sem svar jafngildir á engan hátt IDOR-veikleika. Að fá 200 með almennri villusíðu sýnir það heldur ekki; stöðukóði og raunveruleg áhrif geta auðveldlega farið hvort í sína áttina. Finndu gögn eða aðgerð sem tilheyra öðrum tilbúnum aðila.
Styðjist þjónninn við óhemju langt og slembið auðkenni sem hvorki er gefið upp né gert aðgengilegt á eðlilegan hátt, má telja nánast útilokað að upptalning sé hin ætlaða lausn. Ef bæði hlutanúmer og owner_id eru undirrituð og hver breyting er stöðugt höfnuð er einföld tilvísunarbreyting ólíkleg.
Stundum vill brenna við að einungis ytra útlitið breytist, vegna þess að JavaScript heldur ótrautt áfram að sækja sín eigin gögn eftir allt annarri API-leið. Skoðaðu Network og staðfestu hvaða svar innihélt upplýsingarnar. IDOR er klárlega veikleiki í þjóninum sjálfum, og felst ekki í því einu að geta skrifað nafn Bjarna ofan í flipann Elements.
Samantekt
Vera innskráðs notanda veitir honum ekki sjálfkrafa óskoraða heimild til allra hluta. IDOR eða BOLA kemur upp þegar notandastýrð tilvísun velur hlut og þjónninn tengir hann ekki rétt við notanda, hlutverk eða leigjanda. Auðkennið getur verið tala, UUID, skráarheiti, falinn formreitur eða JSON-gildi.
Lárétt próf færist milli sambærilegra notenda; lóðrétt próf reynir öflugra hlutverk eða aðgerð. Kjörin byrjunarprófun styðst við þekkta gervihluti, gildandi eigin lotu og gerir framar öllu aðeins eina breytingu í senn. Við sýnum alltaf fram á óheimilaðan aðgang með raunverulegu og afgerandi svari, en látum okkur ekki nægja að benda á að slóðinni einni hafi verið breytt.
Næst förum við yfir í SQL-innskot. Þar er auðkenni eða leitarstrengur ekki aðeins notaður til að velja hlut; rangt samsettur texti getur breytt sjálfri gagnagrunnsfyrirspurninni.