堆溢出 | unlink
unlink的基础知识
-
操作对象的结构体 :(图片中的括号包裹部分是 payload的组成部分 )
image.png
-
unlink 的 操作流程 和 检查:(# 后的是例题的unlink 操作过程)
image.png
-
free 过程中找到前一个chunk 的方法
image.png
unlink 利用变化
unlink的利用随着保护的改变有所变化。
-
古老的unlink: 因为没有对 unlink 操作对象 的 fd 和 bk 进行检查 , 所以可以通过对unlink的 fd 和 bk 的 值伪造,实现任意地址写的操作.操作流程 :
- FD = p->fd ; ( p->fd = target_addres->fd (target_addres -0xc ))
-
BK = p->bk; ( p->bk = except_value)
-
FD->bk = BK;
-*( target_addres->fd->bk = target_addres - 0xc + 0xc )= BK( except_value )
-
BK->fd = FD;
- *(except_value + 0x8) = target_addres - 0xc (这个利用会破坏 except_value + 0x8 的值 ,所以这个利用需要绕过 except + 0x8)
-
现在的 unlink:加入对 p->fd 和 p->bk 以及 size的检查。
-
加入的检查直接导致了不能直接进行任意地址写,但是伪造chunk的 符合条件的 fd 和 bk 可以 fake_chunk = &fake_chunk - 0xc ;
-
fake_chunk_conetnt = p(0) + p(size) + p(&fake - 0xc ) + p(&fake - 0x8)
fake_chunk_content = fake_chunk_content.ljust(size , "a")
fake_chunk_content += p32(size) + p32(next_chun_size - 1)
(此处 减一 是为了去除最后一位的1 , p位置0)
-
例题 heap :
分析:
-
alt
menu 中 提示有 四个功能 , add , set , del , print
-
检查四个函数.
add 中只有一个限制,总分配chunk 数 不大于 9。
set 中 对修改的块的大小和输入大小不做任何检查,得到堆溢出点
del 中 有free 用来触发unlink
print 中 输出对应 chunk 上的值,可在unlink之后用来leak。 -
利用思路 :
- 利用 unlink 修改 一个chunk 的地址 为buf + n *4 ,从而可以修改buf[] 中的chunk 的地址。(修改这里的地址是因为这里的地址可以通过功能函数访问,进行读写)
- set(target_chunk_index , payload) , 修改buf[0]的地址为free@got ,并通过 print函数 进行leak,获取free函数的地址后 , 进行libc_search
3.查找到对应的libc后获取system和binsh的偏移,并且利用free的地址进行计算,获得在elf中的地址
4.再次利用unlink的chunk进行对buf[]的修改 , 使得 *(buf) = free@got , *(buf +4)= addr_bin_sh
5.set(0 , p32(addr_system)) , 覆盖 free的got表值为system函数的地址
6.delete(1) , 执行 free(buf[1]) , 触发 system("/bin/sh") get_shell