Checksec 输出内容含义 & 应对方法
1.Relro
Relocation Read Only, 重定位表只读。重定位表即**.got和.plt**两个表。
我的理解: NO RELRO: 可以写.dynamic,现在的软件不常见,如果是这个选项很有可能是一种对考点的暗示。 Partial RELRO: .dynamic只读,比较常见,可以修改got表内容。 Full RELRO:无法利用GOT表进行攻击。
2.Stack
一般由Canary(金丝雀)来保护,金丝雀原来是石油工人用来判断气体是否有毒。而应用于在栈保护上则是在初始化一个栈帧时在栈底(stack overflow 发生的高位区域的尾部)设置一个随机的 canary 值,当函数返回之时检测 canary 的值是否经过了改变,以此来判断 stack/buffer overflow 是否发生,若改变则说明栈溢出发生,程序触发 stack_chk_fail 函数退出程序。 注意:同一个程序的 canary 的值都是一样的,而且子进程也是一样的。 因此我们需要获取 Canary 的值,或者防止触发 stack_chk_fail 函数。 因为 Canary 的值具有不可预测性,所以需要动态的方法进行泄露,一般常用的方法就是通过格式化字符串漏洞来输出 Canary 的值,或者是用**[栈溢出,输出栈内容]的形式来输出 Canary 但是由于Canary的设计者考虑到了Canary被误泄露的可能性,因此强制规定Canary**的最后两位必须是00。所以在输出的时候会被00截断,而我们只需要多覆盖一位,把\x00给覆盖掉,然后读取的时候再替换成\x00即可。
Pwn学习笔记:printf格式化字符串漏洞原理与利用 Canary机制及绕过策略-格式化字符串漏洞泄露Canary
我的理解:通过调试定位到Canary的地址,然后利用**%[OffSet]$x来读取数据。%[OffSet]表示往后移动[OffSet]个参数。 而且字符串漏洞泄露是可以利用%n**来写入数据的, 写入的数据为已经输出的字符串。
所以可以配合printf(“p32(地址)%[OffSet]%n”); **[OffSet]**是指向p32(地址)的位置,来达到写指定的(地址)的目的,这个例子应该写入的是一字节的0x4。 而且当我们需要要对一个地址写入一个很大的数,例如0x12345678时,我们一般不直接写入,而是利用h或hh,分若干次写入。
%d 用于读取10进制数值 %x 用于读取16进制数值 %s 用于读取字符串值 即泄露任意地址信息(传入指针,访问指针位置的内容,到\x0结束) %n 用于把前面已经打印的长度写入某个内存地址(把栈的地址当作指针,向它指向的地址写) %n 写入4个字节,%hn 写入2个字节,%hhn 写入1个字节。
3.NX
Non-Executable Memory,不可执行内存。 了解 Linux 的都知道其文件有三种属性,即 rwx,而 NX 即没有 x 属性。 如果没有 w 属性,我们就不能向内存单元中写入数据,如果没有 x 属性,写入的 shellcode 就无法执行。 所以,我们此时应该使用其他方法来 pwn 掉程序,其中最常见的方法为 ROP (Return-Oriented Programming 返回导向编程),利用栈溢出在栈上布置地址,每个内存地址对应一个 gadget,利用 ret 等指令进行衔接来执行某项功能,最终达到 pwn 掉程序的目的。 我的理解,不能在栈上直接写Shellcode并且执行,但是可以ROP(即通过ret的时候转到的地址来控制程序运行权限)。