首页 网络安全 正文

LightFTP 多处线程数据竞争漏洞CVE-2026-70637

摘要

栋科技漏洞库关注到LightFTP 2.4通过 ftpserv.c 的 ABOR 命令出现数据争用条件漏洞,追踪为CVE-2026-70637,CVSS 4.0评分 8.2。

LightFTP是采用纯C编写、BSD-2协议超轻量FTP服务端,面向x86 32/64位架构,兼容Linux等POSIX系统,Windows靠Cygwin运行。

一、基本情况

LightFTP适合嵌入式设备文件服务、内网临时文件传输、开发调试环境、教学FTP演示,轻量化架构,无需root/管理员权限即可启动。

LightFTP内存占用低,主打极简轻量化部署,支持标准FTP主动/被动模式(PASV),完整实现STOR、RETR、ABOR、LIST等指令。

LightFTP 多处线程数据竞争漏洞CVE-2026-70637

LightFTP编译后体积仅数百 KB、内存占用极低,主打极简轻量化部署,非常适配嵌入式设备、内网测试环境、小型内网文件共享场景。

栋科技漏洞库关注到LightFTP 2.4通过 ftpserv.c 的 ABOR 命令出现数据争用条件漏洞,追踪为CVE-2026-70637,CVSS 4.0评分 8.2。

二、漏洞分析

CVE-2026-70637漏洞是 LightFTP 在 2.4 及之前版本在 ftpserv.c 中包含多个数据竞争漏洞,漏洞的评分较高,建议相关用户提高警惕。

该漏洞允许匿名攻击者在没有身份验证的情况下通过发出LIST和ABOR命令来造成未定义的行为。

控制线程关闭data_socket和file_fd描述符,而工作线程同时对worker_thread_cleanup中的相同字段进行操作,

允许操作系统重新分配过时的文件描述符,随后由无关资源上的工作线程使用,从而导致潜在的拒绝服务。

(一)详细分析

分析每个连接控制线程(ftp_client_thread)和分离的传输工作线程(stor_thread/rert_thread/list_thread”)共享ftp_context字段,

具体来说,是context->data_socket、context->file_fd和context->worker_thread_abort,没有任何互斥体。

worker_thread_cleanup()(由ABOR或客户端断开连接时调用)关闭fds并将字段归零,

然后在尝试pthread_cancel之前进行500毫秒的纳米睡眠(worker_cleanup_TIMEOUT_NS=500000000)。

在这个500毫秒的窗口期间,worker仍然活着,并使用现在关闭的fd,在潜在的fd重用串扰的密切竞争后创建使用。

1、易受攻击的代码路径

// ftpserv.c:263 — worker_thread_cleanup, called by ftpABOR (:957)
void worker_thread_cleanup(pftp_context context) {
...
context->worker_thread_abort = 1; // :271 — WRITE (no lock)
...
if (context->data_socket != INVALID_SOCKET) { // :276 — READ (no lock)
close(context->data_socket); // :277 — CLOSE fd while worker uses it
context->data_socket = INVALID_SOCKET; // :278
}
if (context->file_fd != -1) { // :281 — READ (no lock)
close(context->file_fd); // :282 — CLOSE fd while worker uses it
context->file_fd = -1; // :283
}
nanosleep(&timeout, NULL); // 500 ms SLEEP :289
pthread_cancel(tid); // worker cancelled AFTER :293
}

Concurrently in stor_thread:

// ftpserv.c:1329 — stor_thread calls create_datasocket → accept() writes context->data_socket
// ftpserv.c:1348 — open() writes context->file_fd
// ftpserv.c:1356 — while (context->worker_thread_abort == 0) — READ (no lock)
// ftpserv.c:1361 — write(file_fd, buffer, sz) — uses the now-closed fd

2、动态验证

验证方式

1、基于上游源码路径 /opt/LightFTP/src,编译生成搭载 ThreadSanitizer(TSan,线程检测工具)的二进制程序:

gcc -fsanitize=thread -O1 -g -pthread
-I/opt/LightFTP/src/inc
cfgparse.c fcrypt.c fspathtools.c ftpconst.c ftpserv.c main.c
-o /tmp/fftp_tsan -lgnutls

2、借助 Python 测试脚本(poc_tsan_trigger.py)触发竞态条件:

执行 PASV 指令后发起 STOR 上传指令:

客户端成功建立数据连接,但并未传输任何数据,工作线程阻塞在 recv_auto(client_socket, ...) 接收函数内。

在工作线程阻塞期间,控制连接发送 ABOR 中止指令。

worker_thread_cleanup 清理函数并发执行:

工作线程仍持有 data_socket、file_fd 两个文件描述符,清理流程却同步关闭了上下文里的这两个文件句柄。

共计执行 6 组 STOR 上传测试、6 组 RETR 下载测试、8 轮并发压力测试。

ThreadSanitizer 输出:关键竞态问题

本次运行过程中,TSan 检测出 9 处互不重复的数据竞争代码段。和本次漏洞直接相关的竞态如下:

竞态 1:context->worker_thread_abort(ftpserv.c 第271行 对比 第1356行)

警告:ThreadSanitizer 捕获数据竞争(进程 PID=200)

线程 T3 在地址 0x7ff508db4f4c 执行4字节写入操作:

#0 worker_thread_cleanup 函数,文件 /opt/LightFTP/src/ftpserv.c 第271行
#1 ftpABOR 函数,文件 /opt/LightFTP/src/ftpserv.c 第957行
#2 ftp_client_thread 函数,文件 /opt/LightFTP/src/ftpserv.c 第1962行

Previous read of size 4 at 0x7ff508db4f4c by thread T4:
  #0 stor_thread          /opt/LightFTP/src/ftpserv.c:1356

汇总:ThreadSanitizer 在 /opt/LightFTP/src/ftpserv.c 第271行的 worker_thread_cleanup 函数检出数据竞争。

控制线程 T3 写入 worker_thread_abort 标识,与此同时工作线程 T4 在传输循环中读取该标识。

竞态2:context->data_socket 读写冲突,ftpserv.c 第276行 与 create_datasocket 第170行产生竞争。

警告:ThreadSanitizer 捕获数据竞争(进程 PID=200)

线程 T3 在地址 0x7ff508db4f38 执行4字节读取:

#0 worker_thread_cleanup  /opt/LightFTP/src/ftpserv.c:276
#1 ftpABOR /opt/LightFTP/src/ftpserv.c:957

Previous write of size 4 at 0x7ff508db4f38 by thread T4:
  #0 create_datasocket    /opt/LightFTP/src/ftpserv.c:170
  #1 stor_thread          /opt/LightFTP/src/ftpserv.c:1329

汇总:ThreadSanitizer 在 /opt/LightFTP/src/ftpserv.c 第277行 worker_thread_cleanup 函数检测到数据竞争。

TSan 检出文件描述符层面的竞争问题:工作线程通过 accept 打开了编号为7的文件描述符;控制线程在工作线程仍在使用该fd的情况下执行了 close 关闭操作。

竞态4:context->file_fd 发生读写竞争,冲突位置为 ftpserv.c 第281行与 stor_thread 第1350行。

警告:ThreadSanitizer 检测到数据竞争(进程PID=200)

线程 T3 在地址 0x7ff508db4f60 执行4字节读取:

#0 worker_thread_cleanup  /opt/LightFTP/src/ftpserv.c:281
#1 ftpABOR /opt/LightFTP/src/ftpserv.c:957

Previous write of size 4 at 0x7ff508db4f60 by thread T4:
  #0 stor_thread          /opt/LightFTP/src/ftpserv.c:1350

汇总:ThreadSanitizer 在 /opt/LightFTP/src/ftpserv.c 第281行的 worker_thread_cleanup 函数发现数据竞争。

竞态5:file_fd 文件描述符关闭操作产生竞争,ftpserv.c 第282行的关闭逻辑与工作线程的 open() 形成文件描述符关闭竞态。

警告:ThreadSanitizer 捕获数据竞争(进程 PID=200)

线程 T3 在地址 0x7ba000000060 执行8字节写入:

#0 close()(TSan拦截函数)
#1 worker_thread_cleanup /opt/LightFTP/src/ftpserv.c:282
#2 ftpABOR /opt/LightFTP/src/ftpserv.c:957
#3 ftp_client_thread /opt/LightFTP/src/ftpserv.c:1962

Previous write of size 8 at 0x7ba000000060 by thread T4:
  #0 open64()              (tsan interceptor)
  #1 stor_thread          /opt/LightFTP/src/ftpserv.c:1348

Location is file descriptor 6 created by thread T4 at:
  #0 open64() -> stor_thread:1348

3、汇总

ThreadSanitizer 在 /opt/LightFTP/src/ftpserv.c 第282行 worker_thread_cleanup 函数检出数据竞争。

文件描述符6(上传目标文件)由工作线程打开;控制线程在工作线程仍写入该文件时执行了关闭操作。

其余竞态问题同样得到证实:context->data_ipv4(286行)、context->data_port(287行)均存在竞争。

清理函数在清空这两个字段的同时,工作线程正在 create_datasocket 函数中对其赋值。

4、漏洞可利用原因

(1)数据套接符释放后复用(释放后使用漏洞)

执行 ABOR 指令关闭 context->data_socket 后,操作系统回收该文件描述符编号。

进程后续任意 open/socket/accept 调用均可复用该fd。

工作线程本地变量 client_socket 仍旧保存旧fd值,

下次调用 recv_auto 时会读取错误资源(其他会话套接字、普通文件),造成不同会话之间数据泄露。

(2)文件描述符释放后复用

同理,ABOR 关闭 context->file_fd 之后fd被回收,其他线程打开文件时可复用该编号。

执行STOR上传的工作线程后续会把客户端数据写入错误文件。

(3)worker_thread_abort 缺少内存屏障

中止标记仅为普通整型变量,未加互斥锁,也未使用原子类型修饰。TSan 证实该变量存在无同步机制的并发读写。

受编译器、CPU指令重排影响,工作线程可能长时间感知不到中止标记,无法及时终止传输。

5、修复方案

为每个上下文配置独立互斥锁,访问 context->data_socket、context->file_fd、context->worker_thread_abort 时全部加锁保护;

将 worker_thread_abort 修改为原子整型 _Atomic int。

worker_thread_cleanup 内执行 close 操作时必须持有互斥锁,

在释放锁之前以原子方式将文件描述符赋值为无效值 INVALID_SOCKET / -1,确保工作线程在发起下一次IO调用前能够检测fd已失效。

三、影响范围

LightFTP ≤ 2.4

四、修复建议

LightFTP>2.4

五、参考链接

管理员已设置登录后刷新可查看



扫描二维码,在手机上阅读
评论
更换验证码
友情链接