Laranode服务器管理面板爆出任意文件写入漏洞(POC已公开)
YGnight
YGnight
night安全
2026年10月11日 10:08
四川
在小说阅读器读本章
去阅读
在公众号小说中沉浸阅读
一、漏洞描述
Laranode 是装在服务器上的虚拟主机管理面板,Laravel 写的,一套面板管着好几个租户的站点和数据库。
面板里带了个文件管理器,租户登录后能在自己的家目录里传文件、改内容。
1.2 及更早版本里,上传接口把文件写到哪个目录,是由请求里的一个字段定的。
这个字段没有被清理。
里面带 ../ 的话,会原样进到最后那次字符串拼接。
于是普通租户账号能把文件落到别的租户家目录下面,连文件内容一起。
编号 CVE-2026-100520,厂商公告 GHSA-34h2-2696-vfvr,归类 CWE-22。
CVSS 3.1 打分 8.8,向量 AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H,三项影响都记 High。
CVSS 4.0 打分 8.7,向量 AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H。
两份都由 VulnCheck 给出。NVD 那条记录状态是 Deferred,没自己评分。
受影响区间从 0 到 1.2,1.2.1 修掉。
触发要一个能登录面板的普通租户账号。管理员权限不需要,用户交互也不需要。
能写成功还靠一层部署状态。安装脚本会把面板进程加进每个租户的组,租户家目录对它是组可读写的。
当时挡在租户与租户之间的,就是应用层那段路径处理。
文件落到别人的站点根目录之后,剩下交给 Web 服务器。请求到那个文件就会被解析运行,进程权限沿用的是那个租户的系统用户。
公开的验证脚本已经放出,一个 poc.py。
时间上,修复代码 2026 年 9 月 21 日合并,CVE 记录同年 9 月 26 日发布,9 月 30 日最后一次更新。
公开情报里没有观测到在野利用记录。EPSS 对这个编号没有返回数据。
| CVE 编号 | CVE-2026-100520 |
| 公告编号 | GHSA-34h2-2696-vfvr |
| 漏洞类型 | 路径穿越转任意文件写入,CWE-22 |
| 影响组件 | Laranode 文件管理器的上传动作 app/Actions/Filemanager/UploadFileAction.php,接口 POST /filemanager/upload-file |
| 受影响版本 | 0 到 1.2,含 1.2 |
| 修复版本 | 1.2.1 |
| 触发前提 | 持有任意一个能登录面板的普通租户账号 |
| 利用条件 | 无需管理员权限,无需用户交互,目标目录对面板进程可写 |
| 危害面 | 跨租户写文件,写进对方站点根目录后可被请求执行,以该租户系统用户身份运行 |
| CVSS | 8.8 CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H,8.7 CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H,均由 VulnCheck 给出 |
| 在野利用 | 公开情报中暂无已观测到的在野利用记录 |
二、漏洞原理
入口挂在 POST /filemanager/upload-file 上,中间件只有 auth 一条。控制器那一层做的是转发,中间没有别的动作。
// routes/web.php v1.2
Route::post('/filemanager/upload-file', [FilemanagerController::class, 'uploadFile'])
->middleware(['auth'])->name('filemanager.uploadFile');
// app/Http/Controllers/FilemanagerController.php v1.2
public function uploadFile(UploadFileAction $uploadFile, Request $r)
{
return $uploadFile->execute($r);
}
处理全落在 execute 里,开头是表单校验。
// app/Actions/Filemanager/UploadFileAction.php v1.2
$r->validate([
'file' => 'required|file',
'chunkIndex' => 'required|integer|min:0',
'totalChunks' => 'required|integer|min:1',
'originalName' => 'required|string|max:255',
'path' => 'required|string',
]);
path 这一项挂了两条规则,required 管有没有送过来,string 管是不是字符串。
字符内容一概不管,斜杠、点、长度都没设限。
校验过了就拼路径。
$file = $r->file('file');
$path = '/home/' . $r->user()->systemUsername . '/' . $r->path;
File::append($path . '/' . $r->originalName, $file->get());
落点由三段字符串拼出来,中间不做任何处理。
第一段是 /home/ 加自己的系统用户名,后两段是这次请求里的 path 和 originalName。
后两段之间没有 basename 比对,没有过滤,拼好的结果也没拿回去跟家目录对一次。
拼好的字符串直接进了 File::append。Laravel 这个门面最后落到 PHP 的 file\_put\_contents,路径里那两个点由内核处理,先退一层,再往下走。
本机用 PHP 7.0.9 复算了这次拼接,下面是从点开始的字符串处理结果。
$path = '/home/' . 'alice' . '/' . '../bob/public\_html';
$dest = $path . '/' . 'pwn\_12345.php';
// 本机实际输出
// $dest /home/alice/../bob/public\_html/pwn\_12345.php
// basename($dest) pwn\_12345.php
// dirname($dest) /home/alice/../bob/public\_html
PHP 这一层一个字符都没动,两个点完整保留。真正的目录回溯发生在打开文件时,由内核按路径规则处理。
应答里的 toDestination 就是拼好的那个字符串,此时里面已经是别人的家目录。
同一条 path 还被送去了另一处。
上传完要给新文件修属主和权限。面板进程改不了属主,这一步调 sudo 跑 laranode-file-permissions.sh。
// app/Actions/Filemanager/UploadFileAction.php v1.2 写入之后紧跟的一步
(new EnsurePermissionsAction)->execute($r->path . '/' . $r->originalName, $r->user()->systemUsername);
// app/Actions/Filemanager/EnsurePermissionsAction.php v1.2
Process::run([
'sudo',
config('laranode.laranode\_bin\_path') . '/laranode-file-permissions.sh',
$path,
$systemUser,
]);
送过去的还是那个带 ../ 的值。越界的就不止写文件这一件事。
那一步脚本是 root 执行的。属主能被改到任意一个写得进去的目标上,权限也一样。
文件写完,后半段就跟文件管理器没关系了。落进 public\_html 的 PHP 文件,被 HTTP 请求到会被 Web 服务器交给 PHP 解析,进程权限沿用那个租户的系统用户。
厂商公告把这里的问题归成两类。另一类是其他操作会跟着符号链接走,编号 CWE-59,1.2.1 一并处理。本篇只跟着上传这一条。
1.2.1 的改法没停在加一层过滤。文件名先被单独约束住了。
// app/Actions/Filemanager/UploadFileAction.php v1.2.1
$originalName = str\_replace('\\', '/', $r->string('originalName')->toString());
if (basename($originalName) !== $originalName || in\_array($originalName, ['.', '..'], true)) {
return response()->json(['error' => 'Invalid upload file name'], 422);
}
反斜杠先换成斜杠,再拿 basename 比一遍。两边不一致说明带了路径成分,直接 422 挡回去。单独的点与两个点也在黑名单里。
相对的那一段也会先过一遍规整,/home 前缀不再由这一步自己拼。
$relativePath = (new WhitespacePathNormalizer)
->normalizePath($r->path . '/' . $originalName);
SafeFileProcess::run(
'append',
$homedir,
[$relativePath, $r->integer('chunkIndex') === 0 ? 'reset' : 'continue'],
$file->get(),
$r->user()->systemUsername,
config('laranode.laranode\_bin\_path'),
);
真正兜住边界的是里面那个辅助脚本,一个 Python 文件 app/Filesystem/safe\_file.py。
def split\_path(path):
if not path or path.startswith('/') or '\x00' in path:
fail('Invalid relative path')
parts = path.split('/')
if any(part in ('', '.', '..') for part in parts):
fail('Invalid relative path')
return parts
def open\_parent(root\_fd, path, create, owner):
parts = split\_path(path)
current = os.dup(root\_fd)
for component in parts[:-1]:
following = os.open(component, os.O\_RDONLY | os.O\_DIRECTORY | os.O\_NOFOLLOW, dir\_fd=current)
...
return current, parts[-1]
它从家目录取一个描述符,往下的每一级目录都用 O\_NOFOLLOW 打开,锚点始终是那个描述符。
绝对路径、空段、单独一个点、两个点,在 split\_path 这一段就结束了。中间某一级被换成符号链接,os.open 会带上 O\_NOFOLLOW 直接报错。
写入也不再对着目标路径直接打开。
handle = os.open(
temporary,
os.O\_WRONLY | os.O\_CREAT | os.O\_EXCL | os.O\_NOFOLLOW,
0o600,
dir\_fd=parent,
)
write\_input(handle, source)
os.fchmod(handle, mode)
os.fchown(handle, uid\_gid[0], uid\_gid[1])
os.fsync(handle)
os.rename(temporary, name, src\_dir\_fd=parent, dst\_dir\_fd=parent)
内容先写在随机名的临时文件上,权限和属主改完,再由 rename 挪过去,整条路径都挂在家目录那个描述符下面。
绕这一圈的用意是没有间隔。先判断路径、再打开文件,两步之间是有时间差的,那段空档里目录树可以被改掉。描述符锚定加逐级不跟链接,是把越界变成做不到,而不是检查出来。
这一版还动了两处跟权限有关的东西。sudo 规则从目录通配改成了脚本白名单,面板自己的目录树不再对管理进程组可写。
三、修复建议
升到 1.2.1。
近期值得重点关注的漏洞预警
【紧急漏洞预警】nacos爆出权限绕过漏洞,可以创建管理员账户,经过分析有点出处(已复现,exp脚本已编写)
【漏洞预警】Atlassian八款产品爆任意文件读取漏洞(附POC)
【漏洞预警】Joomla视频画廊扩展存在SQL注入漏洞(POC已公开)
【漏洞预警】Roundcube网页邮件客户端存在SQL注入漏洞(附POC)
WordPress页面模板存在文件包含漏洞(POC已公开)CVE-2026-87902
WordPress插件Forminator未认证短代码执行漏洞(poc已公开)CVE-2026-92229
WordPress插件Authorizer存在权限提升漏洞(POC已公开)CVE-2026-81294
WordPress插件MStoreAPI存在认证绕过漏洞(POC已公开)CVE-2026-13447
CakePHP爆出SQL注入漏洞(POC已公开)CVE-2026-77635
Node.js模块proxy-addr爆出严重漏洞CVE-2026-90711
Langflow爆出代码执行漏洞CVE-2026-17633 (POC已公开)
Apache CVE-2026-42536,补它只用一行,洞龄十四年
【紧急】搜狗输入法爆出远程代码执行漏洞CVE-2026-51990 ,已被在野利用
【紧急】无需登录就能获取 GitLab 的任意文件数据(附POC)
【紧急】JumpServer堡垒机被公布Access Key泄露漏洞,可以实现提权
Spring Cloud Azure公布严重漏洞 无需任何权限即可取得登录会话
【漏洞POC已公开】Linux RDS 爆出提权漏洞 一块内存放两次,root就到手了
13 行补丁,堵住Linux能拿 root 的内核洞(EXP已公开)
48 字节,换走一台 Windows 的 SYSTEM(CVE-2026-62735漏洞POC已公开)
【漏洞预警】linux删个网桥就能提权root?目前没有补丁(POC已公开)
【漏洞预警】自己注册个号,就能搬空别人的 Magento 订单和支付卡(POC已公开)
【漏洞预警】Next.js 爆出新漏洞,不用登录实现命令执行(POC已公开)
【漏洞补丁绕过预警】Redis CVE-2026-23479变种高危漏洞,EXP已公开
【漏洞补丁绕过】超 30 万 WordPress 站点受影响,Forminator 文件上传漏洞(附POC)
【漏洞预警】Exchange爆出RCE漏洞,利用Exchange 帮另一台 Exchange 开门(POC已公开)
【漏洞预警】不用登录,一个请求就能让 GeoServer 乖乖执行命令(POC已公开)
【漏洞预警】Keycloak不登录就能接管任意账户,双重验证也拦不住
【漏洞预警】 8月WebLogic公布了9个漏洞,有一个需要重点关注
【漏洞预警】近期MongoDB 公布了5个漏洞,最严重的一个可以不认证、远程就能拿下你电脑
【0DAY漏洞】 全球5G手机芯片厂商之一的紫光展锐SOC存在RCE漏洞,影响数十家手机厂商,还未发布补丁
【漏洞告警】安卓 14 到 16 全中招,通讯录 SQL 注入漏洞正在抄家(POC已公开)
【漏洞预警】不用输密码,对方已经接管你的Mac:官方补丁公布macOS存在未鉴权RCE漏洞
【0day漏洞预警】MariaDB 13 爆 9.8 分 RCE 链:最低 USAGE 权限就能远程执行命令
VMware 爆 5 个洞,两个 9.8 不用密码就能打穿 vCente
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。









评论