调试之后的小心得:
- 当你申请小chunk的时候,堆管理器分配chunk的大小是按照0x10的单位来配的,当你所申请的大小a超过的能满足a的 (最小容量-0x10) +0x8时,才会分配最小容量,否则是分配最小容量-0x10,因为分配给你的chunk的后一个chunk的prev_size(0x8)可以作为本chunk数据部分使用。
- 当在题目中发现有打印的机制是跳转在跳转(解引用)时,考虑在第一个跳转的地方写进函数的got表项
- 从目前的调试情况来看,申请堆空间时寻找合适的fastbin是从附近的低地址开始寻找,首先找的是大小合适的chunk,大小合适的判定见1
- 建议:在off by one的利用中,常常需要
申请两个大小类似的–》offbyone写到第二个堆的size域–》free第二个堆–》malloc第二个堆,大小为修改的值
此时一般可以向后拓展,如拓展和利用看具体的题目数据结构,比如有双跳转的打印可以考虑打印got
size_t在32位架构上是4字节,在64位架构上是8字节
关于.fini的说法:
显然,一次利用并不能达到我们getshell的目的,这里用到这么一个知识点 :
程序退出后会执行
.fini_array
地址处的函数,不过只能利用一次。
所以我们可以利用第一次格式化字符串将.fini_array地址处的函数修改成main函数的地址,使程序重新回到main函数。当然,我们还需要泄漏libc地址。
输入点在格式化偏移为12处,我们第一轮利用需要修改的是.fini_array处的内容,所以我们在栈中可以这么构造:
payload2 = ‘5’+p8(0x0)*7 + p64(fini_array) <-- 5为选用submit功能
使程序再次运行的方法:改写fini_arry0的内容(一般在.fini_arry段中,在ida中ctrl+s寻找位置)为main_addr,可以再次运行,但只能用一次。
相信大家都能注意到,就是程序运行了一次就结束了,而我们至少需要两次运行,一次leak,一次change,所以这里需要利用第一次的机会来将fini_arry0改为main_addr,并且泄露libc地址(main函数返回到__libc_start_main中,可以在格式化字符串前来下断点,通过查看栈的数据来查看偏移,进而获得libc地址。),现在还有一个问题是fini_arry0怎么输入进栈并且确定偏移???这里需要打破常规思维,需要改的数据可以不在格式化字符串里,只要偏移可以确定就行!,这时候就想到了之前的那个s给了0x80的空间,我们可以将fini_arry0输入到s里然后通过调试确定偏移。
需要注意的是由于一旦 submit 之后,程序就会直接直接退出,所以我们比较好的思路就是修改 fini_array 中的变量,以便于达到程序执行完毕后,重新返回我们期待的位置。这里我们会使用一个 trick,程序每次读取选择的时候会读取 128 大小,在栈上。而程序最后在输出 dest 的时候,之前所读取的那部分选择必然是在栈上的,所以我们如果我们在栈上预先布置好一些控制流指针,那就可以来控制程序的执行流程。
Fini_array0 : 5+8=13
关于books:一直在肛fini_array在栈上的位置现在也没肛出来,决定先转移战线,先将主流的经典的题目做了,再来看这些骚操作。所以这题可能要跳过了
明天
学习堆的主流利用方法,吃理论和经典题,先把思路吃透