Një nga pjesëmarrësit e konkurrencës UIUCTF 2025, shpjegoi në detaje se si ia arriti të përmbushë një detyrë që kërkonte ekzekutimin e kodit të tij në server, duke pasur vetëm mundësinë për të ndryshuar përmbajtjen e tekstit të komenteve në kod.
Pjesëmarrësit mund të dërgonin një kërkesë rrjeti në një skript Python, i cili krijonte një skript të ri Python me një emër të rastësishëm, shtonte të dhënat e marra nga përdoruesi në tekstin e komenteve, duke hequr karakteret "\n" dhe "\r", dhe e ekzekutonte këtë skript me komandën "python3 emri.py". Duke kontrolluar vetëm përmbajtjen e komenteve, pjesëmarrësi duhej të nxirrte një varg nga skedari "/home/ctfuser/flag". Skripti krijohej me kodin e mëposhtëm: comment = input("> ").replace("\n", "").replace("\r", "") code = f"""print("hello world!") # Ky është një koment. Ja një tjetër: # {comment} print("Thanks for playing!")"""
Në vend të "{comment}" ishin vendosur të dhënat e marra nga pjesëmarrësi, dhe në fund u ekzekutua kodi i mëposhtëm: print("hello world!") # Ky është një koment. Ja një tjetër: # Të dhënat e marra nga pjesëmarrësi i konkurrencës print("Thanks for playing!")
Detyra u formua mbi motivin e një dobësie në parserin CPython, i cili trajtonte karakterin me kod zero si një përfundim të vargut (kjo dobësi mund të përdorej për të fshehur veprime malinj në tekstin e komenteve). Problemi u zgjidh në versionet CPython 3.12.0 dhe 3.11.4. Në trajtuesin e përdorur në konkurs, vetëm karakteret "\n" dhe "\r" hiqeshin, por nëse pjesëmarrësi do të përdorte versionin e dobët të CPython, do të mund të përdorte karakterin "\0" si ndarës. Megjithatë, ky truk nuk funksionoi pasi në konkurs u përdor një version i rregulluar i CPython me supozimin se mund të mbeteshin të tjera gabime të ngjashme dhe pjesëmarrësit mund t'i identifikonin ato.
Pjesëmarrësi që ia doli me sukses me detyrën nuk filloi të kërkonte dobësi të reja në parser që do të mundësonin ndarjen e vargut në pjesë, por shfrytëzoi veçorinë e ekzekutimit në Python të skedarëve sipas llojit të përmbajtjes së tyre. Për shembull, në vend të kodit burimor në një skedar me një prapashtesë " .py ", mund të vendosësh kodin e shpërndara të ruajtur në skedarë me prapashtesë " .pyc ", dhe një skedar i tillë do të ekzekutohej. Në këtë konkurs, pjesëmarrësi mund të kontrollonte vetëm përmbajtjen në mes të skedarit, prandaj nuk mund të shtonte titullin e tij për të deformuar llojin MIME.
Problemi u zgjidhjes Ă«shtĂ« zgjidhur duke pĂ«rdorur faktin se Python, duke filluar nga dega 2.6, mund tĂ« ekzekutojĂ« pĂ«rmbajtjen e ZIP-arkivave pĂ«r shpĂ«rndarjen e paketave Python nĂ« formĂ«n e kompresuar. Ashtu siç ndodh me ĐșĐ”Ńin e баĐčŃĐșĐŸĐŽĐ°, prania e zip-arkivit pĂ«rcaktohet nga pĂ«rmbajtja, jo nga zgjedhja e skedarit, qĂ« do tĂ« thotĂ« se nĂ« "file.py" mund tĂ« vendosni njĂ« zip-arkiv dhe kur ekzekutoni komandĂ«n "python file.py", ai do tĂ« pĂ«rpunojĂ« si njĂ« paketĂ« Python tĂ« kompresuar. NĂ« tĂ« njĂ«jtĂ«n kohĂ«, ZIP-arkivat nĂ« Python indeksohen jo sipas titullit nĂ« fillim tĂ« skedarit, por sipas seksionit EOCD (End of Central Directory Record) nĂ« fund tĂ« skedarit. NĂ«se nĂ« arkiv ka njĂ« skedar "__main__.py", ky skedar e merr automatikisht pĂ«rparĂ«sinĂ« gjatĂ« ekzekutimit tĂ« drejtpĂ«rdrejtĂ« tĂ« arkivit me komandĂ«n "python archive".
Problemi konkurrues u zgjidh duke gjeneruar njĂ« ZIP-arkiv tĂ« ngjashĂ«m dhe duke e vendosur atĂ« nĂ« tekstin e komenteve. PĂ«r tĂ« ruajtur saktĂ«sinĂ« e strukturĂ«s sĂ« skedarit nĂ« kushte tĂ« pranishme nĂ« fund tĂ« skedarit origjinal, me thirrjen âprint(âThanks for playing!â)â, u pĂ«rdor prania e seksionit EOCD tĂ« zonĂ«s sĂ« komenteve, e vendosur nĂ« fund tĂ« arkivave.

Burimi: opennet.ru
