Prije nekoliko dana otkrio metod za zaobilaženje Python-ovih izolovanih sistema za izvršavanje koda, zasnovan na korištenju dugo poznate greške koja se pojavila u Pythonu 2.7, identificirane 2012. godine, a koja još nije ispravljena u Pythonu 3.
To se spominje greška omogućava korištenje posebno vezanog python koda za iniciranje poziva u memoriju koja je već oslobođena (Use-After-Free) u Pythonu. U početku se pretpostavljalo da greška ne predstavlja sigurnosnu prijetnju i samo u vrlo rijetkim slučajevima, obično umjetno stvorenim, može dovesti do abnormalnog prekida rada skripte.
Istraživač sigurnosti pod pseudonimom kn32 zainteresirao se za problem i uspio je pripremiti funkcionalni exploit koji omogućava pozivanje bilo koje sistemske naredbe bez direktnog pristupa metodama kao što je os.system.
Eksploatacija je implementirana u čistom Python-u i radi bez uvoza vanjskih biblioteka i bez instaliranja drajvera "code.__new__". Od kukica se koristi samo "builtin.__id__", što generalno nije zabranjeno. S praktične strane, predloženi kod se može koristiti za zaobilaženje mehanizama izolacije u različitim servisima i okruženjima (na primjer, u okruženjima za učenje, mrežnim ljuskama, ugrađenim kontrolerima, itd.) koji omogućavaju izvršavanje Python koda, ali ograničavaju dostupne poziva i ne dozvoljava metode pristupa kao što je os.system.
Predloženi kod je analog poziva os.sistema, koji funkcioniše tako što iskorištava ranjivost u CPython-u. Eksploatacija radi sa svim verzijama Python 3 na x86-64 sistemima i stabilna je na Ubuntu 22.04 čak i sa omogućenim PIE, RELRO i CET sigurnosnim režimima.
Posao svodi se na dobijanje informacija o adresi jedne od funkcija iz Python koda u CPython izvršnom kodu.
Na osnovu ove adrese izračunavaju se osnovna adresa CPython-a u memoriji i adresa funkcije system() u učitanoj libc instanci. Na kraju, direktan prijelaz na dati adresni sistem počinje zamjenom pokazivača prvog argumenta stringom "/bin/sh".
Najlakši pristup eksploataciji je kreiranje liste dužine jednake dužini oslobođenog bafera, kojoj će najvjerovatnije svoj bafer stavki (ob_item) dodijeliti na istom mjestu kao i oslobođeni bafer.
To će značiti da ćemo dobiti dva različita "pogleda" na isti komad sjećanja. Jedan pogled, memoryview, misli da je memorija samo niz bajtova u koje možemo proizvoljno pisati ili čitati iz njih. Drugi pogled je lista koju smo kreirali, koja misli da je memorija lista PyObject pokazivača. To znači da možemo kreirati lažne PyObject e-poruke negdje u memoriji, upisati njihove adrese na listu pisanjem u memoryview, a zatim im pristupiti indeksiranjem liste.
U slučaju PoC-a, oni upisuju 0 u bafer (red 16), a zatim mu pristupaju pomoću print(L[0]). L[0] dobija prvi PyObject* koji je 0, a zatim print pokušava pristupiti nekim poljima u njemu, što rezultira nultom dereferenciranjem pokazivača.
To se spominje ova greška je prisutna u svim verzijama python-a od najmanje python-a 2.7 i iako je eksploatacija dizajnirana da radi na gotovo svakoj verziji Pythona 3, to ne znači da se ne može reproducirati u Pythonu 2 (prema autoru).
Svrha eksploatacije je pozivanje system("/bin/sh") čiji su koraci sledeći:
- CPython curenje binarne funkcije pokazivača
- Izračunajte CPython osnovnu adresu
- Izračunajte adresu sistema ili vašeg PLT stuba
- Skočite na ovu adresu sa prvim argumentom koji ukazuje na /bin/sh
- Pobeda
Na kraju, spomenuto je da eksploatacija neće biti korisna u većini konfiguracija. Međutim, može biti korisno za Python tumače koji pokušavaju izolirati kod, ograničavaju uvoz ili koriste zakačke za kontrolu.
Konačno ako ste zainteresirani da saznate više o tome o napomeni, možete pogledati originalnu publikaciju u sljedeći link.