Canary保护机制与绕过策略
简介
一种防止栈溢出的保护机制;栈溢出的主要利用过程就是通过填充数据覆盖存在于栈上的局部变量,井溢出至ebp和eip等,从而劫持程序控制流;在未开启栈溢出保护的时候,可以通过覆盖返回地址来达到执行shellcode 的目的;如果开启栈保护,在函数调用的时候(执行时),会往栈中插入类似于cookie的信息,当函数返回的时候会验证cookie信息是否合法,即在栈销毁之前测试该值是否发生改变;如果不合法,表示栈溢出发生,会立即停止程序的执行。攻击者在利用栈溢出的时候会将该cookie信息覆盖掉,但程序在返回检查该值的时候能够发现发生栈溢出,故导致攻击者利用失败。
原理
在一个函数的入口处,从fs/gs寄存器中取出一个4字节(eax)或者8字节(rax)的值存到栈上,当函数结束时会检查这个栈上的值是否和存进去的一致。
当canary被篡改时,触发_stack_chk_fail
绕过方法
1.格式化字符串绕过canary
通过格式化字符串读取canary的值,在覆盖canary的时候将canary原有的值写入payload中。
%s 从内存中读取字符串
2.Canary爆破(针对有fork函数的程序)
fork作用相当于自我复制,每一次复制出来的程序,内存布局都是一样的,当然canary值也一样。那我们就可以逐位爆破。如果程序崩溃了就说明这一位不对,如果程序正常就可以接着跑下一位,直到跑出正确的canary。
3.Stack smashing(故意触发canary.ssp leak)
4.劫持_stack chk fail
修改got表中_stack_chk_fail函数的地址,在栈溢出后执行该函数,但由于该函数的地址被修改,所以程序会跳转到我们想要执行的地址。
PIE机制介绍
PIE PIE技术是一个针对代码段(.text)、数据段 (.data)、未初始化全局变量段(.bss)等固定地址的一个防护技术,如果程序开启了PIE保护的话,在每次加载程序时都变换加载地址,从而不能通过ROPgadget等一些工具来帮助解题。
绕过方法
刚刚在程序中看到的开了PIE保护的程序,所有代码段的地址都只有最后三个数是已知的,这里有一点要知道的是,程序的加载地址一般都是以内存页为单位的,所以程序的基地址最后三个数字一定是0,这也就是说那些地址已知的最后三个数就是实际地址的最后三个数。知道这一点之后我们就有了绕过PIE的思路,虽然我并不知完整的地址,但我知道最后三个数,那么我们就可以利用栈上已有的地址,只修改他们最后两个字节(最后四个数)即可。所以对于绕过PIE保护的核心思想就是partial writing (部分写地址)