Juvline
- 关注

想练习一下自己关于代码审计的能力,感觉最主要的就是多学习,多看代码,就准备找找最近的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 controller
和shiro
定位到密码加密的函数,这里再记录一下关于shiro
加密的流程
回到代码本身,定位到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();
}
整个代码中没有任何过滤,就是一处无任何过滤可以上传任意后缀的代码
在网页中
本机根目录下面的文件夹也出现了
文件的路径也在网页中有所显示
但是项目是一个前后端分离的项目,我不知道如何才能进行进一步的利用
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
来进行完成文件上传,由于没有其它过滤的存在,是存在文件上传的漏洞且可以被利用、
他的修复方式是
添加了一个验证文件是否是指定的图片,然后在文件上传的地方进行验证
这种白名单修复文件上传的方法只是一种,我觉得还可以加上进行过滤文件内容,可以进行过滤<
由此就可以很大概率的禁止php
代码的执行
其它
代码中的漏洞防不胜防,修复和对抗的过程令人着迷
在审计novel-plus
的时候,运气好发现另一个函数也具有漏洞,获得了自己的第一个cve
CVE-2024-33383
,也算的是一个别的收获了
如需授权、对文章有疑问或需删除稿件,请联系 FreeBuf 客服小蜜蜂(微信:freebee1024)