blossom-editor / blossom

A markdown editor that you can deploy on your own servers to achieve cloud storage and device synchronization(支持私有部署的云端存储双链笔记软件)
https://www.wangyunf.com/blossom-doc/index
MIT License
2.97k stars 231 forks source link

任意文件上传 #122

Closed Guardian-JTZ closed 2 months ago

Guardian-JTZ commented 4 months ago

介绍

blossom 存在任意文件上传漏洞, 同时还可以将文件上传到任意位置, 上传一些特殊的文件来将对应文件覆盖

示例

POST /picture/file/upload HTTP/1.1
Host: 192.168.102.131:9999
Content-Length: 1416
Authorization: Bearer c23e29a1efb94189ada35a496a02b158
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.6167.85 Safari/537.36
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryIqDGz43F5B9QiIHz
Accept: */*
Origin: http://192.168.102.131:9999
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Connection: close

------WebKitFormBoundaryIqDGz43F5B9QiIHz
Content-Disposition: form-data; name="pid"

-1
------WebKitFormBoundaryIqDGz43F5B9QiIHz
Content-Disposition: form-data; name="filename"

Bash.png
------WebKitFormBoundaryIqDGz43F5B9QiIHz
Content-Disposition: form-data; name="repeatUpload"

false
------WebKitFormBoundaryIqDGz43F5B9QiIHz
Content-Disposition: form-data; name="file"; filename="Bash.png"
Content-Type: image/png
....
------WebKitFormBoundaryIqDGz43F5B9QiIHz--

查看后台源码, 可以发现并没有过多的进行限制或过滤操作, 上传的文件名、文件路径全部都可以由客户端进行控制

@Transactional(rollbackFor = Exception.class)
public PictureEntity insert(MultipartFile file, String filename, Long pid, Long userId, Boolean repeatUpload) {
    PictureEntity pic = new PictureEntity();
    pic.setUserId(userId);
    pic.setId(PrimaryKeyUtil.nextId());
    // 文件原名
    pic.setSourceName(file.getOriginalFilename());
    // 文件后缀, 后缀无法修改
    pic.setSuffix(FileUtil.getSuffix(pic.getSourceName()));
    // 文件名以传入文件名为优先
    if (StrUtil.isBlank(filename)) {
        pic.setName(file.getOriginalFilename());
    } else {
        pic.setName(filename);
        if (StrUtil.isBlank(FileUtil.getSuffix(filename))) {
            pic.setName(filename + "." + pic.getSuffix());
        }
    }
    pic.setSize(file.getSize());

    final String domain = paramService.getDomain();
    final String rootPath = osManager.getDefaultPath();
    final String uid = "/U" + userId;
    final String pname = "/" + pic.getName();

    // 上传文件夹为空, 则上传至默认文件夹, 默认文件夹是系统提供的无法删除的文件夹, ID为 userId * -1
    if (pid == null || pid <= 0) {
        pic.setPid(userId * -1);
        pic.setPathName(rootPath + uid + pname);
    } else {
        FolderEntity folder = folderService.selectById(pid);
        XzException400HTTP.throwBy(ObjUtil.isNull(folder), "上传文件夹[" + pid + "]不存在, 请核对后再上传");
        final String storePath = StrUtil.isBlank(folder.getStorePath()) ? "/" : folder.getStorePath();
        pic.setPid(pid);
        pic.setPathName(rootPath + uid + storePath + pname);
    }

    pic.setPathName(pic.getPathName().replaceAll("//", "/"));
    pic.setUrl(domain + pic.getPathName());

    PictureEntity originPic;
    if ((originPic = baseMapper.selectByPathName(pic.getPathName())) != null) {
        // 如果允许重复上传, 则修改大小
        if (repeatUpload) {
            PictureEntity upd = new PictureEntity();
            upd.setId(originPic.getId());
            upd.setSize(pic.getSize());
            upd.setCreTime(new Date());
            baseMapper.updById(upd);
            pic.setId(originPic.getId());
        } else {
            throw new XzException400HTTP("图片[" + pic.getPathName() + "]已存在, 请重命名文件或选择其他路径!");
        }
    } else {
        baseMapper.insert(pic);
    }

    // 入库后进行文件上传操作
    try (InputStream inputStream = file.getInputStream()) {
        osManager.put(pic.getPathName(), inputStream);
    } catch (IOException e) {
        throw new XzException500("图片[" + pic.getPathName() + "]上传异常,请重试");
    }
    return pic;
}

借此可以构造特殊的请求来进行上传, (为了便于演示, 我在这里修改 /etc/passwd 文件) image-20240511193405505 进入系统进行查看, 可以发现产生了对应的文件 image-20240511193356514

如果遭到入侵, 攻击者可能会利用此来修改原始用户的公私钥文件或者其他配置文件造成危害

修复

限制文件上传的路径

github-actions[bot] commented 3 months ago

This issue has been open 30 days with no activity. This will be closed in 7 days.

github-actions[bot] commented 2 months ago

This issue has been automatically marked as stale because it hasn't had any recent activity.