代码审计 | novel-plus(CNVD-2024-09639)和likeshop(CNNVD-2024-01765)
字数 1626 2025-08-20 18:17:31

Novel-Plus与LikeShop代码审计与漏洞分析教学文档

1. Novel-Plus任意文件上传漏洞(CNVD-2024-09639)

1.1 漏洞描述

Novel-Plus是一个多端(PC、WAP)阅读、功能完善的小说CMS系统。在com.java2nb.common.controller.FileControllerupload()方法中,处理fileName参数时存在任意文件上传漏洞。远程攻击者可以构造特殊请求上传任意文件,并以系统上下文执行任意代码。

1.2 漏洞定位

漏洞位于com.java2nb.common.controller.FileController类的upload()方法:

@ResponseBody
@PostMapping("/upload")
R upload(@RequestParam("file") MultipartFile file, HttpServletRequest request) {
    if ("test".equals(getUsername())) {
        return R.error(1, "演示系统不允许修改,完整体验请部署程序");
    }
    Date date = new Date();
    String year = DateUtils.format(date, DateUtils.YEAR_PATTERN);
    String month = DateUtils.format(date, DateUtils.MONTH_PATTERN);
    String day = DateUtils.format(date, DateUtils.DAY_PATTERN);
    String fileName = file.getOriginalFilename();
    String fileDir = year + "/" + month + "/" + day + "/";
    fileName = FileUtil.renameToUUID(fileName);
    FileDO sysFile = new FileDO(FileType.fileType(fileName), Constant.UPLOAD_FILES_PREFIX + fileDir + fileName, date);
    try {
        FileUtil.uploadFile(file.getBytes(), jnConfig.getUploadPath() + fileDir, fileName);
    } catch (Exception e) {
        return R.error();
    }
    if (sysFileService.save(sysFile) > 0) {
        return R.ok().put("fileName", sysFile.getUrl());
    }
    return R.error();
}

1.3 漏洞分析

  1. 方法接收一个MultipartFile类型的文件参数
  2. 获取原始文件名file.getOriginalFilename()
  3. 使用FileUtil.renameToUUID()重命名文件,但未对文件类型进行任何过滤
  4. 调用FileUtil.uploadFile()方法上传文件

FileUtil.uploadFile()方法实现:

public static void uploadFile(byte[] file, String filePath, String fileName) throws Exception {
    File targetFile = new File(filePath);
    if (!targetFile.exists()) {
        targetFile.mkdirs();
    }
    FileOutputStream out = new FileOutputStream(filePath + fileName);
    out.write(file);
    out.flush();
    out.close();
}

该方法直接将文件内容写入服务器,没有任何安全校验。

1.4 漏洞利用

攻击者可以构造恶意请求上传任意文件(如.jsp.php等),上传后可通过访问上传的文件路径执行任意代码。

1.5 修复建议

  1. 实现文件类型白名单验证
  2. 对上传文件内容进行检查
  3. 限制上传目录的执行权限
  4. 对上传文件进行重命名(已部分实现)

2. LikeShop任意文件上传漏洞(CNNVD-2024-01765)

2.1 漏洞描述

LikeShop存在任意文件上传漏洞,攻击者可以通过构造特殊请求上传恶意文件,导致远程代码执行。

2.2 漏洞定位

漏洞位于/server/application/api/controller/file文件的formImage函数:

public function formImage() {
    $data = FileServer::userFormImage($this->user_id);
    $this->_success($data['msg'], $data['data'], $data['code']);
}

跟进userFormImage函数:

public static function userFormImage($user_id = 0, $save_dir='uploads/user') {
    try {
        $config = [
            'default' => ConfigServer::get('storage', 'default', 'local'),
            'engine' => ConfigServer::get('storage_engine')
        ];
        if (empty($config['engine']['local'])) {
            $config['engine']['local'] = [];
        }
        $StorageDriver = new StorageDriver($config);
        $StorageDriver->setUploadFile('file');
        if (!$StorageDriver->upload($save_dir)) {
            throw new Exception('图片上传失败' . $StorageDriver->getError());
        }
        // 图片上传路径
        $fileName = $StorageDriver->getFileName();
        // 图片信息
        $fileInfo = $StorageDriver->getFileInfo();
        // 记录图片信息
        $data = [
            'user_id' => $user_id ? $user_id : 0,
            'name' => $fileInfo['name'],
            'type' => File::type_image,
            'uri' => $save_dir . '/' . str_replace($save_dir . '/', '', $fileName),
            'create_time' => time(),
        ];
        Db::name('user_file')->insert($data);
        $result['url'] = UrlServer::getFileUrl($data['uri']);
        $result['base_url'] = $data['uri'];
        $result['name'] = $data['name'];
        return self::dataSuccess('上传文件成功', $result);
    } catch (\Exception $e) {
        $message = lang($e->getMessage()) ?? $e->getMessage();
        return self::dataError('上传文件失败:' . $message);
    }
}

2.3 漏洞分析

  1. 使用StorageDriver处理文件上传
  2. 未对上传文件类型进行有效验证
  3. 虽然函数名和变量名暗示只处理图片,但实际未限制文件类型
  4. 攻击者可上传任意文件类型(如PHP文件)

2.4 漏洞利用

构造恶意请求上传PHP文件:

POST /api/file/formimage HTTP/2
Host: x.x.x.x
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2226.0 Safari/537.36
Connection: close
Content-Length: 201
Content-Type: multipart/form-data; boundary=----WebKitFormBoundarygcflwtei
Accept-Encoding: gzip, deflate

------WebKitFormBoundarygcflwtei
Content-Disposition: form-data; name="file";filename="test.php"
Content-Type: application/x-php

This page has a vulnerability!
------WebKitFormBoundarygcflwtei--

2.5 修复建议

  1. 实现文件类型白名单验证(如仅允许.jpg/.png等图片格式)
  2. 对上传文件内容进行检查,确保是有效的图片文件
  3. 限制上传目录的执行权限
  4. 对上传文件进行重命名

3. 代码审计技巧总结

3.1 文件上传漏洞常见审计点

  1. 查找文件上传功能点
  2. 检查是否有文件类型验证
  3. 检查是否有内容验证
  4. 检查上传路径是否可控
  5. 检查上传后的文件处理逻辑

3.2 漏洞修复方案

  1. 白名单验证:只允许特定的安全文件类型
  2. 内容检查:对文件内容进行验证(如图片必须包含有效的图片头)
  3. 重命名:上传文件使用随机名称,避免覆盖和路径猜测
  4. 权限控制:上传目录禁止执行权限
  5. 文件隔离:将上传文件存储在Web根目录之外

3.3 审计工具与方法

  1. 静态分析:通过代码搜索定位关键函数
  2. 动态调试:结合运行时的行为分析
  3. 补丁对比:对比修复前后的代码变化
  4. 框架特性:了解所用框架的安全机制和常见问题

4. 扩展发现

在审计Novel-Plus过程中,还发现了另一个漏洞并获得CVE编号:CVE-2024-33383。这表明深入审计往往能发现多个安全问题。

5. 总结

本教学文档详细分析了Novel-Plus和LikeShop的两个文件上传漏洞,包括漏洞描述、定位、分析和修复方案。通过这两个案例,我们可以学习到:

  1. 文件上传功能必须进行严格的安全控制
  2. 仅靠前端验证是不够的,必须实现服务端验证
  3. 代码审计需要关注数据处理的全流程
  4. 漏洞修复应采取多层次防御措施

代码审计是一个需要耐心和细致的工作,通过不断学习和实践,可以提升发现安全问题的能力。

Novel-Plus与LikeShop代码审计与漏洞分析教学文档 1. Novel-Plus任意文件上传漏洞(CNVD-2024-09639) 1.1 漏洞描述 Novel-Plus是一个多端(PC、WAP)阅读、功能完善的小说CMS系统。在 com.java2nb.common.controller.FileController 的 upload() 方法中,处理 fileName 参数时存在任意文件上传漏洞。远程攻击者可以构造特殊请求上传任意文件,并以系统上下文执行任意代码。 1.2 漏洞定位 漏洞位于 com.java2nb.common.controller.FileController 类的 upload() 方法: 1.3 漏洞分析 方法接收一个 MultipartFile 类型的文件参数 获取原始文件名 file.getOriginalFilename() 使用 FileUtil.renameToUUID() 重命名文件,但未对文件类型进行任何过滤 调用 FileUtil.uploadFile() 方法上传文件 FileUtil.uploadFile() 方法实现: 该方法直接将文件内容写入服务器,没有任何安全校验。 1.4 漏洞利用 攻击者可以构造恶意请求上传任意文件(如 .jsp 、 .php 等),上传后可通过访问上传的文件路径执行任意代码。 1.5 修复建议 实现文件类型白名单验证 对上传文件内容进行检查 限制上传目录的执行权限 对上传文件进行重命名(已部分实现) 2. LikeShop任意文件上传漏洞(CNNVD-2024-01765) 2.1 漏洞描述 LikeShop存在任意文件上传漏洞,攻击者可以通过构造特殊请求上传恶意文件,导致远程代码执行。 2.2 漏洞定位 漏洞位于 /server/application/api/controller/file 文件的 formImage 函数: 跟进 userFormImage 函数: 2.3 漏洞分析 使用 StorageDriver 处理文件上传 未对上传文件类型进行有效验证 虽然函数名和变量名暗示只处理图片,但实际未限制文件类型 攻击者可上传任意文件类型(如PHP文件) 2.4 漏洞利用 构造恶意请求上传PHP文件: 2.5 修复建议 实现文件类型白名单验证(如仅允许.jpg/.png等图片格式) 对上传文件内容进行检查,确保是有效的图片文件 限制上传目录的执行权限 对上传文件进行重命名 3. 代码审计技巧总结 3.1 文件上传漏洞常见审计点 查找文件上传功能点 检查是否有文件类型验证 检查是否有内容验证 检查上传路径是否可控 检查上传后的文件处理逻辑 3.2 漏洞修复方案 白名单验证 :只允许特定的安全文件类型 内容检查 :对文件内容进行验证(如图片必须包含有效的图片头) 重命名 :上传文件使用随机名称,避免覆盖和路径猜测 权限控制 :上传目录禁止执行权限 文件隔离 :将上传文件存储在Web根目录之外 3.3 审计工具与方法 静态分析 :通过代码搜索定位关键函数 动态调试 :结合运行时的行为分析 补丁对比 :对比修复前后的代码变化 框架特性 :了解所用框架的安全机制和常见问题 4. 扩展发现 在审计Novel-Plus过程中,还发现了另一个漏洞并获得CVE编号: CVE-2024-33383 。这表明深入审计往往能发现多个安全问题。 5. 总结 本教学文档详细分析了Novel-Plus和LikeShop的两个文件上传漏洞,包括漏洞描述、定位、分析和修复方案。通过这两个案例,我们可以学习到: 文件上传功能必须进行严格的安全控制 仅靠前端验证是不够的,必须实现服务端验证 代码审计需要关注数据处理的全流程 漏洞修复应采取多层次防御措施 代码审计是一个需要耐心和细致的工作,通过不断学习和实践,可以提升发现安全问题的能力。