WP-0ops2024-pwn-<IP Management System>
字数 1354 2025-08-22 12:22:54

IP Management System Pwn 漏洞分析与利用

题目概述

这是一个来自0ops战队2024年国际比赛的堆利用题目,题目实现了一个IP地址管理系统,允许用户创建IP集合、添加/删除IP地址、查询IP状态以及删除IP集合。程序存在堆溢出漏洞,可以通过精心构造的IP地址操作实现任意地址读写。

主要功能分析

1. 创建IP集合

printf("Please input start ip:");
read(0, s, 0x1FuLL);
v1 = ret_ip_addr(s);
printf("Please input end ip:");
read(0, s, 0x1FuLL);
v2 = ret_ip_addr(s);
if (v1 > v2 || v2 - v1 + 1 > 0x10000) _exit(-1);
v3 = malloc(((v2 - v1) >> 3) + 1); // 最大size是0x2000
  • 输入起始IP和结束IP
  • 计算IP范围大小:(end_ip - start_ip) / 8 + 1
  • 最大允许分配大小为0x2000字节
  • 每个IP用1个bit位表示,因此需要除以8

2. 添加/删除IP地址

unsigned __int64 __fastcall add_or_delet(int opt) {
    // ... 变量声明省略 ...
    
    if (!ptr) _exit(-1);
    printf("Please input ip: ");
    read(0, s, 0x2FuLL);
    
    // 处理三种IP输入格式
    if (strchr(s, '-')) {       // "ip1-ip2"格式
        v4 = 1;
        v6 = strtok(s, "-");
        nptr = strtok(0LL, "-");
    } 
    else if (strchr(s, '/')) {  // "ip/num"格式
        v4 = 2;
        v6 = strtok(s, "/");
        nptr = strtok(0LL, "/");
    } 
    else {                      // 单个"ip"格式
        v4 = 3;
        v6 = s;
    }
    
    v2 = ret_ip_addr(v6);
    if (v2 < creat_ip_start || v2 > creat_ip_end) _exit(-1);
    
    // 根据格式计算v3(结束IP)
    if (v4 == 3) {
        v3 = v2; // 格式为"ip"
    } 
    else if (v4 == 1) {
        v3 = ret_ip_addr(nptr); // 格式为"ip-ip"
    } 
    else {
        v5 = atoi(nptr); // 格式为"ip/num"
        if (v5 <= 0 || v5 > 31) _exit(-1);
        v2 &= ~((1 << (32 - v5)) - 1);
        v3 = ((1 << (32 - v5)) - 1) | v2;
    }
    
    if (v3 > creat_ip_end) _exit(-1);
    
    // 设置或清除bit位
    for (i = v2; i <= v3; ++i) {
        if (opt) 
            ptr[(i - creat_ip_start) / 8] |= 1 << ((i - creat_ip_start) & 7); // 设置bit
        else 
            ptr[(i - creat_ip_start) / 8] &= ~(1 << ((i - creat_ip_start) & 7)); // 清除bit
    }
    
    puts("Edit IP Set Success!");
    return v10 - __readfsqword(0x28u);
}

关键点:

  1. 三种IP输入格式

    • "ip":单个IP地址
    • "ip1-ip2":IP范围
    • "ip/num":CIDR表示法,最有利用价值
  2. "ip/num"格式的处理

    v5 = atoi(nptr); // num值
    if (v5 <= 0 || v5 > 31) _exit(-1);
    v2 &= ~((1 << (32 - v5)) - 1);  // 起始IP = ip & ~((1<<(32-num))-1)
    v3 = ((1 << (32 - v5)) - 1) | v2; // 结束IP = ip | ((1<<(32-num))-1)
    
    • 可以用于大范围修改bit位
    • ip_start末几位不为0时,可能导致v2 < ip_start,造成向上溢出
  3. bit位操作

    • 通过(i - creat_ip_start) / 8计算字节偏移
    • 通过(i - creat_ip_start) & 7计算bit位偏移
    • 使用位运算设置或清除特定bit

3. 查询IP状态

if (((ptr[(v1 - creat_ip_start) / 8] >> ((v1 - creat_ip_start) & 7)) & 1) != 0)
    puts("IP is in the set");
else
    puts("IP is not in the set");
  • 可以用于读取任意bit位,实现信息泄露

4. 删除IP集合

if (!ptr) _exit(-1);
free(ptr);
ptr = 0LL;
creat_ip_start = 0;
creat_ip_end = 0;
return puts("Delete IP Set Success!");
  • 简单的free操作,没有UAF漏洞

漏洞利用分析

1. 负数的处理

v2 < ip_start时,(i - creat_ip_start)为负数,此时:

// 对于负数i:
(i - creat_ip_start) / 8  // 除法结果向零舍入
(i - creat_ip_start) & 7  // 等价于取模运算

测试代码显示负数bit位操作的行为:

-67 : -8 == 1 << 5
-66 : -8 == 1 << 6
-65 : -8 == 1 << 7
-64 : -8 == 1 << 0
-63 : -7 == 1 << 1
...
-8 : -1 == 1 << 0
-7 : 0 == 1 << 1
...
0 : 0 == 1 << 0
1 : 0 == 1 << 1
...

2. 利用思路

  1. 信息泄露

    • 使用查询功能读取堆或libc地址
    • 通过设置特定bit位构造伪造的堆块结构
  2. 堆布局

    • 分配大chunk,修改size使其变小
    • 在堆内伪造chunk结构
    • 通过free操作使chunk进入unsorted bin或small bin
  3. 具体步骤

    • 修改size的PREV_INUSE位,实现向上合并
    • 劫持tcache bin
    • 修改__free_hook或类似函数指针为system
    • 通过添加IP触发命令执行

3. 利用代码关键函数

def ret2_str_ip(ip):
    # 将整数IP转换为字符串格式
    ret = ''
    for i in range(4):
        ret += str(ip >> (8 * (3 - i)) & 255)
        if i != 3: ret += '.'
    return ret

def write_addr(ip, off, value):
    # 在指定偏移处写入值(通过设置bit位)
    n = 0
    va = value
    while va:
        n += 1
        va = va >> 1
    for i in range(n):
        bit = value & 1
        if bit == 1:
            add(ip + off * 8 + i)
        value = value >> 1

def get_libc(ip, off):
    # 通过查询功能读取内存值
    libc = 0
    for i in range(48):
        libc += jude(ip + off * 8 + i) << i
    return libc

完整利用流程

  1. 泄露libc地址

    • 创建大chunk并修改size
    • 释放后重新分配,读取unsorted bin中的libc地址
  2. 泄露堆地址

    • 类似操作使chunk进入small bin
    • 读取small bin中的堆地址
  3. 构造fake chunk

    • 使用write_addr函数伪造chunk结构
    • 设置size和fd/bk指针绕过unlink检查
  4. 劫持控制流

    • 修改strtok相关的函数指针为system
    • 通过添加IP触发命令执行

防御建议

  1. 输入验证

    • 严格检查IP地址范围,防止负数计算
    • 限制CIDR表示法中的num值范围
  2. 内存管理

    • 使用calloc代替malloc初始化内存
    • 实现安全的size检查
  3. 安全机制

    • 启用ASLR和PIE
    • 使用现代glibc版本的安全特性

总结

这道题目展示了如何通过精心构造的IP地址操作实现堆溢出和任意地址读写。关键点在于理解"ip/num"格式的处理方式以及负数情况下的bit位操作行为。利用过程涉及堆布局、信息泄露、伪造chunk结构等技术,是一个典型的堆利用案例。

IP Management System Pwn 漏洞分析与利用 题目概述 这是一个来自0ops战队2024年国际比赛的堆利用题目,题目实现了一个IP地址管理系统,允许用户创建IP集合、添加/删除IP地址、查询IP状态以及删除IP集合。程序存在堆溢出漏洞,可以通过精心构造的IP地址操作实现任意地址读写。 主要功能分析 1. 创建IP集合 输入起始IP和结束IP 计算IP范围大小: (end_ip - start_ip) / 8 + 1 最大允许分配大小为0x2000字节 每个IP用1个bit位表示,因此需要除以8 2. 添加/删除IP地址 关键点: 三种IP输入格式 : "ip" :单个IP地址 "ip1-ip2" :IP范围 "ip/num" :CIDR表示法,最有利用价值 "ip/num"格式的处理 : 可以用于大范围修改bit位 当 ip_start 末几位不为0时,可能导致 v2 < ip_start ,造成向上溢出 bit位操作 : 通过 (i - creat_ip_start) / 8 计算字节偏移 通过 (i - creat_ip_start) & 7 计算bit位偏移 使用位运算设置或清除特定bit 3. 查询IP状态 可以用于读取任意bit位,实现信息泄露 4. 删除IP集合 简单的free操作,没有UAF漏洞 漏洞利用分析 1. 负数的处理 当 v2 < ip_start 时, (i - creat_ip_start) 为负数,此时: 测试代码显示负数bit位操作的行为: 2. 利用思路 信息泄露 : 使用查询功能读取堆或libc地址 通过设置特定bit位构造伪造的堆块结构 堆布局 : 分配大chunk,修改size使其变小 在堆内伪造chunk结构 通过free操作使chunk进入unsorted bin或small bin 具体步骤 : 修改size的PREV_ INUSE位,实现向上合并 劫持tcache bin 修改 __free_hook 或类似函数指针为system 通过添加IP触发命令执行 3. 利用代码关键函数 完整利用流程 泄露libc地址 : 创建大chunk并修改size 释放后重新分配,读取unsorted bin中的libc地址 泄露堆地址 : 类似操作使chunk进入small bin 读取small bin中的堆地址 构造fake chunk : 使用write_ addr函数伪造chunk结构 设置size和fd/bk指针绕过unlink检查 劫持控制流 : 修改 strtok 相关的函数指针为system 通过添加IP触发命令执行 防御建议 输入验证 : 严格检查IP地址范围,防止负数计算 限制CIDR表示法中的num值范围 内存管理 : 使用calloc代替malloc初始化内存 实现安全的size检查 安全机制 : 启用ASLR和PIE 使用现代glibc版本的安全特性 总结 这道题目展示了如何通过精心构造的IP地址操作实现堆溢出和任意地址读写。关键点在于理解"ip/num"格式的处理方式以及负数情况下的bit位操作行为。利用过程涉及堆布局、信息泄露、伪造chunk结构等技术,是一个典型的堆利用案例。