Перезапись возвращаемого значения стека EBP

Привет, я пытаюсь написать эксплойт переполнения для простой программы, которую я создал. Bellow — это программа на C, которую я написал.

#include <unistd.h>
#include <string.h>
#include <stdio.h>

char *string_in = "Did not work";

int test(char *this){
char sum_buf[6];
strncpy(sum_buf,this,24);
return 0;
}

void hello(){
printf("hello man");
string_in = "If this triggered, it means our shell code is working\n";
return;
}

int main(int argc, void **argv){

test("01234567890123456789\x00\x40\x06\x02");
printf("My string is %s",string_in);
return 0;

}

В основном происходит то, что строка должна быть прочитана в EBP с перезаписью со значением 0x00400602, которое является адресом возврата моей функции hello(). Я знаю, что это значение адреса для моей функции hello, так как objdump -d test_stack.o. Из дампа объекта я могу сказать, что rsp был расширен на 20 байт, как показано ниже.

00000000004005b4 <test>:
  4005b4:   55                      push   %rbp
  4005b5:   48 89 e5                mov    %rsp,%rbp
  4005b8:   48 83 ec 20             sub    $0x20,%rsp
  4005bc:   48 89 7d e8             mov    %rdi,-0x18(%rbp)
  4005c0:   64 48 8b 04 25 28 00    mov    %fs:0x28,%rax
  4005c7:   00 00 
  4005c9:   48 89 45 f8             mov    %rax,-0x8(%rbp)
  4005cd:   31 c0                   xor    %eax,%eax
  4005cf:   48 8b 4d e8             mov    -0x18(%rbp),%rcx
  4005d3:   48 8d 45 f0             lea    -0x10(%rbp),%rax
  4005d7:   ba 18 00 00 00          mov    $0x18,%edx
  4005dc:   48 89 ce                mov    %rcx,%rsi
  4005df:   48 89 c7                mov    %rax,%rdi
  4005e2:   e8 a9 fe ff ff          callq  400490 <strncpy@plt>
  4005e7:   b8 00 00 00 00          mov    $0x0,%eax
  4005ec:   48 8b 55 f8             mov    -0x8(%rbp),%rdx
  4005f0:   64 48 33 14 25 28 00    xor    %fs:0x28,%rdx
  4005f7:   00 00 
  4005f9:   74 05                   je     400600 <test+0x4c>
  4005fb:   e8 a0 fe ff ff          callq  4004a0 <__stack_chk_fail@plt>
  400600:   c9                      leaveq 
  400601:   c3                      retq   

0000000000400602 <hello>:
  400602:   55                      push   %rbp
  400603:   48 89 e5                mov    %rsp,%rbp
  400606:   b8 6d 07 40 00          mov    $0x40076d,%eax
  40060b:   48 89 c7                mov    %rax,%rdi
  40060e:   b8 00 00 00 00          mov    $0x0,%eax
  400613:   e8 98 fe ff ff          callq  4004b0 <printf@plt>
  400618:   48 c7 05 0d 0a 20 00    movq   $0x400778,0x200a0d(%rip)        #

Начиная с суммы менее $20,%rsp, я знаю, что мне нужно написать не менее 20 байтов... но я не уверен, сколько еще мне нужно написать, чтобы добраться до моего rbp. Возможно, что из моих вычислений мне нужно записать 8 или мои байты, так как есть 2 вызова x. Хотя я действительно не уверен, сколько мне нужно написать.

Я компилирую свою программу так...

gcc -g stack.c -o test_stack.o
execstack -s test_stack.o

Поскольку я использую Ubuntu 11, моя версия ядра похожа на 3.0.17, поэтому я знаю, что мой aslr включен по умолчанию. Возможно, мне нужно отключить это, но я не знаю, как это сделать. Также я запускаю i386:x86_64. Могу ли я сказать, как на самом деле выглядит мой стек во время прогона? Как я могу заставить это работать и как узнать, сколько мне нужно написать?

Спасибо за помощь


person Dr.Knowitall    schedule 19.04.2012    source источник
comment
Одна проблема, которую я вижу, заключается в том, что вы не используете достаточно байтов для адреса функции. Вам нужно 32 бита: \x00\x40\x06\x01. Кроме того, я думаю, вам может понадобиться изменить порядок этих байтов, потому что x86 хранит 0x00400601 в памяти как 0x01, 0x06, 0x40, 0x00. Наконец, я не знаю, помогут ли мои предложения. Это зависит от того, как gcc создает фрейм стека. Лучше всего выполнить пошаговое выполнение в отладчике, чтобы вы могли видеть, что происходит.   -  person Jim Mischel    schedule 20.04.2012
comment
Вы правы, я забыл ввести последний байт. Спасибо, я посмотрю, работает ли это.   -  person Dr.Knowitall    schedule 20.04.2012
comment
Лол, теперь я не получаю ошибку stackoverflow. Это потрясающе! Но по какой-то причине это не printf().   -  person Dr.Knowitall    schedule 20.04.2012
comment
sub $0x20,%rsp выделяет 32 байта для кадра стека, а не 20 (шестнадцатеричная запись).   -  person Michael Foukarakis    schedule 20.04.2012
comment
Я давно не занимался сборкой, поэтому пропустил 0x как шестнадцатеричный.   -  person Dr.Knowitall    schedule 20.04.2012


Ответы (1)


Ну, первая проблема заключалась в том, что мне пришлось отключить защиту стека с включенным флагом -fno-stack-protector. Как только я это сделал, перезаписать мой буфер стало намного проще. Вторая проблема заключалась в том, что даже если строка была прочитана и сохранена с обратным порядком байтов, код операции и операнд интерпретировались с обратным порядком байтов. Я не понимаю, почему это так. Наконец, меня интересовала перезапись не кадра стека EBP... а адреса возврата моей функции. Это означало, что вместо записи 24 байтов мне нужно было эффективно перезаписать колоссальные 32 байта. Наконец-то программа заработала!

person Dr.Knowitall    schedule 20.04.2012