LOAD_NAME / LOAD_CONST opcode OOB Read
Last updated
Last updated
Leer & oefen AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Leer & oefen GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Hierdie inligting is geneem uit hierdie skrywe.
Ons kan die OOB leesfunksie in LOAD_NAME / LOAD_CONST opcode gebruik om 'n simbool in die geheue te kry. Dit beteken om 'n truuk soos (a, b, c, ... honderde simbole ..., __getattribute__) if [] else [].__getattribute__(...)
te gebruik om 'n simbool (soos funksienaam) te kry wat jy wil hê.
Dan kan jy net jou ontploffing saamstel.
Die bronne kode is redelik kort, bevat slegs 4 lyne!
U kan willekeurige Python-kode invoer, en dit sal gecompileer word na 'n Python-kode objek. egter co_consts
en co_names
van daardie kode objek sal vervang word met 'n leë tupel voordat daardie kode objek geëvalueer word.
So op hierdie manier, sal alle uitdrukkings wat konstantes bevat (bv. getalle, strings ens.) of name (bv. veranderlikes, funksies) uiteindelik 'n segmentasiefout kan veroorsaak.
Hoe gebeur die segfault?
Kom ons begin met 'n eenvoudige voorbeeld, [a, b, c]
kan in die volgende bytecode gecompileer word.
Maar wat as die co_names
'n leë tupel word? Die LOAD_NAME 2
opcode word steeds uitgevoer, en probeer om waarde van daardie geheue-adres te lees waar dit oorspronklik behoort te wees. Ja, dit is 'n out-of-bound lees "kenmerk".
Die kernkonsep vir die oplossing is eenvoudig. Sommige opcodes in CPython, byvoorbeeld LOAD_NAME
en LOAD_CONST
, is kwesbaar (?) vir OOB lees.
Hulle haal 'n objek uit indeks oparg
van die consts
of names
tupel (dit is wat co_consts
en co_names
onder die oppervlak genoem word). Ons kan na die volgende kort snippest oor LOAD_CONST
verwys om te sien wat CPython doen wanneer dit na die LOAD_CONST
opcode verwerk.
In hierdie manier kan ons die OOB-funksie gebruik om 'n "naam" van arbitrêre geheue-offset te kry. Om seker te maak watter naam dit het en wat sy offset is, hou net aan om LOAD_NAME 0
, LOAD_NAME 1
... LOAD_NAME 99
... te probeer. En jy kan iets vind in ongeveer oparg > 700. Jy kan ook probeer om gdb te gebruik om na die geheue-opstelling te kyk, natuurlik, maar ek dink nie dit sal makliker wees nie?
Sodra ons daardie nuttige offsets vir name / consts verkry, hoe kry ons 'n naam / const van daardie offset en gebruik dit? Hier is 'n truuk vir jou:
Kom ons neem aan ons kan 'n __getattribute__
naam van offset 5 (LOAD_NAME 5
) met co_names=()
kry, doen dan net die volgende dinge:
Let op dat dit nie nodig is om dit as
__getattribute__
te noem nie, jy kan dit as iets korter of meer vreemd noem
Jy kan die rede agter dit verstaan deur net na die bytecode te kyk:
Let op dat LOAD_ATTR
ook die naam van co_names
haal. Python laai name vanaf dieselfde offset as die naam dieselfde is, so die tweede __getattribute__
word steeds van offset=5 gelaai. Deur hierdie kenmerk te gebruik, kan ons 'n arbitrêre naam gebruik sodra die naam in die geheue naby is.
Om getalle te genereer, behoort dit triviaal te wees:
0: nie [[]]
1: nie []
2: (nie []) + (nie [])
...
Ek het nie consts gebruik nie weens die lengte beperking.
Eerstens hier is 'n skrip vir ons om daardie offsets van name te vind.
En die volgende is vir die generering van die werklike Python exploit.
Dit doen basies die volgende dinge, vir daardie strings kry ons dit van die __dir__
metode:
Leer & oefen AWS Hacking:HackTricks Opleiding AWS Red Team Expert (ARTE) Leer & oefen GCP Hacking: HackTricks Opleiding GCP Red Team Expert (GRTE)