Dlaczego lokalizacja zmiennych środowiskowych różni się tak bardzo?

9

Czytając książkę Hacking: The Art of Exploitation autorstwa Jona Ericksona, staram się przybliżyć adres zmiennej środowiskowej, SHELLCODEaby wykorzystać program.

Za każdym razem, gdy biegnę, getenv("SHELLCODE");aby uzyskać lokalizację, rezultat jest zupełnie inny.

Wyciąg z mojej skorupy:

> for i in $(seq 10); do ./a.out SHELLCODE; done
SHELLCODE is at 0xff9ab3a3
SHELLCODE is at 0xffcdb3a3
SHELLCODE is at 0xffb9a3a3
SHELLCODE is at 0xffa743a3
SHELLCODE is at 0xffdb43a3
SHELLCODE is at 0xfff683a3
SHELLCODE is at 0xffef03a3
SHELLCODE is at 0xffc1c3a3
SHELLCODE is at 0xff85a3a3
SHELLCODE is at 0xff8e03a3

Rozumiem, że jeśli nazwa programu zostanie zmodyfikowana lub dodane zostaną nowe zmienne środowiskowe, pozycja będzie nieco inna, ale dlaczego lokalizacja tak się różni?

Janman
źródło
getenvInstrukcja mówi, że zwraca wskaźnik do łańcucha znaków zawierającego wartość zmiennej. Cała reszta jest nieokreślona, ​​więc twoje jądro i / lub kompilator mogą trzymać wartość tam, gdzie chcą, pod warunkiem, że obietnica wskaźnika pozostanie prawdziwa. Zgaduję, że dokładna odpowiedź na to może być ciężka magia i zależy od różnych szczegółów implementacji mapowania pamięci i fazy księżyca. (Nie jestem wystarczającym czarodziejem, aby dać ci dokładną odpowiedź.)
Anko,
„Rozumiem, że jeśli nazwa programu zostanie zmodyfikowana lub zostaną dodane nowe zmienne środowiskowe, pozycja będzie nieco inna, ale dlaczego lokalizacja tak się różni?” To prawda w najprostszym ze wszystkich możliwych wdrożeń, ale z pewnością nie jest wymagana.
dmckee --- były moderator kociak

Odpowiedzi:

13

To, co opisujesz, to funkcja anty-exploitacyjna o nazwie Randomization Layout Space Address (ASLR). Zasadniczo jądro umieszcza najwyższy adres stosu wywołań funkcji programu pod nieco innym („losowym”) adresem za każdym razem, gdy jądro ładuje plik ELF programu z dysku. Adresy argvi zmienne środowiskowe, z których jeden jest kodem powłoki, kończą się pod różnym adresem przy każdym wywołaniu programu.

ASLR ma utrudniać wykorzystanie przepełnienia bufora i innych luk związanych ze stosem. Eksplorator musi napisać kod lub zrobić coś, aby uwzględnić różne adresy zmiennych i wartości na stosie wywołań funkcji.

Wygląda na to, że możesz wyłączyć ASLR, wykonując coś takiego:

echo 0 > /proc/sys/kernel/randomize_va_space

jako użytkownik root. Ponieważ wyraźnie powołujesz się na Ubuntu, powyższe polecenie jest inne:

echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
Bruce Ediger
źródło
Tak, to załatwiło sprawę. Zauważyłem, że autor książki używa Ubuntu 10.04, który nie ma jeszcze ASLR.
Janman