WAR GAME/dreamhack

[dreamhack : pwnable] basic_rop_x64 풀이

jir4vvit 2021. 1. 20. 18:49

문제 풀이 환경 : ubuntu 16.04.7

 

64bit에서 ROP 문제이다. 

보호기법
main

main에서 bof가 발생하고 있다. buf 크기는 0x40이지만 read로 0x400을 읽으려고 하고 있다.

페이로드를 총 두 번 짤 것이다.

 

첫 번째 페이로드는 libc_base를 구하기 위함이다. libc_base를 구하기 위해 read함수의 실제 주소를 leak한다. 그리고 RET를 main으로 줘서 main이 한 번 더 돌게 한다.

두 번 째 페이로드에서 RET에 system함수를 넣어 진짜 쉘을 딸 것이다. 

 


첫 번째 payload : read 함수의 실제 주소 leak

read 함수의 실제 주소를 leak하기 위해서는 어떻게 해야 할까? 

출력하는 함수 인자로 read함수 got를 주면 read 함수의 실제 주소가 출력이 될 것이다. 그거를 recv로 받아오면 되겠지?

 

IDA로 함수 목록을 살펴보니까 puts 함수가 있어서 이걸로 read 함수의 got를 출력하기로 했다.

 

 

그러면 이제 가젯을 찾아준다. 64bit 에서 호출규약은 System V AMD64 ABI라고 한다.. 아무튼 결론은 호출할 함수에 전달될 인자 값을 레지스터에 저장한다. 

 

참고로 인자값을 레지스터에 저장하는 순서는 rdi, rsi, rdx, rcx ... 순서이다.

 

ROPgadget 을 이용하여 찾아보자.

jir4vvit@jir4vvit-virtual-machine:~/dreamhack/rop/rop2$ ROPgadget --binary basic_rop_x64 | grep "pop"

 

puts 함수는 인자가 하나니.. pop rdi; ret을 찾으면 된다. 

이것은 다시 말해 호출할 함수의 첫 번째 인자 값을 저장한다는 것을 뜻한다.

 

마침 저기 보인다. 0x400883

 

payload = ''
payload += "A"*72

payload += p64(pop_rdi)
payload += p64(read_got)
payload += p64(puts_plt)
payload += p64(main)

pop_rdi 를 하고 첫번째 인자로 read_got를 준 puts_plt를 호출한다. 

그리고 이거 이후 실행될 함수는 main이다.

 

그러면?!!??!?!

puts의 인자로 read_got를 줬으니, read_got가 출력될 것이다.

이것을 recv로 받아오자.

 

libc_base는 간단하게 아래처럼 구할 수 있다.

libc_base = read_addr - read_offset

 


두 번째 payload : 쉘 따기

첫 번째 페이로드를 실행하고 나면 read 함수 주소를 leak하고 다시 main으로 돌아가 main이 한 번 더 실행된 상태이다.

 

read 함수 주소를 leak하면 libc_base를 구할 수 있고,  libc_base를 구하면 system 함수의 실제 주소와 "/bin/sh" 문자열 실제 주소를 구할 수 있을 것이다.

system_addr = libc_base + system_offset
binsh_addr = libc_base + binsh_offset

 

그럼 이제 끝났다..

 

첫 번째 페이로드를 전송했던 것처럼 pop_rdi 를 하고 첫번째 인자로 binsh 문자열을 주고 system 함수를 호출하면 된다! (system 함수 인자도 하나임)

payload = ''
payload += "A"*72
payload += p64(pop_rdi)
payload += p64(binsh_addr)
payload += p64(system_addr)

 


exploit

exploit 코드는 생략하겠다. (공개글로 올리고 싶어서..)