Skip to content

Unrestricted Upload of File with Dangerous Type (CWE-434) /admin/cmsWebFile/doUpload #93

@NinjaGPT

Description

@NinjaGPT

Summary

The admin panel allows users to customize uploaded file types through the endpoint "/admin/sysConfigData/save", including dangerous types such as jsp, jspx, php, html, etc. Yes, server-side scripts typically won't be executed, but browsers will parse and execute client-side code. Therefore, if attackers upload htm, html, or pdf files containing malicious JavaScript code, they will be executed, leading to XSS attacks.

The endpoint /admin/cmsWebFile/doUpload allow user uploads html, htm and PDF file without sanitizer which leads to Stored XSS.

Details

Image
  • publiccms-parent/publiccms-core/src/main/java/com/publiccms/controller/admin/cms/CmsWebFileAdminController.java
@RequestMapping("doUpload")
    @Csrf
    public String upload(@RequestAttribute SysSite site, @SessionAttribute SysUser admin, MultipartFile[] files, String path,
            boolean privatefile, boolean overwrite, boolean unzip, String encoding, boolean here, boolean zipOverwrite,
            HttpServletRequest request, ModelMap model) {
        if (null != files) {
            try {
                for (MultipartFile file : files) {
                    String originalName = file.getOriginalFilename();
                    String suffix = CmsFileUtils.getSuffix(originalName);
                    String filepath = CommonUtils.joinString(path, Constants.SEPARATOR, originalName);
                    String fuleFilePath = siteComponent.getWebFilePath(site.getId(), filepath);
                    if (ArrayUtils.contains(safeConfigComponent.getSafeSuffix(site), suffix)) {
                        if (CommonUtils.notEmpty(suffix) && suffix.equalsIgnoreCase(".zip") && unzip) {
                            try {
                                File dest = File.createTempFile("temp_", suffix);
                                file.transferTo(dest);
                                String targetPath;
                                if (here) {
                                    targetPath = siteComponent.getWebFilePath(site.getId(), path);
                                } else {
                                    targetPath = siteComponent.getWebFilePath(site.getId(),
                                            CommonUtils.joinString(path, Constants.SEPARATOR,
                                                    originalName.substring(0, originalName.lastIndexOf(Constants.DOT))));
                                }
                                ZipUtils.unzip(dest.getAbsolutePath(), targetPath, encoding, zipOverwrite, (f, e) -> {
                                    String historyFilePath = siteComponent.getTemplateHistoryFilePath(site.getId(), e.getName(),
                                            true);
                                    try {
                                        CmsFileUtils.copyInputStreamToFile(f.getInputStream(e), historyFilePath);
                                    } catch (IOException e1) {
                                    }
                                    return true;
                                });
                                Files.delete(dest.toPath());
                            } catch (IOException e) {
                                model.addAttribute(CommonConstants.ERROR, e.getMessage());
                                log.error(e.getMessage(), e);
                            }
                        } else if (overwrite || !CmsFileUtils.exists(fuleFilePath)) {
                            if (CmsFileUtils.exists(fuleFilePath)) {
                                String historyFilePath = siteComponent.getWebHistoryFilePath(site.getId(), filepath, true);
                                try {
                                    CmsFileUtils.copyFileToFile(historyFilePath, historyFilePath);
                                } catch (IOException e1) {
                                }
                            }
                            CmsFileUtils.upload(file, fuleFilePath);
                            if (CmsFileUtils.isSafe(fuleFilePath, suffix)) {
                                FileUploadResult uploadResult = CmsFileUtils.getFileSize(fuleFilePath, originalName, suffix);
                                logUploadService.save(new LogUpload(site.getId(), admin.getId(),
                                        LogLoginService.CHANNEL_WEB_MANAGER, originalName, privatefile,
                                        CmsFileUtils.getFileType(CmsFileUtils.getSuffix(originalName)), file.getSize(),
                                        uploadResult.getWidth(), uploadResult.getHeight(), RequestUtils.getIpAddress(request),
                                        CommonUtils.getDate(), filepath));
                            } else {
                                CmsFileUtils.delete(fuleFilePath);
                                model.addAttribute(CommonConstants.ERROR, "verify.custom.file.unsafe");
                                return CommonConstants.TEMPLATE_ERROR;
                            }
                        }
                    } else {
                        model.addAttribute(CommonConstants.ERROR, "verify.custom.fileType");
                        return CommonConstants.TEMPLATE_ERROR;
                    }
                }
            } catch (IOException e) {
                model.addAttribute(CommonConstants.ERROR, e.getMessage());
                log.error(e.getMessage(), e);
                return CommonConstants.TEMPLATE_ERROR;
            }
        }
        return CommonConstants.TEMPLATE_DONE;

    }

POC

Image Image

Impact

The Stored XSS vulnerability allows attackers launch attacks via arbitrary javascript execution, such as phishing, stealing user's credentials, etc

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions