1. 前言
漏洞描述 :
此不当授权漏洞允许未经身份验证的攻击者重置 Confluence 并创建 Confluence 实例管理员帐户。使用此帐户,攻击者可以执行 Confluence 实例管理员可用的所有管理操作,从而导致机密性、完整性和可用性完全丧失。
简单理解就是 CVE-2023-22515 可以新建管理员账号,CVE-2023-22518 可以通过备份文件来覆盖原本的 Confluence 服务,从而使用备份文件中的账号管理服务。
影响版本**:**
修复版本8.3.4、8.4.4、8.5.3、8.6.1之前的版本均受影响。
2. 环境搭建
官网下载 8.5.2 版本:
https://www.atlassian.com/software/confluence/download-archives
具体安装步骤参考 CVE-2023-22515,之前搭了 8.5.1 环境,直接在上面更新。
再贴两个参考链接:
https://andblog.cn/2655
https://l4yn3.github.io/2019/04/20/Confluence-漏洞分析环境搭建/
3. 漏洞复现
在登录状态下,访问/admin/backup.action,导出备份文件,此时 admin 账号的登录密码为confluence.;
然后修改密码为password,以便跟恢复备份后做对比;
退出登录,用 POST 请求/json/setup-restore.action,则能进入恢复备份文件页面;
选择上面生成的备份文件进行导入,抓包把synchronous改为 true,表示同步执行任务;
上传成功;
返回登录界面,用备份文件中的密码进行登录,能够登录进去,说明备份文件覆盖成功。
synchronous不改为 true 的话,就会返回一个 taskId,这个时候虽然返回完成,但还没有覆盖;
然后再访问/longrunningtaskxml.action?taskId=xxx才能覆盖完成。
4. 漏洞分析
diff 一下 8.5.2 和 8.5.3 版本的 jar 包,新增了两个注解@AdminOnly和@SystemAdminOnly,都是用于校验权限的注解,并且为大部分 action 都添加了@WebSudoRequired注解。
4-1. 权限校验1
在 Confluence 服务中,WebSudo 是一种安全机制,用于验证用户的身份执行敏感操作。他表示用户在执行这些操作时需要通过 Web 界面重新验证身份,也就是进行二次验证,以确保用户具有足够的权限来执行这些敏感任务。
在 WebSudoInterceptor 中,获取了 URI、访问的 action 的类以及方法等,调用了matches()方法,如果 matches 方法返回为 true,则进入 else 分支,进行二次登录验证;
进入到DefaultWebSudoManager.matches(),判断了 URI 是否为/admin/开头,是则继续判断访问的 action 的类、方法、包是否添加了@WebSudoNotRequired注解,只要有一个添加了@WebSudoNotRequired注解,就说明当前访问的资源不需要进行二次校验;
URI 不为/admin/开头,则判断访问的 action 的类、方法、包是否添加了@WebSudoRequired注解,只要有一个添加了@WebSudoRequired注解,就说明访问的资源需要进行二次校验;
这样的逻辑就存在缺陷,如果以非/admin/开头去访问实际需要 admin 权限、但又没有添加@WebSudoRequired注解的 action,就可以成功绕过matches()的校验。
根据官方公告里提到的三条利用路径分析,这三个 action 都属于setup包,应该通过/setup/xxx.action访问才对;
`/json/setup-restore.action` `/json/setup-restore-local.action` `/json/setup-restore-progress.action`
请求/setup/setup-restore.action会显示已经完成安装了;
但是struts.xml中使用了 package 继承,json继承于admin继承于setup,也就是说通过/json/和/admin/也可以访问/setup/下的 action;
在未登录状态下请求/admin/setup-restore.action会跳转到登录页面,在登录状态下请求会进行二次登录校验;
而在未登录状态下请求/json/setup-restore.action则能成功访问,SetupRestoreAction 只能通过 POST 请求;
可以看到,/json/setup-restore.action不仅访问到了/setup/下的 action,还绕过了DefaultWebSudoManager.matches()的二次校验。
所以在修复版本当中,就为大多数 action 都添加了@WebSudoRequired,无差别进行二次校验。
4-2. 权限校验2
还有一个权限校验的点在 PermissionCheckInterceptor,其中调用了ConfluenceActionSupport.isPermitted(),如果返回为 true,则表示允许访问;
ConfluenceActionSupport.isPermitted()中,先判断了服务是否已经安装完成,这是肯定的,看 else 分支;
如果 skipAccessCheck 为 true,则略过 if 分支,后面就是返回 true;
不过 skipAccessCheck 默认值为 false,所以调用ConfluenceActionSupport.isPermitted()方法的都会报“没有权限”。
但是重写了isPermitted()方法的、使其返回 true 的 action,就不受限制,例如 SetupRestoreAction 中重写了isPermitted()直接返回 true。
还有就是 ConfluenceActionSupport 中存在setSkipAccessCheck()方法,可以通过修改 skipAccessCheck 为 true 来绕过;
例如,admin 包下的viewlanguage.action,使用了PermissionCheckInterceptor 拦截器,ConfigureLanguageAction 中没有重写isPermitted()方法;
未登录状态下,直接访问/json/viewlanguage.action会跳转到登录页面,添加?skipAccessCheck=true则能成功访问。
所以两种情况能绕过 PermissionCheckInterceptor 校验:
重写isPermitted()方法,使其返回为 true;
不重写isPermitted()方法,修改 skipAccessCheck 为true。
4-3. 备份文件
下载坑点(错误操作):
在“备份与恢复”页面创建并下载备份文件,选择备份站点,返回类型也为SITE;
然后修改用户密码,退出登录,POST 请求/json/setup-restore.action进行上传,却报错说我们试图在还原一个空间备份,但是我们明明就备份的是站点。
看看代码,英文版报错内容在SetupRestoreAction.validate()中出现,进入条件是exportScope类型不为ALL,而我们的备份文件中是jobScope且值为SITE,不在一个频道,自然会报错。
所以应该找一个exportScope为ALL的备份点。
下载正确操作:
从/admin/backup.action导出备份文件;
在BackupAction.execute()中,调用的runLegacyVersion()把exportScope设为了 ALL,所以能避开上面的报错。
再进行上传,把synchronous改为 true,直接同步完成覆盖,如果不改为 true,虽然返回显示成功,但是并不能使用备份中的密码去登录。
在SetupRestoreAction.execute()中调用了父类的execute(),到 AbstractImportAction 中,isImportAllowed()恒返回 true,调用doRestore();
在doRestore()中判断了synchronous的值,如果为 true 则直接执行当前任务,进行备份覆盖。
synchronous默认为 false,不修改则返回一个 taskId;
还需要通过/longrunningtaskxml.action?taskId=去执行这个任务,调用this.executorService.submit()提交并执行。
参考链接:
https://xz.aliyun.com/t/12961
https://xz.aliyun.com/t/12981
5pringKi11:CVE-2023-22518 Critical Privilege Escalation Vulnerability in Atlassian's Confluence.pdf