文章总结: 该文档详细分析了VvvebCMS1.0.8及以下版本中存在的任意文件上传漏洞CVE-2026-6257。漏洞核心在于media.php文件的rename()函数验证逻辑缺陷:检测到危险扩展名时仅设置失败标志但未中断执行,导致攻击者可绕过限制重命名文件。通过先上传.htaccess文件注入Apache指令,再上传PHP文件实现远程代码执行。文档提供了完整的Docker环境搭建步骤、手动/自动化复现方法、流量特征分析以及修复方案。 综合评分: 85 文章分类: 漏洞分析,WEB安全,应用安全,红队,应急响应
Vvveb CMS 任意文件上传导致RCE | CVE-2026-6257原理分析&研究
原创
404号浪漫 404号浪漫
404号浪漫
2026年4月27日 22:46 北京
在小说阅读器读本章
去阅读
点击蓝字,关注我们
0x0 背景介绍
Vvveb是一套开源的PHP内容管理系统,用于构建网站、博客或电商平台。
受影响版本中,media.php文件的rename()函数在检测到受限扩展名(如.php、.htaccess)时,仅设置$success=false但缺少return语句,导致验证失败后仍继续执行重命名操作。攻击者可利用此逻辑缺陷先将文本文件重命名为.htaccess注入Apache指令,再将另一文件重命名为.php从而执行任意操作系统命令。
修复版本中通过在扩展名检测逻辑后添加return语句并提前设置响应类型为json,使验证失败时立即返回错误响应并终止函数执行。
漏洞详情
| 漏洞类型 | 影响版本 | 利用复杂度 | CVE编号 | | — | — | — | — | | 文件上传 | <= 1.0.8 | 低 | CVE-2026-6257 |
攻击效果:
- 任意文件上传,导致RCE。
0x1 环境搭建(Ubuntu24)
1.1-Ubuntu24+Docker搭建配置
- ### 另存为install.sh
#!/bin/bash# 若任何命令失败则退出set -eecho "[*] 阶段1/4:检查并安装基础依赖..."if ! command -v docker &> /dev/null || ! command -v git &> /dev/null || ! command -v curl &> /dev/null; then echo "[+] 正在安装 docker.io git curl ..." sudo apt update && sudo apt install -y docker.io git curlfisudo systemctl enable --now docker 2>/dev/null || trueecho "[*] 阶段2/4:创建工作目录并克隆 Vvveb 仓库(含子模块)..."WORKDIR="$HOME/vvveb-lab-git"mkdir -p "$WORKDIR" && cd "$WORKDIR"if [ -d Vvveb ]; then echo "[!] 目标目录 Vvveb 已存在,将进行清理..." rm -rf Vvvebfigit clone --recurse-submodules https://github.com/givanz/Vvveb.gitcd Vvveb# 切换到稳定版本 1.0.8git checkout 1.0.8# 确保子模块匹配标签版本git submodule update --init --recursiveecho "[+] Vvveb 1.0.8 项目已准备完毕(含完整主题)。"echo "[*] 阶段3/4:生成 docker-compose.yml 配置文件..."cat > docker-compose.yml <<'EOF'version: '3.8'services: web: image: php:8.1-apache container_name: vvveb_web volumes: - .:/var/www/html ports: - "8080:80" depends_on: - db networks: - vvveb_net command: > sh -c "apt-get update && apt-get install -y libzip-dev && docker-php-ext-install pdo_mysql gettext mysqli zip && a2enmod rewrite && sed -i 's|DocumentRoot /var/www/html|DocumentRoot /var/www/html/public|' /etc/apache2/sites-available/000-default.conf && sed -i 's|AllowOverride None|AllowOverride All|g' /etc/apache2/conf-enabled/docker-php.conf && chown -R www-data:www-data /var/www/html && apache2-foreground" db: image: mysql:5.7 container_name: vvveb_db command: --default-authentication-plugin=mysql_native_password --sql-mode="" environment: MYSQL_ROOT_PASSWORD: root_password MYSQL_DATABASE: vvveb_db MYSQL_USER: vvveb_user MYSQL_PASSWORD: vvveb_pass volumes: - db_data:/var/lib/mysql networks: - vvveb_netvolumes: db_data:networks: vvveb_net:EOFecho "[*] 阶段4/4:启动 Docker 容器(首次需拉取镜像并编译扩展,约1分钟)..."docker compose down -v 2>/dev/null || truedocker compose up -decho ""echo "=============================================="echo " Vvveb 1.0.8 环境部署完成!"echo " - 访问地址: http://localhost:8080"echo " - 安装向导将自动启动"echo " - 数据库信息(安装时填写):"echo " 引擎:MySQLi"echo " 主机:db"echo " 库名:vvveb_db"echo " 用户:vvveb_user"echo " 密码:vvveb_pass"echo " - 管理员账号在安装时自行设置"echo " - 后台地址: http://localhost:8080/admin/"echo ""echo " - 如有问题,可查看日志: docker logs vvveb_web"echo "=============================================="
0x2 漏洞复现
2.1-脚本验证
https://github.com/Kai-One001/cve-/blob/main/Vvveb_CMS_RCE_CVE-2026-6257.py
- 脚本思路是👇:
1) 用管理员账号登录后台2) 打开媒体管理器(媒体/资源管理相关页面,内部会调用`admin/index.php?module=media/media`)3) 上传一个普通文本文件(例如a.txt)到media/根目录4) 在媒体列表中对a.txt执行重命名,改成.htaccess5) 再上传另一个文本文件(例如 shell.txt)6) 访问 https://<host>/media/shell.txt?cmd=whoami(示例)观察命令执行结果
#
2.2-手动复现
2.2.1-先上传txt文件内容为.htacces
2.2.2-对文件进行重命名
#
2.2.3-再次上传一句话
理论思路是:上传一句话txt文件,重命名为php文件配合之前重命名的.htacces进行利用,但是这里偷懒了
2.2.4-验证执行
因为.htacces有 将txt当作php执行,所以可以直接验证
#
2.2.5-主机验证
2.3-复现流量特征 (PCAP)
几个重要节点流量
- 上传接口
- 重命名文件
- ## RCE验证成功
#
0x3 漏洞原理分析
3.1-架构与模块定位
Vvveb CMS 的媒体管理并不是一个“单独的上传脚本”,而是典型的Admin控制器 + Trait 复用逻辑 结构:控制器负责路由入口与视图变量,而真正的上传/删除/重命名等危险文件操作被放进system/traits/media.php的Media trait 里复用
这类设计的预期安全边界通常是:
1. 入口层(Admin 控制器)保证 已登录、CSRF 校验、权限;
2. 逻辑层(Trait)保证 文件名净化、扩展名/MIME 拦截,并且在拦截命中时 立即中断危险操作;
3. 物理层(文件系统/Apache)按配置决定是否会解释执行。
重命名处理器里:它看似做了扩展名拦截,但缺少return/中断,导致拦截形同虚设。
| 层级 | 核心文件 | 关键职责 | 与漏洞链条的关系 |
| — | — | — | — |
| 入口层 | admin/controller/media/media.php | 后台媒体模块控制器;调用 setMediaEndpoints() 暴露 upload/rename 等 endpoint | 提供可被认证用户调用的上传/重命名入口 |
| 逻辑层(危险操作) | system/traits/media.php | upload() /rename()/delete() 等文件系统操作;扩展名、MIME 拦截;落盘与 rename/copy | 漏洞点就在 rename():拦截命中后不终止,仍执行 rename() |
| 安全边界 | admin/controller/base.php | Admin 统一初始化:登录校验、CSRF 校验、权限初始化 | 说明漏洞前提:必须已登录且携带 CSRF |
| 视图/交互 | admin/template/media/media.tpl + 前端 JS(多处引用 media controller) | 管理后台界面;触发上传/重命名请求 | 用于 Web 复现时定位请求与参数 |
3.2 锁定关键路径:从“媒体重命名”一路追到文件系统 rename()
漏洞描述中提到“媒体管理功能”,而Vvveb的后台模块通常是 admin[自定义]/index.php?module=... 的路由。先确认媒体模块的入口是否把upload/rename作为可调用action暴露出来。
技巧:
• 直接在代码里搜索 module=media/media,可以看到多处控制器引用;
• 最核心的是 admin/controller/media/media.php ,里面会构造 $controllerPath。
查到一个媒体模块控制器并不直接处理重命名,但它做了一件关键事:调用``setMediaEndpoints(),把 upload/rename 等 endpoint 拼成 URL暴露给前端。
// admin/controller/media/media.phpuseVvveb\System\Traits\Media asMediaTrait;// ...function index(){ $adminPath = \Vvveb\adminPath(); $controllerPath = $adminPath .'index.php?module=media/media'; $this->setMediaEndpoints($controllerPath);
$this->view->mediaContentUrl ="$controllerPath&action=mediaContent";}// ...
- 入口可以明确了:所有重命名都落到同一个动作
action=rename,而动作实现就在同一个trait里的rename()函数(问了下AI命名逻辑)。 - 控制器类
Media明确use MediaTrait;真正的action实现并不在控制器文件里,而在trait中 - 接下来要找的就是:它是否真的在执行前阻断了危险扩展名。
#
3.3-边界缺失:好消息~有拦截 坏消息!没拦住
顺着setMediaEndpoints()往下看,找下endpoint ,检查是否存在upload()与 rename()
// system/traits/media.phpprotected function setMediaEndpoints($controllerPath) { $this->view->uploadUrl = "$controllerPath&action=upload"; $this->view->renameUrl = "$controllerPath&action=rename"; //xxxx}
- 先注意到一个deny列表,说明代码是做限制了:
// system/traits/media.phppublic $uploadDenyExtensions = ['php', 'svg', 'js', 'exe'];
- 然后再看主角
rename(),关键片段如下:
// system/traits/media.phpfunction rename() { $file = sanitizeFileName($this->request->post['file']); $newname = sanitizeFileName($this->request->post['newname'] ?? ''); // ... $currentFile = $dirMedia . DS . $file; if ($newname) { $targetFile = dirname($currentFile) . DS . $newname; }
$extension = strtolower(substr($targetFile, strrpos($targetFile, '.') + 1));
if (isset($this->uploadDenyExtensions) && in_array($extension, $this->uploadDenyExtensions)) { $message .= __('File type not allowed!'); $success = false; }
// 关键:即便命中 deny,这里也没有 return / die / output if (rename($currentFile, $targetFile)) { $message = ['success' => true, 'message' => __('File renamed!')]; } else { $message = ['success' => false, 'message' => __('Error renaming file!')]; }
$this->response->output($message);}
- 预期设计:命中deny列表(例如目标扩展名是
php)时,应当 立即中断,并返回失败响应(比如403/400或success=false)。 - 实际实现:命中deny后只是给
$success=false,但没有任何 控制流中断,随后无条件进入rename($currentFile, $targetFile)。 - 结果:扩展名拦截从安全策略变成提示,只要底层文件系统允许重命名,后台就会给出 重命名成功的JSON。
- 更绝的是:
rename()函数中$message/$success甚至没有初始化(相比upload()有明确初始化),这意味着“以为自己在维护一个success/message 状态机”,但真正返回给客户端的,最终会被rename()的结果覆盖
重命名PHP后缀时,提示失败,但已完成(不过按理说可以直接执行PHP了,但是我一直403…人麻木了)
3.4-推导最大危害:从“可写文件”升级到“可执行代码”
目前来看,重命名绕过.php的理论已经成立,然后就再往下翻翻如何RCE
第一段:上传阶段的安全边界确实存在
//system/traits/media.phpif (isset($this->uploadDenyExtensions) && in_array($extension, $this->uploadDenyExtensions)) { $message .= __('File type not allowed!'); $success = false;}
......
if (isset($this->uploadDenyMime) && in_array($mimeType, $this->uploadDenyMime)) {
$message .= __('File type not allowed!');
$success = false;
}......
if ($success) { if ($overwrite) { $destination = $this->dirMedia . $path . DS . $fileName; } else { while (file_exists($destination = $this->dirMedia . $path . DS . $fileName) && ($i++ < 5)) { $fileName = rand(0, 10000) . '-' . $origFilename; } }
if (@move_uploaded_file($files['tmp_name'][$count], $destination)) { if (isset($this->request->post['onlyFilename'])) { $return = $fileName; } else { $return = $destination; } $message = __('File uploaded successfully!'); } else { $destination = $this->dirMedia . $path . DS; $success = false;
if (! is_writable($destination)) { $message = sprintf(__('%s not writable!'), $destination); } else { $message = __('Error moving uploaded file!'); } }}
upload()会检查扩展名与 MIME:所以攻击者不能直接上传.php。
第二段:重命名阶段把上传边界“拆掉” 一旦攻击者能把已上传文件重命名,媒体目录就可能出现可执行脚本。
但还差一个现实条件:服务器是否会把该目录下的.php执行?
1、在很多很多部署里,/media/ 本就位于 Web 根目录,且 PHP 解析默认对 .php 生效;这时 仅凭重命名 即可 RCE。•
2、如果运维曾做过限制,攻击者仍可通过写入 .htaccess
这里还有一个关键事实:Vvveb的deny列表里 没有htaccess。这意味着:
1、上传 a.txt(内容为 Apache 指令)是允许的;2、重命名为 .htaccess 也很可能允许; 最终媒体目录的行为被攻击者“重配置”,从纯静态资源目录变成可执行载荷的容器。
3.5 链路总结(调用链 + 注入点/爆发点标注)
完整链路(以后台媒体模块为入口):
/xxx/index.php?module=media/media-> xxx/controller/media/media.php::index() -> system/traits/media.php::setMediaEndpoints()`(暴露 `action=upload` / `action=rename`) -> [注入点] `system/traits/media.php::upload()`(允许上传文本载荷为 `.txt`) -> [逻辑缺陷] `system/traits/media.php::rename()`(deny 命中不 return,仍执行 `rename()`) -> [爆发点] Web 访问 `public/media/<payload>.php`(或受 `.htaccess` 影响的扩展)触发解释执行 -> RCE:以 Web 进程用户执行系统命令
#
#
0x4 修复建议
1、升级最新版本:将组件升级安全版本,v1.0.8以上版本
https://github.com/givanz/Vvveb
2、临时防护措施:
- 服务器隔离:禁止public/media/目录下解析PHP,明确禁止.htaccess 生效:对媒体目录AllowOverride None,并阻止上传/写入以点开头的敏感文件名
- 防火墙 / WAF:拦截/审计后台接口,且newname/newfile 以.php、.phtml、.phar、.htaccess、.user.ini结尾
- 拦截上传问:拦截上传内容包含Apache指令关键字:AddType、SetHandler、php_value、php_flag
免责声明:本文仅用于安全研究目的,未经授权不得用于非法渗透测试活动。
/** 狡诈的科目二!!**/
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:404号浪漫 404号浪漫 404号浪漫《Vvveb CMS 任意文件上传导致RCE | CVE-2026-6257原理分析&研究》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。










评论