Как указано BSH, ваш шеллкод не содержит байтов сообщения. Переход к метке MESSAGE
и вызов подпрограммы GOBACK
перед определением байта msg
был хорошим шагом, так как адрес msg находился бы в верхней части стека в качестве адреса возврата, который можно было бы выскочить на ecx
, где хранится адрес msg ,
Но и ваш, и код BSH имеет небольшое ограничение. Он содержит NULL bytes (\x00)
, который будет рассматриваться как конец строки при разыменовании указателем функции.
Существует разумный способ обойти это. Значения, которые вы храните в eax, ebx and edx
, достаточно малы, чтобы их можно было непосредственно записать в нижние полубайты соответствующих регистров за один проход, обратившись к al, bl and dl
соответственно. Верхний полубайт может содержать нежелательное значение, чтобы его можно было хранить.
b8 04 00 00 00 ------ mov $0x4,%eax
становится
b0 04 ------ mov $0x4,%al
31 c0 ------ xor %eax,%eax
В отличие от множества ранее инструкций, новый набор команд не содержит NULL байт.
Таким образом, окончательная программа выглядит следующим образом:
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
Сборка и соединение:
$ nasm -f elf hello.asm -o hello.o
$ ld -s -m elf_i386 hello.o -o hello
$ ./hello
y0u sp34k 1337 ? $
Теперь извлечь шеллкод из приветствия двоичного:
$ for i in `objdump -d hello | tr '\t' ' ' | tr ' ' '\n' | egrep '^[0-9a-f]{2}$' ` ; do echo -n "\\x$i" ; done
выхода:
\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
Теперь мы можем иметь нашу программу драйвера для запуска шеллкода.
#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;
}
Есть определенные функции безопасности в современных компиляторов, как NX protection, который предотвращает выполнение кода в сегменте данных или стека. Поэтому мы должны явно указать компилятор, чтобы отключить их.
$ gcc -g -Wall -fno-stack-protector -z execstack launcher.c -o launcher
Теперь launcher
может быть вызван для запуска шеллкода.
$ ./launcher
y0u sp34k 1337 ? $
Для более сложных шельфовых кодов было бы еще одно препятствие. Современные ядра Linux имеют ASLR или Address Space Layout Randomization
Вам может понадобиться отключить это перед вашим впрыскивать шеллкод, особенно когда речь идет через переполнение буфера.
[email protected]:~# echo 0 > /proc/sys/kernel/randomize_va_space
Не знаете, почему у вас не было никаких переломов, но это был отличный ответ. Спасибо за помощь. –
нулевые байты должны быть удалены, чтобы выполнить шеллкода Тхо – REALFREE
@REALFREE Нулевой байт будет проблемой, если вы работаете с функцией требуется нулем строку, как строковые функции как 'strcpy', он не будет читать всю шеллкода, строку. В противном случае все нормально. – 2013-10-15 13:38:21