堆溢出 | 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。

  • 利用思路 :

    1. 利用 unlink 修改 一个chunk 的地址 为buf + n *4 ,从而可以修改buf[] 中的chunk 的地址。(修改这里的地址是因为这里的地址可以通过功能函数访问,进行读写)
    2. 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

exp.py

你可能感兴趣的:(堆溢出 | unlink)