libcurl FTP路径规范化漏洞解析:编码路径遍历攻击与技术修复

本文详细分析libcurl在处理FTP路径时存在的安全漏洞,该漏洞允许攻击者通过编码的%2e%2e实现目录遍历。文章包含漏洞原理、复现步骤、影响分析和修复建议,涉及路径规范化、URL解码和CWD命令执行等核心技术细节。

libcurl FTP路径规范化漏洞分析

漏洞概述

libcurl在处理FTP路径时存在路径规范化缺陷,允许解码的%2e%2e转换为CWD ..命令,导致目录遍历攻击(路径遍历,CWE-22)。

技术细节

漏洞原理

lib/ftp.c中的ftp_parse_url_path函数在URL解码FTP路径段(如%2e%2e)后,使用临时循环将解码后的路径拆分为组件,跳过由//产生的空组件。代码未执行规范路径规范化(无基于堆栈的...处理)。因此,编码的遍历序列如%2e%2e解码为..并可能成为正常路径组件,导致libcurl向远程FTP服务器发出CWD ..命令。

受影响版本

curl 8.4.0 (x86_64-pc-linux-gnu) libcurl/8.4.0 OpenSSL/1.1.1k zlib/1.2.11

复现步骤

  1. 准备测试环境:
1
2
3
4
mkdir -p ~/curl-test/dir ~/curl-test/testdir
echo "INSIDE" > ~/curl-test/dir/inside.txt
echo "OUTSIDE" > ~/curl-test/testdir/outside.txt
cd ~/curl-test
  1. 启动FTP服务器:
1
2
python3 -m pip install pyftpdlib
python3 -m pyftpdlib -w
  1. 执行curl命令:
1
curl --trace-ascii curl_trace.txt -v "ftp://127.0.0.1:2121/dir//%2e%2e/testdir" 2>&1 | tee curl_stdout.txt

代码分析

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
/* URL解码FTP路径 */
result = Curl_urldecode(ftp->path, 0, &ftpc->rawpath, &pathLen, REJECT_CTRL);

/* 将URL路径解析为单独的路径组件 */
while(dirAlloc--) {
    const char *spos = strchr(curPos, '/');
    size_t clen = spos - curPos;
    if(!clen && (ftpc->dirdepth == 0))
        ++clen;
    /* 跳过空路径组件,如"x//y" */
    if(clen) {
        ftpc->dirs[ftpc->dirdepth].start = (int)(curPos - rawPath);
        ftpc->dirs[ftpc->dirdepth].len = (int)clen;
        ftpc->dirdepth++;
    }
    curPos = spos + 1;
}

/* 后续用于发送CWD命令 */
result = Curl_pp_sendf(data, &ftpc->pp, "CWD %s", ftpc->entrypath);

影响分析

安全影响

  • 路径遍历(CWE-22)—输入验证不当(CWE-20)
  • 远程文件泄露:攻击者可构造URL导致libcurl遍历到父目录并尝试在目标目录外执行RETR
  • 客户端过滤器绕过:执行简单清理的应用程序可能被编码等价物(%2e%2e)绕过
  • 供应链和自动化滥用:自动处理FTP URL的软件可能被诱骗获取或覆盖允许区域外的文件

严重程度

建议严重性:高 CVSS向量示例:AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:L/A:N → CVSS ~7.x

修复建议

  1. 在URL解码后、拆分为路径组件之前执行规范路径规范化(基于堆栈的./..处理,合并//
  2. 拒绝尝试遍历允许根目录之上的路径(返回错误而不是发送CWD)
  3. 为编码遍历案例和混合排列添加单元测试

项目方回应

curl维护者确认该问题在curl 8.13.0及更高版本中已修复,并指出:

  • 允许攻击者控制URL本身已经存在很大风险
  • FTP客户端完全可以按要求更改目录到"..",适当的目录保护必须在服务器端实现
  • 使用--path-as-is参数可以允许此行为

报告最终被标记为"不适用"并公开披露。

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