curl库Use-After-Free漏洞分析:从任意写入到潜在安全风险

本文详细分析了curl库中一个Use-After-Free漏洞的技术细节,该漏洞在某些版本中可导致任意写入,文章涵盖漏洞原理、复现步骤、影响版本及修复方案,涉及内存管理、splay树操作等底层技术实现。

curl Use-After-Free漏洞技术分析

漏洞概述

该漏洞是一个Use-After-Free(释放后使用)漏洞,在某些curl版本中可导致任意写入/读取内存。漏洞存在于curl处理并行传输(-Z选项)和URL通配符([0-10]格式)时的内存管理逻辑中。

受影响版本

  • curl 8.13.0 (x86_64-pc-linux-gnu) - 可导致任意读/写
  • curl 8.14.0 (x86_64-pc-linux-gnu) - 可导致任意读/写
  • curl 8.15.0 (x86_64-pc-linux-gnu) - 仅导致任意写入

漏洞复现步骤

  1. 下载并编译目标版本:
1
2
3
wget https://github.com/curl/curl/releases/download/curl-8_14_0/curl-8.14.0.zip && unzip curl-8.14.0.zip && cd curl-8.14.0
CFLAGS="-fsanitize=address,undefined -g -O0 -fno-omit-frame-pointer" ./configure --with-openssl
make all -j$(nproc) && sudo make install
  1. 触发漏洞:
1
while true; do curl --url "c071993_domain22.com/image[0-10]tp.com/dir[0-10]/api/path[0-10]/api" -Zs --max-time 0.01; echo $?; done

技术原理

漏洞触发路径

  1. curl_easy_init()调用Curl_open()分配Curl_easy结构体
  2. 传输完成后post_per_transfer()调用curl_easy_cleanup(),进而调用Curl_close()释放内存
  3. Curl_expire_clear()调用Curl_splayremove()时传入已释放的&data->state.timenode指针
  4. Curl_splayremove()对已释放内存进行指针操作(splay.c:234行),导致UAF和任意写入

关键代码片段

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
// 内存分配
struct Curl_easy *data = calloc(1, sizeof(struct Curl_easy));

// 内存释放
free(data); // struct Curl_easy *data被释放但未置空

// UAF发生点
int Curl_splayremove(struct Curl_tree *t,
                    struct Curl_tree *removenode, // 已释放的&data->state.timenode
                    struct Curl_tree **newroot)
{
    removenode->samep->samen = removenode->samen; // splay.c:234行,写入已释放内存
    removenode->samen->samep = removenode->samep;
}

漏洞条件

  • 必须使用URL通配符(方括号范围格式)
  • 需要启用并行模式(-Z选项)
  • –max-time设置为较小值(如0.01)

修复方案

在curl 8.15.0中通过修改multi.c的curl_multi_perform()函数修复:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
+ (void)add_next_timeout(now, multi, data);
if(data->mstate == MSTATE_PENDING) {
    bool stream_unused;
    CURLcode result_unused;
    if(multi_handle_timeout(data, &now, &stream_unused, &result_unused)) {
        infof(data, "PENDING handle timeout");
        move_pending_to_connect(multi, data);
    }
}
- (void)add_next_timeout(now, multi, Curl_splayget(t));

影响分析

虽然该漏洞理论上可导致8字节任意写入,但实际利用面临以下挑战:

  1. 攻击者需要精确控制堆内存布局
  2. 依赖特定网络时序条件
  3. 写入内容不可控(仅为内部splay树操作)

参考链接

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计