Įvadas

Šiais metais NKSC (Nacionalinis kibernetinio saugumo centras) organizavo tarpmokyklines CTF varžybas Cyber maratonas. Šiose varžybose dalyvavo mūsų komanda ZeroDayTeam ir po šių varžybų norėčiau pasidalinti savo patirtimi.

Varžybose iš komandos dalyvavo du dalyviai: V1lkius ir zerodaygym.

Apie rungtynes

“Cyber maratonas” buvo 3 ciklų CTF varžybos, tai reiškia, kad užduotys yra paleidžiamos atskirai į kiekvieną ciklą, o pertraukos tarp ciklų yra tarp 2-3 mėnesių. Kiekviename cikle nugalėtojas yra išrenkamas pirmiausiai pagal komandos taškus, paskui pagal užduoties išsprendimo laiką. Varžybų nugalėtojas yra renkamas pagal sudėtinį visų ciklų komandinių taškų kiekį.

Patirtis

Pirmasis ciklas

Pirmasis ciklas, kaip mūsų komanda ir tikėjosi, buvo ganėtinai paprastas ir užduotys buvo nesunkiai išsprendžiamos. Kadangi jau turėjome gana nemažai patirties CTF užduočių sprendime, visas užduotis, išskyrus vieną, išsprendėme per ~40 min. Paskutinė likusi užduotis vadinosi „Gilaus tinklo slaptažodžių grupių himnas“ ir buvo verta 80 taškų (vidutinis užduoties sunkumas).

Nekreipdami dėmesio į labai neaiškiai suformuluotą užduotį (kurios aprašymas po kelių dienų buvo patobulintas organizatorių), mes šią užduotį intensyviai sprendėme 3 dienas, be jokių hint’ų (organizatoriai suteikia hint’us paskutinę ciklo dieną). Paskutinę dieną sulaukėme hint’o ir beveik iškart išsprendėme užduotį. Paaiškėjo, kad sprendimas buvo paprasčiausiai apsukti tekstą ir uudekoduoti. Sprendimas pasirodė pakankamai logiškas ir nors mums ir nepatiko ši užduotis dėl jos paprastumo, mes supratom, kad, kaip komandai, mums reikia patobulėti ties kriptografija.

Pirmąjį ciklą iškarto pastebėjome, kad užduotys nėra standartiškos (nebuvo reguliarių kategorijų, kaip PWN ar Web) ir didžioji dalis jų tebuvo kriptografija arba steganografija. Tačiau to ir tikėjomės iš CTF, kuris buvo ruošiamas moksleiviams, kurie, dažnu atveju, nėra susipažinę su kibernetinio saugumo pasauliu.

Pirmąjame cikle mūsų komanda užėmė 2 vietą, VL (Vilniaus Licėjaus) komandai atlikus paskutinę likusią užduotį keliomis valandomis greičiau už mus.

Antrasis ciklas

Antrasis ciklas buvo, taip pat, ganėtinai paprastas. Didžiąją dalį užduočių išsprendėme gana greitai, ir paskutinę likusią rev tipo užduotį išsprendėme antros dienos pradžioj. Antrajame cikle užduočių monotoniškumas pasireiškė dar stipriau. Užduočių tipai buvo tokie patys, kaip ir pirmame cikle: labai daug steganografijos, kriptografijos ir tik viena pasirodžiusi įdomesnė rev tipo užduotis.

Labai aiškiai buvo matomi organizatorių bandymai sukurti užduotis, kurios nebūtų išsprendžiamos AI agentų, ką aš gerbiu ir tikiu, kad tai turėtų būti skatinama. Tačiau jau šiame etape pasimatė ir AI unsolvable užduočių kūrimo minusas - užduočių suprastėjusi kokybė. Mūsų komanda, kaip ir kelios kitos su kuriomis bendravome, tiek pirmo, tiek antro etapo užduotimis, jau tuo metu, buvo pakankamai nusivylusi. Atrodė, kad užduotys buvo sukurtos be idėjos, užduotyse buvo rodomi tik keli triukai, kuriuos buvo sunku ne exploit'int, o tiesiog surasti. Tikriausiai daug kas su manimi gali nesutikti ir sakyti, kad CTF tikslas ir yra surasti kelią, kaip išspręsti užduotį. Tačiau jeigu užduotis turi vieną neaiškų sprendimą, kurio tiesiog reikia ieškoti per spėliojimą, nežinant ar eini teisingu keliu, ar esi visiškame rabbit hole, kuris niekur neveda, tai nėra gera užduotis.

Trečias ciklas ☠️

Trečias etapas žadėjo daug, ypač dėl naujos „Web“ kategorijos, tačiau organizatoriai nepasimokė iš savo klaidų. Logiškos užduotys buvo išspręstos žaibiškai. Galiausiai mes ir komanda „Kvantai“ atsidūrėme situacijoje, kai iki finišo trūko vos trijų užduočių.

Pirmoji iš likusių užduočių

Pirmoji iš likusių 3 užduočių vadinosi Agento kišenė. Joje buvo duoti du failai: tekstinis failas Priminimas.txt ir paveiksliukas, kuris buvo agento kortelės logotipas.

Paveiksliukas iš išvaizdos atrodė visiškai paprastai:

Agento kisne

Tačiau paveiksliuko metadatoj buvo užslėpta daug skirtingų duomenų, kas atrodė kaip užuomenos:

Antrame tekstiniame faile buvo matoma, kas iš pradžių atrodė kaip paprastas tekstas, tačiau įsigilinus ir apžiūrėjus visus failo baitus buvo matomi užslėpti specialūs non ascii-readable baitai:

Iš pradžių tai atrodė kaip įdomi užduotis, visa komanda pradėjo labai intensyviai ieškoti informacijos apie užslėptus baitus, tačiau šios užduoties mums nepavyko išspręsti. Tikėjomės, jog atsakymas yra kažkas sudėtingo ir įdomaus, tačiau sužinoję atsakymą labai nusivylėme. Pasirodo, paveikslėlyje užslėpta informacija, tekstiniame faile užslėpti specialūs baitai tebuvo klaidinanti informacija, viskas ką reikėjo padaryti tebuvo kaip flag'ą pateikti raudonos spalvos hex kodą, kuri buvo paveikslėlyje.

Atsakymas: ctf_cm{dc0906}

Organizatoriai paaiškino, jog iš tekstinio failo reikėjo suprasti Raudona, žalia, mėlyna, kaip RGB (kas buvo aišku nuo pat pradžių), ir todėl reikėjo paimti hex kodą spalvos, buvusios paveiksliukyje.

Nors ir šis paaiškinimas yra iš dalies logiškas, bet tie nieku nevedantys rabbit hole'ai, su kuriais susidūrėme ne mes vieni ir kurie nieko nepridėjo prie edukacinės vertės, bei flag'o formato nebuvimas sukėlė daug klausimų, koks išvis buvo šitos užduoties tikslas.

Antroji iš likusių užduočių

Antroji iš likusių užduočių vadinosi Paint paslaptis. Joje buvo duotas ~19mb didumo painter.exe failas. Tai buvo piešimo programėlė sukurta Windows operacinei sistemai.

Mano komandos narys Vilkius labai didelę dalį laiko praleido analizuodamas programos kodą, jį reverse engineerindamas ir aiškindamasis, kaip programa veikia. Po daug laiko jis išsiaiškino, jog programa iš tikrųjų nieko kenksmingo nedaro ar net nieko neslepia, vienintelis dalykas, kur jis kažką rado tai buvo cm{1 simbolius vienoje iš programos ikonėlių, kas atrodė kaip ctf_cm{...} flag'o formato pradžios dalis. Šioje vietoje jis neklydo ir mes pradėjom labiau gilintis į programos ikonėles, kas buvo teisingas kelias. Tačiau net 4 dienas sėdėdami ir bandydami aiškintis skirtingus būdus rasti ir atkoduoti skirtingas flag'o dalis, geriausia, ką mums pavyko atkoduoti buvo ctf_cm{1c0n5_uplMkhad!cr3u}, kas atrodė kaip pradžia, bet tikrai ne galutinis flagas. Baigusis CTF’ui Kvantų komanda, kuriai pavyko išspręsti šią užduotį, draugiškai pasidalino užduoties sprendimu. Jie mums pasakė, kad po labai daug token'ų, jų AI išsprendė šią užduotį ir davė sprendimą. Su dirbtinio intelekto pagalba paredagavau jų šį jų pasidalintą sprendimą ir pateikiau jį žemiau.

Perskaitęs užduoties sprendimą pakalbėjau su komanda (tokią nuomonę turėjo ir kitos komandos) ir mes visi pritarėm, jog ši užduotis yra visiškai absurdiška ir neišsprendžiama žmogui. Flag'o dalys buvo ištraukiamos iš visiškai atsitiktinių vietų programoje ir tarp jų nesimatė jokios logiškos sąsajos. Net organizatoriai nesugebėjo paaiškinti šio sprendimo kelio ir kodėl flag'o dalys buvo būtent taip išmėtytos. Ties šia užduotimi praleidome labai daug laiko, tačiau galiausiai likome tikrai nusivylę jos sprendimu.

Trečioji iš likusių užduočių

Ši užduotis vadinosi Iš ko statomi Vilko namai?, tai buvo web kategorijos užduotis, kurioje buvo pateikta svetainė.

Ties šia užduotimi praleidau daugiausiai laiko. Pakankamai greitai išsiaiškinau, kad visi svetainės endpoint'ai buvo statiniai apart vieno /api/proxy. Šis endpoint turėjo path parametrą su kuriuo serveris darė HTTP GET requestus į nurodytą kelią. Kas blokavo vartotoją nuo paprašymo visiškai, bet kokio kelio buvo reikalavimas, kad kelias prasidėtų su /assets/ ir, taip pat, visi path traversal bandymai tokie kaip ../, bandant pabėgti iš leidžiamo kelio buvo neleistini. Pakankamai greitai, jau pačią pirmą dieną išsiaiškinau, kad šį blokavimą galima apeiti su trigubu URL kodavimu ties .. simboliais, taigi /api/proxy?path=/assets/%25252e%25252e/index.html suteikė serverio užklaustą /index.html puslapį. Ties šia vieta užstrigau, kadangi iš serverio nesugebėjau gauti jokių naujų failų. Tris dienas praleidau ties šita vieta: naudodamas labai daug bruteforce su skirtingais wordlist'ais ieškojau naujų kelių, ieškojau kitų bug'ų, kuriuos sujungęs galėčiau kažką naujo pasiekti (radau, kad serveris buvo pažeidžiamas CL.0 HTTP Request Smuggling, cache deception bei cache poisoning, tačiau tai niekur nenuvedė). Per šias tris diena kelis kartus prašiau organizatorių patikrinti, ar tikrai užduotis yra išsprendžiama, ar WAF (Web Application Firewall neblokuoja jokių užklausų, tačiau du kartus buvau patikintas, kad užduotis yra išsprendžiama. Galiausiai varžyboms baigusis užduoties kūrėjas atsiuntė šios užduoties sprendimą. Pats pirmas žingsnis buvo:

1 žingsnis: pasiekti vidinį registry per proxy

RESP=$(curl -sG "$BASE/api/proxy" --data-urlencode 'path=/assets/%252e%252e/internal/registry/current') echo "$RESP" | jq .

Ties pirmu žingsniu man iš karto kilo klausimas, kaip reikėjo nežinant gauti /internal/registry/current kelią. Testuojant, net teisingas atspėtas directory nebuvo niekaip skirtingas nuo paprasto neegzistuojančio kelio. Peržiūrėjęs visus savo bruteforce sąrašus supratau, kad nebuvo jokių logiškų būdų atspėti šį kelią. Paklausus organizatorių jie pirmiausiai kovojo, jog tai buvo galima išmąstyti, kadangi /registry/current kelias yra pakankamai dažnas docker aplinkoje, tačiau, kaip atspėti /internal/ jie patys negalėjo atsakyti. Galiausiai pasigilinę jie suprato, jog ši užduotis yra neišsprendžiama ir parašė atsiprašymą dalyviams.

Rekomendacijos organizatoriams

Kadangi su komanda esame dalyvavę ne viename CTF’e ir matę pačių įvairiausių varžybų formatų, turime kelis pastebėjimus bei rekomendacijas organizatoriams. Visų pirma, siūlytume įvesti privalomą testavimą su žmonėmis, kurie tų užduočių nekūrė - tai padėtų išvengti situacijų, kai vietoje techninių žinių tenka tiesiog spėlioti autoriaus mintis bei padėtų sumažinti ar pilnai eliminuoti neišsprendžiamų užduočių kiekį. Taip pat vertėtų atsisakyti painių mįslių, kurios neturi nieko bendro su kibernetiniu saugumu, ir kurti iššūkius, paremtus realiomis pažeidžiamumų paieškos situacijomis. Galiausiai, labai svarbu suskirstyti užduotis į kategorijas, įsitikinti, kad užduotys atitiktų savo kategorijas, o po renginio būtų dalinamasi išsamiais oficialiais sprendimais (write-ups), iš kurių būtų galima pasimokyti.

Apibendrinimas

Apibendrinant mūsų komandos patirtį visuose trijuose „Cyber maratono“ etapuose, tenka pripažinti, kad varžybos paliko dvejopą įspūdį. Aš tikrai gerbiu Nacionalinį kibernetinio saugumo centrą (NKSC/CERT-LT) už iniciatyvą ir bandymą įtraukti Lietuvos jaunimą į kibernetinio saugumo sritį, tačiau tenka pripažinti, kad pačiu šių CTF varžybų formatu bei kokybe esu labai nusivylęs.

Nors pasitaikė viena kita įtraukianti užduotis, daugelis jų atrodė realiame gyvenime nepritaikomos ir sukurtos tik tam, kad užpildytų varžybų turinį. Didžioji dalis užduočių neturėjo gilesnės idėjos ir pademonstravo tik pavienes, neišskirtines technikas. Užduotims smarkiai trūko loginės sekos, sprendimus tekdavo aklai spėlioti, o dažnu atveju susidarė įspūdis, jog jos buvo tiesiog nekokybiškai sugeneruotos dirbtinio intelekto. Trečiajame etape, praleidus daugybę laiko prie „Iš ko statomi Vilko namai?“ užduoties ir net kelis kartus gavus organizatorių patikinimus dėl jos išsprendžiamumo, galiausiai paaiškėjo apmaudi tiesa – su turima informacija jos išspręsti buvo neįmanoma.

Bendra šių varžybų kokybė mūsų komandą labai nuvylė. Užduotys buvo silpnos ir paviršutiniškos, o iš tokios institucijos kaip NKSC tikėjomės gerokai aukštesnio, profesionalesnio ir į realių įgūdžių ugdymą orientuoto lygio. Tikimės, kad organizatoriai atsižvelgs į šią kritiką ir ateities kibernetiniai maratonai bus daug labiau apgalvoti.