Jól láthatóan löketesen vagyok terhelt: az utóbbi pár nap híreiről lemaradtam, most meg hirtelen annyi szabadidőm keletkezett, hogy elolvastam xorl elég terjengősre sikerült leírását az először felfedezett, távolról kihasználható OpenBSD biztonsági hibáról, amely az FTP szolgáltatást érintette. Bár a poszt még az utolsó nyamvadék wrapper rutin működésére is kitér, egy lényeges dolgot azért hiányolok:
A probléma oka az volt, hogy egy cikluson belül inkrementált változót használtak fel egy string záró \0-jának beillesztéséhez, ez pedig az allokált puffer 1 (NULL-)byteos túlcsordulásához vezethetett, ami felülírhatta az EBP regiszter (aka. Frame/Base Pointer) értékét. A hibás függvény visszatéréskor így rossz értékre állította vissza az ESP (Stack Pointer) értékét és ezáltal rossz helyről olvasta vissza az EIP regiszter (aka. Instruction Pointer) által mutatott címet is, a programfutás tehát nem a várt helyen folytatódott.
A kérdés az, hogy (a fenti folyamatot feltételezve) milyen peremfeltétel(ek)nek kell teljesülni ahhoz, hogy az EIP regisztert a támadó állíthassa be végül?
Jó matekolást ;)
sghctoma · http://sghctoma.extra.hu 2010.01.13. 17:23:25
mivel az 1024 byte meretu bufferbe irt 1025 byte pont 1 byte-tal irja felul a stack-on tarolt EBP erteket, kozvetlenul az alatt kell lennie, tehat igy nez ki a replydirname stack frame-je (remelem szetcseszi a blogmotor :) ):
. .
| stack |
| frame |
| of |
| pwd |
+-------- ---+
| stored ret |
+------------+
| stored ebp |
+------------+ *
| AAA" |
+------------+
| |
. ret x 63 .
. .
| |
+------------+
| shellcode |
. + .
. A padding .
| |
+------------+
| 255 x A |
+------------+
| write_dir |
. + .
. A padding .
| |
+------------+
*-gal jelolt reszen irunk felul 1 byte-ot 0x00-val, igy csokkentve a tarolt EBP erteket annyival, amennyi a tarolt EBP legkisebb helyierteku byte-ja volt.. a replydirname epilogusaban az EBP regiszter erteke termeszetesen erre a rossz ertekre allitodik, amit aztan a pwd epilogusaban az ESP regiszter is megkap..
tehat ami tortenik: amikor a pwd visszater, az ESP valamennyivel kisebb erteku, mint normalis esetben, igy egy alacsonyabb cimrol jon a visszateresi ertek.. ennek a 'valamennyi'-nek kell megfelelonek lenni ahhoz, hogy menjen a moka.. konkretan tul kell vele loni a pwd stack frame-jet, a reply_dirname stack frame-jeben a RET-et es a tarolt EBP-t, plusz az AAA" stringet..
remelem nem voltam tul zagyva :)
buherator · http://buhera.blog.hu 2010.01.13. 17:46:04
Ez igaz, de a kérdés arra irányult volna, hogy mitől lesz az a valamennyi megfelelő ahhoz, hogy menjen a móka? Ugye ha az EBP felülírt byte-ja éppen 0-volt, akkor minden marad a régiben, ha 1, akkor csak egyet lépünk vissza + az sem mindegy, hogy hol van attacker által vezérelt adat a stacken.
Megmondom őszintén, nem sakkoztam végig a dolgot, de érzésem szerint lehetne általános feltételrendszert adni ilyen esetekre (akár a +1 byte értékének függvényében).
Bónusz kérdés: el lehet-e jutni más úton az EIP-ig az EBP LSB-jének módosításával?
sghctoma · http://sghctoma.extra.hu 2010.01.13. 18:03:16
buherator · http://buhera.blog.hu 2010.01.13. 18:51:14
Szóval engem az érdekelne, hogy mekkora konkrétan ez a "mázli faktor" egy off-by-one bug esetén. Ha csak az zavarhat be, hogy LSB(EBP)==[off-by-one byte], akkor az 255/256 eséllyel siker, adott [off-by-one byte]-ra.
Szóljatok ha hülyeségeket beszélek plz!
buherator · http://buhera.blog.hu 2010.01.13. 18:51:50
synapse · http://www.synsecblog.com 2010.01.13. 19:50:43
synapse
Hunger 2010.01.14. 14:14:07
buherator · http://buhera.blog.hu 2010.01.14. 14:39:55
Van nekem x86-on (és mondjuk ezen a régi OpenBSD-n, nincs ASLR, DEP vagy más plusz védelem) futó, tetszőleges szoftverem, amiről tudom, hogy hibás, és a futás adott pillanatában felül bírom írni rajta keresztül az EBP utolsó byte-ját. Ki akarom használni a hibát úgy, hogy a módosított EBP értéket felhasználva egy általam teljesen vezérelt EIP töltődjön be a hibás function lefutása után. Csak ezt az egy hibát ismerem, és többet nem is keresek. Mik kihasználhatóság kritériumai a stack felépítésére (melyik részeit kell tudnom közvetlenül vezérelni), ill az aktuális, eredeti EBP értékére nézve?
sghctoma · http://sghctoma.extra.hu 2010.01.14. 16:04:28
@Hunger: azert a manapsag hasznalt mindenfele vedelmek mellett kell nemi szerencse, hogy egy bug tenylegesen kihasznalhato legyen..
Hunger 2010.01.14. 17:24:33
sghctoma · http://sghctoma.extra.hu 2010.01.14. 17:33:54
@Hunger: szimplan arra akartam utalni a szerencsevel, hogy nem minden bug-bol tudsz mukodo exploit-ot gyartani.. tehat nem arrol beszelek, hogy irsz egy megbizhatatlan exploit-ot, ami neha mukodik, neha nem, hanem, hogy egyaltalan lehetseges-e exploitalni a hibat..
Hunger 2010.01.14. 17:38:35
synapse · http://www.synsecblog.com 2010.01.15. 10:57:59
Persze, en ezt ertem. Az ASLR-t, meg a DEP-et se azert hasznaljak, mert _megoldja_ a problemat hanem mert jelentosen csokkenti a kihasznalhatosag eselyeit. Annak az eselye pedig, hogy van egy kihasznalhato codexec es egy jo infoleak eleg kicsi (vagy druvan gany a kod) -> szerencse kell hozza. Es itt a szerencset csak es kizarolag arra ertem, hogy a program tartalmazza-e a hibat, nem pedig arra, hogy megtalalod-e.
BTW kezdo haxorhoz hogy szivargott el a zeroday? Ha megtalalta, de favago modon allt neki akkor kezdo, vagy lusta?
buhera:
"Mik kihasználhatóság kritériumai a stack felépítésére (melyik részeit kell tudnom közvetlenül vezérelni), ill az aktuális, eredeti EBP értékére nézve?"
synapse
synapse · http://www.synsecblog.com 2010.01.15. 12:13:25
Igy nez ki egy function epilogue elmeletben:
mov %ebp, %esp
pop %ebp
ret
Hasznalok nehany "konstanst":
- joebp: az eredeti stacken tarolt ebp erteke
- lsbbyte: joebp utolso byte-janak az eredeti erteke
- hackedeip: altalunk megadott hamis eip ertek
Az exploitalasnal nagyjabol ez fog vegbemenni:
- felulirjuk a joebp lsb-jat 0-al (igy lsbbyte-al csokken
az erteke)
- function epilogue soran:
- stack teteje az ebp regiszter erteke lesz (esp = ebp)
- stack alja a tarolt ebp lesz (altalunk korruptalt ebp)
- popoljuk ebp + 4-et (tarolt eip) es raugrunk
Emiatt az kell csak, hogy lsbbyte erteke eleg magas legyen
ahhoz, hogy elerje a hackelt eip utani negy byteot. ->
lsbbyte == joebp - &hackedeip + 4, vagy ha tobb hackelt
eip-et is el tudunk helyezni, akkor legyen ->
(joebp - &lasthackedeip + 4 >= lsbbyte) &&
lsbbyte >= (joebp - &firsthackedeip + 4) ->
Mivel stack alignment miatt joebp % 4 mindig 0, igy
kihasznalhato.
Pelda:
Ha lsbbyte mondjuk 40 es 32 bytenyi adat van joebp-tol az elso
&hck-ig, akkor a tarolt ebp-bol betoltve az ebp regiszter 40
byte-al alacsonyabb ertekre mutat 0x1052 helyett 0x1012-re,
igy amikor ebp+4-rol felolvassuk az eip-t, pont hck-t
fogja kiolvasni 0x1016-rol:
...
0x1052-0x1049 |GUT| <- joebp, itt lenne a stack alja
0x1048-0x1045 |grb| <- szemet*
0x1044-0x1041 |grb| <- szemet*
0x1040-0x1037 |EBP| <- innen olvassuk fel a korruptalt joebpt
0x1036-0x1033 |grb| <- szemet*
0x1032-0x1029 |grb| <- szemet*
0x1028-0x1025 |grb| <- szemet*
0x1024-0x1021 |grb| <- szemet*
0x1020-0x1017 |grb| <- szemet*
0x1016-0x1013 |hck| <- elso helyi valtozonk ami a hackelt eip-t tartalmazza
0x1012-0x1009 |hck|
0x1008-0x1005 |hck|
0x1004-0x1000 |hck| <- utolso helyi valtozonk ami a hackelt eip-t tartalmazza
...
*: Itt igazabol mindegy mi van, de lehet:
fgv param, mentett reg. vagy hck-nak hasznalhatatlan lokal valtozok
"Mik kihasználhatóság kritériumai a stack felépítésére (melyik
részeit kell tudnom közvetlenül vezérelni), ill az aktuális,
eredeti EBP értékére nézve?"
- azt a reszet, ahova ebp mutatni fog
- ebp utolso byteja (lsbbyte) erteke feleljen meg ennek:
joebp - &hackedeip + 4 == lsbbyte
De lehet, hogy elb*sztam :)
synapse
synapse · http://www.synsecblog.com 2010.01.15. 12:22:46
"tehat ami tortenik: amikor a pwd visszater, az ESP valamennyivel kisebb erteku, mint normalis esetben"
Itt nem esp, hanem ebp mert esp az ebp regiszterbol lesz allitva. Amiright?
synapse
conscience 2010.01.15. 12:56:34
Ha azonban mégiscsak jól álmodtam meg a dolgot, akkor ESP kiindulási értékének ismeretében kalkulálható a hiba kihasználása.
Najó, megyek, iszom egy KVt...
buherator · http://buhera.blog.hu 2010.01.15. 13:38:01
synapse · http://www.synsecblog.com 2010.01.15. 13:41:29
"EIP értéke EBP+strlen+6 címen foglal helyet eredetileg (+1 a záró null, +2 a 4bájtos, tárolt EBP címe) ha nincs egyéb sallang"
??? strlen? Az eip az ebp elott kerul mentesre, igy &eip = &ebp + 4
"Eszerint az új EBP alapján EIP-t valahonnan a sztringünkből szeretné majd visszakapni a progi "
Igen, ha ebp utolso byteja annyi, mint a kulonbseg a jo ebp es a mi eipnk cime kozti kulonbseg + 4.
(lastbyte == joebp - &mieipnk + 4)
"Ha azonban mégiscsak jól álmodtam meg a dolgot, akkor ESP kiindulási értékének ismeretében kalkulálható a hiba kihasználása."
Reszben, ha ESP-n itt azt az erteket erted amit kiolvasott(volna) a stackrol (de amit mi korruptalunk) [En ezt elnevezem most X-nek]. Azonban ez nem eleg, a mi tarolt eipnk cimet is tudni kell (vagy a ketto kozti sallag meretet). Ha ez is megvan, akkor ebbol kovetkezik, hogyha X[lsb] == X - &mieipnk + 4 akkor a hiba kihasznalhato, ugyanis:
X erteke lecsokken az utolso byte ertekevel
(X = X-X[lsb])
Ezaltal ebp a stacken feljebb (alacsonyabb cimre) for mutatni.
ebp = X - X[lsb]
Mivel X[lsb] -t ismerjuk:
ebp = X - (X - &mieipnk + 4)
ebp = X - X + &mieipnk - 4)
ebp = &mieipnk - 4
Itt ebp a &mieip ala mutat 4 bytetal, igy a ret utasitas ezt hasznalja fel eipnek eip = ebp + 4 miatt.
Remelem nem magyaraztam tul :)
synapse
conscience 2010.01.15. 13:50:31
axt · http://axtaxt.wordpress.com/ 2010.01.15. 14:02:03
ezért egy ilyen jellegű exploit vagy működik vagy nem! Az eredeti kérdés ha jól értem az volt, hogy ennek mi a valószínűsége? Nem számoltam ki, de érzésre ennek kell teljesülnie
ahhoz hogy működjön:
lsb(EBP) > stacklen(pwd) +4
(Ahol a stacklen(pwd) a pwd függvényhez tartozó stack frame mérete.)
Csak műkedvelő vagyok, nem műértő, szóval ha hülyeséget írtam javítsatok ki! :-D
sghctoma · http://sghctoma.extra.hu 2010.01.15. 14:33:16
a pwd-ben mar az esp is.. a reply_dirname epilogusaban lesz visszaallitva az EBP az altalunk csokkentett ertekre, es utana visszaterunk a pwd fuggvenybe..ennek a fuggvenynek az epilogusaban lesz beallitva az ESP a csokkentett ertekre, es innen megyunk a shellcode-unkba..
"- function epilogue soran:
- stack teteje az ebp regiszter erteke lesz (esp = ebp)
- stack alja a tarolt ebp lesz (altalunk korruptalt ebp)
- popoljuk ebp + 4-et (tarolt eip) es raugrunk"
de itt meg jo helyre ugrunk, hiszen az ESP nem lett modositva, csak az EBP.. a ret meg a stack-rol emeli le a cimet, ahova megy.. igy nez ki a dolog:
reply_dirname epilogusa:
mov esp, ebp ; visszaallitjuk az ESP-t
pop ebp ; berakjuk ESP-be a felulirt erteket
ret ; visszaterunk a pwd-be
pwd epilogusa:
mov esp, ebp ; beallijuk a stack pointert a csokkentett ertekre
pop ebp ; visszaallitjuk az ebp-t
ret ; leszedjuk a stack-rol (stack a bufferunkbe mutat) a ret erteket, es ugrunk
@(-1): igen, csak a +4 az +12 (ret,ebp,AAA"), vagy tobb, pl. ha tobb !scratch regisztert hasznaltunk..
synapse · http://www.synsecblog.com 2010.01.15. 14:34:09
ezért egy ilyen jellegű exploit vagy működik vagy nem!"
A lokalis valtozoknak allokalt hely merete valtozhat ket hivas kozott (parameter atadas miatt). Kerdes, hogy ebben az esetben fog-e es hogy lehet-e ellensulyozni altalunk megadott parameterekkel...
"Az eredeti kérdés ha jól értem az volt, hogy ennek mi a valószínűsége?"
Nem, az volt hogy milyen felteteleknek kell teljesulnie.
"lsb(EBP) > stacklen(pwd) +4"
pwd stack framejenek a merete nem eleg, mert az aktualis stack framejetol (replydirname()) is fugg, hogy tudunk-e a megfelelo helyre kodot rakni. Viszont "lsb(EBP) >= stacklen(pwd) + stackjunklen(replydirname) + 4", ahol stackjunklen() a stack azon reszenek meretet adja vissza, ahova nem tudunk eip-t rakni (param, reg, etc...)
syn
synapse · http://www.synsecblog.com 2010.01.15. 15:33:14
Vegulis ennyi hely kell:
lsbbyte == &pwd_caller_ebp - &hacked_eip + 4
Kosz a korrekciot Toma :)
Ez mutatja a regisztermanipulaciokat, prologue utan, epilogue elott (eip push/popot beleszamolva).
Toma mester, ez igy korrekt?
======|pwd-> repl-> pwd-> call|
[EIP] | | | | |
|EBP| |<-ebp| | | |
|grb| | | | | |
|grb| | | | | |
|grb| | | | | |
|grb| | | | | |
|grb| |<-esp| |<-esp| |
|EIP| | | | | |
|EBP| | |<-ebp| | |
|grb| | | | | |
|grb| | | | | |
|grb| | | | | |
|grb| | | | |<-esp|
|hck| | | | | |
|grb| | | |<-ebp| |
|grb| | | | | |
|end| | |<-esp| | |
Tehat ebp = grb, eip = hck,
esp = &hck - 4
synapse
synapse · http://www.synsecblog.com 2010.01.15. 15:34:56
======|pwd-> repl-> pwd-> call|
[EIP] |=====|=====|=====|=====|
|EBP| |<-ebp|=====|=====|=====|
|grb| |=====|=====|=====|=====|
|grb| |=====|=====|=====|=====|
|grb| |=====|=====|=====|=====|
|grb| |=====|=====|=====|=====|
|grb| |<-esp|=====|<-esp|=====|
|EIP| |=====|=====|=====|=====|
|EBP| |=====|<-ebp|=====|=====|
|grb| |=====|=====|=====|=====|
|grb| |=====|=====|=====|=====|
|grb| |=====|=====|=====|=====|
|grb| |=====|=====|=====|<-esp|
|hck| |=====|=====|=====|=====|
|grb| |=====|=====|<-ebp|=====|
|grb| |=====|=====|=====|=====|
|end| |=====|<-esp|=====|=====|
axt · http://axtaxt.wordpress.com/ 2010.01.15. 15:44:05
- regs: a nem scratch regiszterek nem a lokális változóknak való helyfoglalás után kezdenek pusholódni a verembe?
- az AAA" -mondjuk nem számít, mert az a lokális buffer vége
@synapse: a param az még nem az előző stackframe-be számít? ha nem akkor viszont lehet vonni a pwd stackjunkjának egy részét (kivéve a regs-ek által használtat)
synapse · http://www.synsecblog.com 2010.01.15. 15:58:09
A caller parameterezi fel a callee-t es utana hivja meg. stdcall eseten a callee takarit, cdecl eseten a caller. Az en logikam szerint aki takarit, annak a stack frameje (masikeban ne turkaljon), hiaba nem ott kezdodik a frame ebp szerint. Bar ez csak az en velemenyem :)
synapse
axt · http://axtaxt.wordpress.com/ 2010.01.15. 16:40:03
axt · http://axtaxt.wordpress.com/ 2010.01.15. 16:46:43
lsbbyte >= &pwd_caller_ebp - &hacked_eip + 4
Hunger 2010.01.16. 01:20:17
"Annak az eselye pedig, hogy van egy kihasznalhato codexec es egy jo infoleak eleg kicsi (vagy druvan gany a kod) -> szerencse kell hozza."
Ez gyakori tévhit... Infoleak bugokból általában jóval több van, mert kevésbé figyelnek oda rá, mint a bof problémákra.
Saját tapasztalat, hogy a puffer túlcsordulásról már hallottak az átlag koderek, de amikor infoleak problémákat hozom szóba, akkor összekeverik a memleak-kel...
synapse · http://www.synsecblog.com 2010.01.16. 15:00:16
Ez evidens, en azt mondtam hogy az extra komponens bevezetese miatt csokken a valoszinusege annak, hogy kihasznalhato az eredeti hiba.
syn
sghctoma · http://sghctoma.extra.hu 2010.01.17. 22:31:46
"- regs: a nem scratch regiszterek nem a lokális változóknak való helyfoglalás után kezdenek pusholódni a verembe?"
ezt igy szabalykent nem lehet kijelenteni, de siman elofordulhat, hogy ez a gyakoribb..
@synapse:
jepp, korrektnek tunik..