0%

House Of Orange-原理

House Of Orange

House Of Orange 的利用比较特殊(题目中不存在 free 函数或其他释放堆块的函数 )

House Of Orange 核心就是通过漏洞利用获得 free 的效果

这种操作的原理简单来说是当前堆的 top chunk 尺寸不足以满足申请分配的大小的时候,原来的 top chunk 会被释放并被置入 unsorted bin 中,通过这一点可以在没有 free 函数情况下获取到 unsorted bins

然后利用 unsorted bin attack 结合 FSOP(也就是通过修改 IO_list_all 劫持到伪造的 IO_FILE 结构上)从而getshell


House Of Orange 利用姿势

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <stdlib.h>
#define fake_size 0x0fe1 // 注意页对齐

int main(void)
{
void *ptr;

ptr=malloc(0x10);
ptr=(void *)((long long)ptr+24);

*((long long*)ptr)=fake_size; // overwrite top chunk size

malloc(0x2000); //小于 mmap 分配阈值(128K,0x20000)

malloc(0x60);
}

申请 “0x2000” 字节后:

1
2
3
4
5
Free chunk (unsortedbin) | PREV_INUSE
Addr: 0x55555555b020
Size: 0x1fc1
fd: 0x7ffff7dd1b78
bk: 0x7ffff7dd1b78

申请 “0x60” 字节后:

1
2
3
4
5
6
7
8
9
Allocated chunk | PREV_INUSE
Addr: 0x55555555b020
Size: 0x71

Free chunk (unsortedbin) | PREV_INUSE
Addr: 0x55555555b090
Size: 0x1f51
fd: 0x7ffff7dd1b78
bk: 0x7ffff7dd1b78

直接在 top chunk 中向上申请了( libc-2.27 和 libc-2.31 直接挂掉)

伪造的 top chunk size 的要求 :

  • 伪造的 size 必须要对齐到内存页(0x0fe1、0x1fe1、0x2fe1、0x3fe)
  • size 要大于 MINSIZE(0x10)
  • size 要小于之后申请的 chunk size + MINSIZE(0X10)
  • size 的 prev inuse 位必须为“1”

伪造 top chunk size 时,需要保持最后3字节与GDB中显示的真正 top chunk size 一致

利用条件:

  • 有堆溢出(溢出得足够多,至少可以修改 top chunk size)
  • 可以申请较大的空间
  • 没有释放模块(看见程序没有 free,realloc等函数时,优先考虑打House Of Orange)

后续可以配合 unsortedbin attack 和 FSOP 获取 shell,简略过程为:

  • 利用 unsortedbin attack 在 _IO_list_all 中写入 main_arean + 88
  • 如果把 main_arean + 88 当成一个 IO_FILE 结构体,那么 struct _IO_FILE *_chain 指针的地址为 main_arena + 88 + 0x68(main_arena+0xc0)
  • 而 main_arena + 0xc0 中存储有大小为“0x60”的 smallbin 中第一个 chunk 的地址
  • 如果可以在大小为“0x60”的第一个 small chunk 中伪造 IO_FILE 结构体

详细过程在分析 FSOP 时说明

版本对 House Of Orange 的影响

libc-2.23

House Of Orange 适用于 libc-2.23 及之前的版本,libc-2.24 版本增加了 vtable check,但仍然可以绕过,libc-2.27 及之后的版本取消了 abort 刷新流的操作,所以这个方法基本就失效了

libc-2.24

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/* Perform vtable pointer validation.  If validation fails, terminate
the process. */
static inline const struct _IO_jump_t *
IO_validate_vtable (const struct _IO_jump_t *vtable)
{
/* Fast path: The vtable pointer is within the __libc_IO_vtables
section. */
uintptr_t section_length = __stop___libc_IO_vtables - __start___libc_IO_vtables;
const char *ptr = (const char *) vtable;
uintptr_t offset = ptr - __start___libc_IO_vtables;
if (__glibc_unlikely (offset >= section_length))
/* The vtable pointer is not in the expected section. Use the
slow path, which will terminate the process if necessary. */
_IO_vtable_check ();
return vtable;
}

IO_validate_vtable要求我们的vtable必须在__stop___libc_IO_vtables__start___libc_IO_vtables之间,这就意味着我们不能利用任意地址来充当vtable

libc-2.27(完全失效)