freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

点我创作

试试在FreeBuf发布您的第一篇文章 让安全圈留下您的足迹
我知道了

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

代码审计 | novel-plus(CNVD-2024-09639)和likeshop(CNNVD-2024-01765)
Juvline 2024-11-28 14:38:33 12243
所属地 浙江省

想练习一下自己关于代码审计的能力,感觉最主要的就是多学习,多看代码,就准备找找最近的cve根据补丁来进行复现。

novel-plus

github地址:

https://github.com/201206030/novel-plus

cnvd地址

https://www.cnvd.org.cn/flaw/show/CNVD-2024-09639

漏洞描述

Novel-Plus是一个多端(PC、WAP)阅读 、功能完善的小说CMS系统。 Novel-Plus com.java2nb.common.controller.FileController: upload()处理fieName参数存在任意文件上传漏洞,远程攻击者可以利用该漏洞提交特殊的请求,可上传任意文件,以系统上下文执行任意代码

将环境进行搭建好之后,我们进入到了后台,这里还出现一个小问题,就是我并没有找到admin用户的密码是多少,然后根据login controllershiro定位到密码加密的函数,这里再记录一下关于shiro加密的流程

image-20240422192048036

回到代码本身,定位到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();
    }

创建新的文件夹之后创建新的文件dao,然后调用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();
	}

整个代码中没有任何过滤,就是一处无任何过滤可以上传任意后缀的代码

在网页中

image-20240422192919618

本机根目录下面的文件夹也出现了

image-20240422192952340

文件的路径也在网页中有所显示

image-20240422193023758

但是项目是一个前后端分离的项目,我不知道如何才能进行进一步的利用

likeshop

cve-2024-0352``cnnvd-202401-765

网上有现成的复现文章https://www.freebuf.com/articles/web/389841.html

POST /api/file/formimage HTTP/2
Host: 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--

具体对应到的则是/server/application/api/controller/file文件下面的formImage函数

<?php

namespace app\api\controller;


use app\common\server\FileServer;

class File extends ApiBase
{
    public $like_not_need_login = ['formImage','test'];
    /**
     * showdoc
     * @catalog 接口/上传文件
     * @title form表单方式上传图片
     * @description 图片上传
     * @method post
     * @url /file/formimage
     * @return param name string 图片名称
     * @return param url string 文件地址
     * @remark
     * @number 1
     * @return {"code":1,"msg":"上传文件成功","data":{"url":"http:\/\/likeb2b2c.yixiangonline.com\/uploads\/images\/user\/20200810\/3cb866f6bb30b7239d91582f7d9822d6.png","name":"2.png"},"show":0,"time":"0.283254","debug":{"request":{"get":[],"post":[],"header":{"content-length":"103132","content-type":"multipart\/form-data; boundary=--------------------------206668736604428806173438","connection":"keep-alive","accept-encoding":"gzip, deflate, br","host":"www.likeb2b2c.com:20002","postman-token":"1f8aa4dd-f53c-4d12-98b4-8d901ac847db","cache-control":"no-cache","accept":"*\/*","user-agent":"PostmanRuntime\/7.26.2"}}}}
     */
    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("\\","/", $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);
        }
    }

在获取配置后就调用$StorageDriver来进行完成文件上传,由于没有其它过滤的存在,是存在文件上传的漏洞且可以被利用、

他的修复方式是

image-20240426225546463

添加了一个验证文件是否是指定的图片,然后在文件上传的地方进行验证

image-20240426230302281

这种白名单修复文件上传的方法只是一种,我觉得还可以加上进行过滤文件内容,可以进行过滤<由此就可以很大概率的禁止php代码的执行

其它

代码中的漏洞防不胜防,修复和对抗的过程令人着迷

在审计novel-plus的时候,运气好发现另一个函数也具有漏洞,获得了自己的第一个cve

CVE-2024-33383,也算的是一个别的收获了

# 漏洞复现
免责声明
1.一般免责声明:本文所提供的技术信息仅供参考,不构成任何专业建议。读者应根据自身情况谨慎使用且应遵守《中华人民共和国网络安全法》,作者及发布平台不对因使用本文信息而导致的任何直接或间接责任或损失负责。
2. 适用性声明:文中技术内容可能不适用于所有情况或系统,在实际应用前请充分测试和评估。若因使用不当造成的任何问题,相关方不承担责任。
3. 更新声明:技术发展迅速,文章内容可能存在滞后性。读者需自行判断信息的时效性,因依据过时内容产生的后果,作者及发布平台不承担责任。
本文为 Juvline 独立观点,未经授权禁止转载。
如需授权、对文章有疑问或需删除稿件,请联系 FreeBuf 客服小蜜蜂(微信:freebee1024)
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
Juvline LV.2
这家伙太懒了,还未填写个人描述!
  • 2 文章数
  • 0 关注者
flask新版内存马源码学习
2024-11-28