[攻防世界]进阶区hacknote
又一道堆利用的题,虽然是堆利用的题,不过这题比较好利用漏洞,我感觉这题不好写的地方就在于如何利用system拿到shell,这道题没法直接用system(/bin/sh),需要用到linux执行的技巧。
这道题给了libc,所以一会就不用自己泄露libc地址了,可以直接用。
32位、能覆写、有栈保护、有nx,没随机地址。可以覆写,但是由于不能修改堆内容,只有创建堆的时候才可以写入,所以可以在创建时让指针指向任一函数的got表地址,但是没法修改其内容,只好另寻他路。
运行一下,发现是个菜单题,可以执行添加、删除、输出操作。
32位IDA打开看看,main主要就是菜单选择
Add函数:
可以看到最多创建5个堆块,且每次add一个新笔记时,会malloc两次,第一次malloc 0x8的块,姑且叫它note,ptr[i]和p0[0]均指向该块;第二次会malloc size的块,这个块存储输入的数据,就叫它contant,ptr[i]+1和p0[1]指向该块。
contant的内容是由我们输入的,note的内容是程序设定的,第22行的操作就是把函数sub_804862B地址放到ptr[i]指向的位置,由于是32位程序,所以会占用0x4的空间,点进去看看sub_804862B是个干什么的函数:
是要传入一个参数a1,然后puts输出*(a1+4)处的数据,结合该程序输出函数sub_80488A5中的(*(void (__cdecl **)(void *))ptr[v1])(ptr[v1]) ,可以看出,当ptr[v1]指向note时,可以翻译成 puts*(note+4),由此可推断note堆中后0x4位应该是contant的地址,否则就没法输出contant内容了。
画出堆结构:
Del函数:
两次free,先free掉contant,然后才是note结构体,且都没有置NULL,会留下两个野指针仍指着原先的位置,所以存在着uaf漏洞。
思路:
- Add两个新笔记,分别为0号和1号,大小均为0x20 (只要不是0x8就行,0x8的话,free以后会使note和contant进入同一个fastbins,不方便利用)。
- 先Del掉0号笔记,然后Del 1号笔记,让note块进入fastbins,此时0x8的fastbins如下。
0x8 fastbins:→note1→note0
由于fastbins是单链表维护的,所以先进后出,所以下次Add的块符合条件时,会先取用note1,然后才是note0。
3. Add 一个大小0x8的2号笔记,2号笔记的note2就是曾经note1的块,而contant2就是曾经note0的块。
4. 在contant2中写入puts(puts_got),并用指针调用来泄露puts的got地址,并计算libc加载基址。
5. Del 2号笔记,Add 大小0x8的3号笔记,此时note3是曾经的note1,contant3是曾经的note0。
6. 由于Print函数是用指针执行note中的函数,所以在contant3中的写入system地址,用Print 0时,就会利用没有被NULL的ptr[0]指针调用指向的system函数,但程序中note结构中的输出函数实际上输出的是 *(其本身位置+4) 处的内容,但当我们把这个输出函数替换成system时,构成的实际上是system(system地址和后续内容),就会形成乱码,所以需要用到一个linux的使用技巧,就是shell的条件判断 || ,写入p32(system_addr)+’||sh’,此时用Print 0调用时,就会形成system(system_addr||sh),由于system(system_addr)不可执行,所以就会执行system(sh),前0x4已经写入了system的地址,所以还有0x4的空间刚好写入’||sh’。
EXP:
1 | from pwn import * |
关于linux的shell命令条件判断:可以看篇文章