Jako wspomniany numer BSH, Twój kod powłoki nie zawiera bajtów wiadomości. Przeskakiwanie do etykiety MESSAGE
i wywoływanie procedury GOBACK
tuż przed zdefiniowaniem bajtu było dobrym posunięciem, ponieważ adres msg byłby na wierzchu stosu jako adres zwrotny, który mógłby zostać wyświetlony na ecx
, gdzie przechowywany jest adres msg .
Ale zarówno twój, jak i kod BSH ma niewielkie ograniczenie. Zawiera NULL bytes (\x00)
, który byłby uważany za koniec ciągu, gdy został odwołany przez wskaźnik funkcji.
Istnieje sprytny sposób obejścia tego. Wartości, które przechowujesz pod eax, ebx and edx
, są na tyle małe, że można je zapisać bezpośrednio w niższych numerach poszczególnych rejestrów za jednym razem, uzyskując dostęp do odpowiednio al, bl and dl
. Górna partia może zawierać wartość śmieciową, dzięki czemu może zostać zmieniona.
b8 04 00 00 00 ------ mov $0x4,%eax
staje
b0 04 ------ mov $0x4,%al
31 c0 ------ xor %eax,%eax
przeciwieństwie do wcześniejszego zestawu instrukcji, nowy zestaw instrukcji nie zawiera żadnych bajt NULL.
więc końcowy program wygląda następująco:
global _start
section .text
_start:
jmp message
proc:
xor eax, eax
mov al, 0x04
xor ebx, ebx
mov bl, 0x01
pop ecx
xor edx, edx
mov dl, 0x16
int 0x80
xor eax, eax
mov al, 0x01
xor ebx, ebx
mov bl, 0x01 ; return 1
int 0x80
message:
call proc
msg db " y0u sp34k 1337 ? "
section .data
Montaż i łączenie:
$ nasm -f elf hello.asm -o hello.o
$ ld -s -m elf_i386 hello.o -o hello
$ ./hello
y0u sp34k 1337 ? $
Teraz wyodrębnić szelkod od binarnego Witaj
$ for i in `objdump -d hello | tr '\t' ' ' | tr ' ' '\n' | egrep '^[0-9a-f]{2}$' ` ; do echo -n "\\x$i" ; done
wyjściowa:
\xeb\x19\x31\xc0\xb0\x04\x31\xdb\xb3\x01\x59\x31\xd2\xb2\x12\xcd\x80\x31\xc0\xb0\x01\x31\xdb\xb3\x01\xcd\x80\xe8\xe2\xff\xff\xff\x20\x79\x30\x75\x20\x73\x70\x33\x34\x6b\x20\x31\x33\x33\x37\x20\x3f\x20
Teraz możemy mieć program do uruchomienia kodu powłoki.
#include <stdio.h>
char shellcode[] = "\xeb\x19\x31\xc0\xb0\x04\x31\xdb"
"\xb3\x01\x59\x31\xd2\xb2\x12\xcd"
"\x80\x31\xc0\xb0\x01\x31\xdb\xb3"
"\x01\xcd\x80\xe8\xe2\xff\xff\xff"
"\x20\x79\x30\x75\x20\x73\x70\x33"
"\x34\x6b\x20\x31\x33\x33\x37\x20"
"\x3f\x20";
int main(int argc, char **argv) {
(*(void(*)())shellcode)();
return 0;
}
Istnieją pewne cechy bezpieczeństwa w nowoczesnych kompilatorów jak NX protection który uniemożliwia wykonanie kodu w segmencie danych lub stosu. Dlatego powinniśmy wyraźnie określić kompilator, aby je wyłączyć.
$ gcc -g -Wall -fno-stack-protector -z execstack launcher.c -o launcher
Teraz launcher
mogą być powoływane w celu uruchomienia szelkod.
$ ./launcher
y0u sp34k 1337 ? $
Dla bardziej złożonych skorup, pojawiłaby się kolejna przeszkoda. Współczesne jądra Linux mają ASLR lub Address Space Layout Randomization
Może być konieczne wyłączenie tego przed wstrzyknięciem kodu powłoki, szczególnie gdy jest to spowodowane przepełnieniem bufora.
[email protected]:~# echo 0 > /proc/sys/kernel/randomize_va_space
Nie jestem pewna, dlaczego nie udało Ci się zdobyć żadnych głosów, ale to była świetna odpowiedź. Dzięki za pomoc. –
bajty null powinny zostać usunięte, aby wykonać kod powłoki tho – REALFREE
@REALFREE Bajt Null byłby problemem, jeśli pracujesz z funkcją, która wymaga zakończonych znakiem NUL ciągów jak funkcje łańcuchowe jako 'strcpy', nie odczyta całego kodu powłoki, łańcucha. W przeciwnym razie jest OK. –