Redis hyperloglog远程代码执行漏洞 (CVE-2025-32023)复现分析
字数 2498 2025-09-01 11:26:03
Redis HyperLogLog 远程代码执行漏洞(CVE-2025-32023)分析与利用
漏洞概述
Redis HyperLogLog(HLL)数据结构在处理稀疏型与密集型HLL合并操作时存在整数溢出漏洞,攻击者可通过构造恶意HLL数据触发该漏洞,最终实现远程代码执行。该漏洞编号为CVE-2025-32023,影响Redis多个版本。
漏洞原理
HyperLogLog数据结构
HyperLogLog是Redis用于基数统计的数据结构,使用16384个6位寄存器存储基数估算中间状态。HLL有两种存储模式:
- 密集模式:直接存储所有寄存器值,内存消耗较大
- 稀疏模式:通过编码压缩存储连续相同值,编码格式如下:
| 类型 | 编码格式 | 说明 |
|---|---|---|
| 拓展零运行 | xzero 01xxxxxx yyyyyyyy |
表示连续较长的零值区域 |
| 零运行 | zero 00xxxxxx |
设置连续但不够长的零值区域 |
| 特殊值 | 1vvvvvxx |
紧凑存储小值 |
漏洞根源
在hllMerge和hllSparseToDense函数中存在整数溢出漏洞:
- 处理
ZERO/XZERO编码时无边界检查,仅VAL类型存在检查if ((runlen + idx) > HLL_REGISTERS) break - 检查中的
idx为int类型,可能为负值 - 溢出后
HLL_DENSE_SET_REGISTER(hdr->registers,idx,regval)可越界修改堆内存
利用流程
1. 通过整数溢出导致受限地址写
利用步骤:
-
构造恶意稀疏型HLL数据:
- 以
HYLL魔术头开头 - 设置稀疏编码标识并填充至0x10字节完成头部构造
- 通过
xzero(0x4000)-0x3fffd与xzero(0xc000-0x956c)组合使计数器溢出 - 通过
p8(0b1_00011_00)设置runlen=1、regval=4(对应SDS_TYPE_64)
- 以
-
触发漏洞:
- 将目标key(即
pfmerge命令的首个参数)预设为稀疏型HLL - 确保复制后的新空间在转换为密集型时触发漏洞
- 将目标key(即
效果:实现受限地址写能力(覆盖范围为int负数空间的3/4)
2. 堆风水构建实现大范围内存读写
堆布局构建:
- 预分配三个
sdshdr16实例(sdsa/b/c) - 调整数据尺寸使其均分配0x3800大小的堆块
- 形成四个0x3800堆块连续排列的内存布局
内存修改:
- 通过漏洞修改
sdsb的flags字段 - 将
SDSHDR16(0x02)改为SDSHDR64(0x04) - 使
len/alloc字段解析范围从2字节扩展至8字节
效果:实现大范围内存读写能力
3. 堆喷射和内存块识别泄露基地址
3.1 泄露sdsb基址
步骤:
- 通过
embstr对象内存布局实现地址计算 - 采用特征化批量喷射策略(堆喷射)
- 生成8字节随机标记用于识别
- 计算喷射总量
spray_cnt = 0x100000 // 0x40 - 每个对象命名格式为
sds:_{idx},内容结构为标记(8字节)+序号(8字节)
地址解析:
- 通过三重校验确保目标对象的合法性:
- 对象头校验(
dump[tofs] == 0x80表示embstr类型) - 引用计数校验(
u32(dump[tofs+4:tofs+8]) == 0x1) - SDS头部校验(
dump[tofs+0x10:tofs+0x13] == b'\x2b\x2b\x01')
- 对象头校验(
- 逆向推导出
sdsb字符串的头部地址
3.2 泄露程序基地址
jemalloc内存结构:
- 主分配区采用独立开辟的2MB内存块
- 堆块头部包含
base_block_t结构体、edata_t元数据及base_t管理结构 base_t中两个ehooks_t成员的ptr字段指向ehooks_default_extent_hooks
泄露方法:
- 遍历堆内存转储数据,筛选满足0x200000(2MB)大小的内存块
- 验证0xc8-0xcf与0xd8-0xdf偏移处的两个地址的低12位是否与
je_ehooks_default_extent_hooks符号的低12位一致 - 通过符号的编译偏移量反向计算进程基址
4. 构造伪模块完成栈迁移实现提权
4.1 构造模块对象
步骤:
- 修改之前泄露的
embstr对象的robj头部:- 类型标记设为0x05(对应
Module类型) - 保持原有编码和LRU字段
- 设置引用计数为1
- 将对象指针重定向至可控内存区域
- 类型标记设为0x05(对应
- 伪造
moduleValue结构体 - 修改
type指针指向地址,将free函数指向ROP gadget
4.2 栈迁移与ROP链执行
ROP链功能:
- 通过三次调用
dup2系统调用,将当前连接的文件描述符fd复制到标准输入(0)、标准输出(1)和标准错误(2) - 执行
execve("/bin/sh")获取shell
栈迁移过程:
- 进入gadget#0,
rdi被设置为badr + 0x2010 - 执行gadget#1,
rdi被修改为badr + 0x2028 - 执行gadget#2,
rbp的值为badr + 0x2028 - 执行
leave指令,rsp的值变为badr + 0x2030,完成栈转移
防御建议
- 升级到修复该漏洞的Redis版本
- 对HLL数据结构操作添加严格的边界检查
- 启用Redis的安全配置,如禁用危险命令、限制网络访问等
- 使用内存保护机制如ASLR、DEP等
总结
CVE-2025-32023漏洞通过精心构造的HLL数据结构触发整数溢出,结合堆布局操控和ROP技术实现远程代码执行。该漏洞利用展示了从内存破坏到完整权限提升的完整攻击链,强调了数据结构边界检查的重要性。