首页
社区
课程
招聘
The House of Mind (FASTBIN METHOD) + PRIME
发表于: 2022-3-5 22:13 14227

The House of Mind (FASTBIN METHOD) + PRIME

2022-3-5 22:13
14227

  接着啃http://phrack.org/issues/66/10.html,前段时间在论坛发的The House of Mind,已经对其中的4.1节--THE HOUSE OF MIND做了总结,本文接着原文的后续内容,对4.1.1节--FASTBIN METHOD、4.1.2节--av->top NIGHTMARE、4.2节--THE HOUSE OF PRIME,进行总结。

THE HOUSE OF MIND
  每种THE HOUSE OF XX,各自代表一种利用技术,适用于不同的漏洞形式,每种利用技术,可能又包含多种具体的利用方法,FASTBIN METHOD 和 av->top NIGHTMARE,正是THE HOUSE OF MIND的另外两个子方法,其中av->top NIGHTMARE是一种不成立的方法,作者将它写出来,可能是想表达:不要只想着学习已有的方法,自己也要尝试想想别的路子。

FASTBIN METHOD
漏洞代码已经在4.1节列出,为了方便阅读,这里再来一遍:

溢出数据构造方案:

chunk2->size = 0x0d,fake_heap->ar_ptr = EBP
由于main()栈帧上没有EIP(main()函数没有上一层函数可以返回,main()函数中的return会被编译器替换成exit()),所以为了说明后续思路,作者调整了一下漏洞程序:

思路3的目的是,欺骗glibc认为chunk2所属的arena在EBP处(EBP为执行fvuln()函数时的EBP值,即fvuln()的栈帧起始位置,这个地方存的是main()的栈帧起始位置,往上4个字节存的是main()函数地址),这样,利用"fake_arene->max_fast = chunk2",就可以将fvuln()的返回地址修改为chunk2,而不再是main()函数,从而在fvuln()函数返回时,执行shell code。

但是,这样仍然存在fake_arena->mutex != 0的问题,因为main()的栈帧起始位置不可能为0。

THE HOUSE OF PRIME
THE HOUSE OF PRIME适用于,可以利用bug控制malloc()返回值,并且漏洞程序中存在往该"分配内存"写用户输入的逻辑(比如先欺骗malloc()返回漏洞函数的EBP,后续通过用户输入,就可以改写漏洞函数的返回地址了),原文中的示范漏洞程序如下:

根据The House of Mind的经验,这里就不再过于详细说明了,直接将内存布局、构造数据,以及漏洞程序的执行流程,汇总如下:

漏洞程序执行过程说明:
(1) free(ptr1)
  伪造chunk1->size,欺骗glibc将main_arena->max_fast修改为chunk1的地址,正常逻辑中,max_fast最大可以等于512字节,表示小于512字节的都是fast chunk,被改成chunk1地址(0x80XXXXX),就表示大小不超过0x80XXXXX的chunk,glibc都会将其当作fast chunk处理。
(2) free(ptr2)
  有了步骤(1)的铺垫,chunk2会被glibc当作fast chunk释放,并且归属于main_arena->fastbins[289],这显然已经在main_arena结构之外了,实际上正好与arena_key全局变量重叠(这是将chunk2->size构造为0x919的原因,可以事先通过objdump,查看arena_key与main_arena之间的偏移,并计算得到),从而又欺骗glibc将arena_key修改为chunk2,这样,通过构造chunk2的内容,就可以控制下一次malloc()返回任意想要的地址。
(3) ptr3 = malloc(1024)
  经过步骤(2)后,glibc就会从arena_key分配内存,而arena_key->max_fast与chunk2->size是重叠的,即arena_key->max_fast=0x919,所以1032字节大小的chunk,会被当作fast chunk,从arena_key->fastbins[127]链表中摘取,根据构造数据可知,这个值为EBP。
(4) strncpy(ptr3, argv[2], 1024-1)
  此时ptr3=EBP,执行strncpy(),就会向上覆盖返回地址的值,并且拷贝内容来自用户输入,显然可以覆盖成shell code的地址,根据布局图可以看见,shell code的位置可以有很多选择,具体构造就不再重复叙述了。
(5) 判断条件欺骗
  用于欺骗判断条件的构造数据,布局图中已经使用虚线标出,都不难理解,这里主要说明一下_int_malloc()中的判断2,要求chunk3->size必须与分配大小匹配(示范漏洞程序的第三个启动参数,是写入栈中的,所以正好可以被利用,满足这一点)。
 
实际中漏洞程序,逻辑是不受攻击者控制的,比如示范漏洞程序中最后一次malloc()的参数值,使判断1不成立,_ini_free()就会走后续逻辑,从unsorted bin中分配内存:

unsorted bin相当于一种缓存,每次尝试从unsorted bin分配chunk时,glibc总是从unsorted bin链表头依次取出其中的chunk,如果恰好满足分配内存的大小,就返回给调用者,否则转移到相应的fast bin(av->fastbins[x])或者bin(av->bins[x]),上图代码就是从unsorted bin链表头摘除chunk的过程,当中的if用于判断是否为last remainder chunk,构造数据可以很容易使其不成立,因此可以简化成以下4条语句:

通过最后一条语句可知,如果欺骗bck=EIP-8,就可以将漏洞函数的返回地址,改写为unsorted_chunks(av),即布局图中&arena_key->bins[0],再通过第一条和第二条语句可知,如果往unsorted_chunks(av)->bk即&av->bins[0]+12处放入x,并往x->bk处放入EIP-8,就可以使bck=EIP-8,所以,x值其实有很多选择,只要保证通过溢出数据可以覆盖到,并且不与其它关键的构造位置冲突即可,原文中选的是&av->bins[0]+4,那么相应地,往x->bk即&av->bins[0]+16处放入EIP-8,并在&arena_key->bins[0]位置构造shell code,即可实现利用。
 

/*
*K-sPecial's vulnerable program
*/
#include <stdio.h>
#include <stdlib.h>
 
int main (void) {
   char *ptr  = malloc(1024);        /* First allocated chunk */
   char *ptr2;                       /* Second chunk          */
   /* ptr & ~(HEAP_MAX_SIZE-1) = 0x08000000 */
   int heap = (int)ptr & 0xFFF00000;
   _Bool found = 0;
 
   printf("ptr found at %p\n", ptr);  /* Print address of first chunk */
 
   // i == 2 because this is my second chunk to allocate
   for (int i = 2; i < 1024; i++) {
       /* Allocate chunks up to 0x08100000 */
       if (!found && (((int)(ptr2 = malloc(1024)) & 0xFFF00000) == \
                                       (heap + 0x100000))) {
           printf("good heap allignment found on malloc() %i (%p)\n", i, ptr2);
           found = 1; /* Go out */
           break;
       }
   }
   malloc(1024); /* Request another chunk: (ptr2 != av->top) */
   /* Incorrect input: 1048576 bytes */
   fread (ptr, 1024 * 1024, 1, stdin);
 
   free(ptr);   /* Free first chunk  */
   free(ptr2);  /* The House of Mind */
   return(0);   /* Bye */
}
/*
*K-sPecial's vulnerable program
*/
#include <stdio.h>
#include <stdlib.h>
 
int main (void) {
   char *ptr  = malloc(1024);        /* First allocated chunk */
   char *ptr2;                       /* Second chunk          */
   /* ptr & ~(HEAP_MAX_SIZE-1) = 0x08000000 */
   int heap = (int)ptr & 0xFFF00000;
   _Bool found = 0;
 
   printf("ptr found at %p\n", ptr);  /* Print address of first chunk */
 
   // i == 2 because this is my second chunk to allocate
   for (int i = 2; i < 1024; i++) {
       /* Allocate chunks up to 0x08100000 */
       if (!found && (((int)(ptr2 = malloc(1024)) & 0xFFF00000) == \
                                       (heap + 0x100000))) {
           printf("good heap allignment found on malloc() %i (%p)\n", i, ptr2);
           found = 1; /* Go out */
           break;
       }
   }
   malloc(1024); /* Request another chunk: (ptr2 != av->top) */
   /* Incorrect input: 1048576 bytes */
   fread (ptr, 1024 * 1024, 1, stdin);
 
   free(ptr);   /* Free first chunk  */
   free(ptr2);  /* The House of Mind */
   return(0);   /* Bye */
}
fb = &(av->fastbins[fastbin_index(size)]);
*fb = p;  // av->max_fast = p
fb = &(av->fastbins[fastbin_index(size)]);
*fb = p;  // av->max_fast = p
int fvuln()
{
   // 原漏洞程序main()函数中的代码
}
 
int main( int argc, char *argv[] )
{
   return fvuln();
}
int fvuln()
{
   // 原漏洞程序main()函数中的代码
}
 
int main( int argc, char *argv[] )
{
   return fvuln();
}
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
 
void fvuln(char *str1, char *str2, int age)
{
   int local_age;
   char buffer[64];
   char *ptr = malloc(1024);
   char *ptr1 = malloc(1024);
   char *ptr2 = malloc(1024);
   char *ptr3;
 
   local_age = age;
   strncpy(buffer, str1, sizeof(buffer)-1);
 
   printf("\nptr found at [ %p ]", ptr);
   printf("\nptr1ovf found at [ %p ]", ptr1);
   printf("\nptr2ovf found at [ %p ]\n", ptr2);
 
   printf("Enter a description: ");
   fread(ptr, 1024 * 5, 1, stdin);
 
   free(ptr1);
   printf("\nEND free(1)\n");
   free(ptr2);
   printf("\nEND free(2)\n");
 
   ptr3 = malloc(1024);
   printf("\nEND malloc()\n");
   strncpy(ptr3, str2, 1024-1);
 
   printf("Your name is %s and you are %d", buffer, local_age);
}
 
int main(int argc, char *argv[])
{
   if(argc < 4) {
       printf("Usage: ./hop name last-name age");
       exit(0);
   }
 
   fvuln(argv[1], argv[2], atoi(argv[3]));
   return 0;
}
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
 
void fvuln(char *str1, char *str2, int age)
{
   int local_age;

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

收藏
免费 5
支持
分享
打赏 + 50.00雪花
打赏次数 1 雪花 + 50.00
 
赞赏  Editor   +50.00 2022/04/11 恭喜您获得“雪花”奖励,安全圈有你而精彩!
最新回复 (0)
游客
登录 | 注册 方可回帖
返回
//