Metasploit Module: Libuser roothelper Privilege Escalation
Type: exploit
Path: modules/exploits/linux/local/libuser_roothelper_priv_esc.rb
Disclosure date: 2015-07-24
References: EDB-37706, CVE-2015-3245, CVE-2015-3246, BID-76021, BID-76022, URL-https://seclists.org/oss-sec/2015/q3/185, URL-https://access.redhat.com/articles/1537873

Description:
This module attempts to gain root privileges on Red Hat based Linux
          systems, including RHEL, Fedora and CentOS, by exploiting a newline
          injection vulnerability in libuser and userhelper versions prior to
          0.56.13-8 and version 0.60 before 0.60-7.

          This module makes use of the roothelper.c exploit from Qualys to
          insert a new user with UID=0 in /etc/passwd.

          Note, the password for the current user is required by userhelper.

          Note, on some systems, such as Fedora 11, the user entry for the
          current user in /etc/passwd will become corrupted and exploitation
          will fail.

          This module has been tested successfully on libuser packaged versions
          0.56.13-4.el6 on CentOS 6.0 (x86_64);
          0.56.13-5.el6 on CentOS 6.5 (x86_64);
          0.60-5.el7 on CentOS 7.1-1503 (x86_64);
          0.56.16-1.fc13 on Fedora 13 (i686);
          0.59-1.fc19 on Fedora Desktop 19 (x86_64);
          0.60-3.fc20 on Fedora Desktop 20 (x86_64);
          0.60-6.fc21 on Fedora Desktop 21 (x86_64);
          0.60-6.fc22 on Fedora Desktop 22 (x86_64);
          0.56.13-5.el6 on Red Hat 6.6 (x86_64); and
          0.60-5.el7 on Red Hat 7.0 (x86_64).

          RHEL 5 is vulnerable, however the installed version of glibc (2.5)
          is missing various functions required by roothelper.c.

Check method (fingerprinting):
userhelper_path = '/usr/sbin/userhelper'
    return CheckCode::Safe("#{userhelper_path} file not found") unless file? userhelper_path
    return CheckCode::Safe("#{userhelper_path} is not setuid") unless setuid? userhelper_path

    vprint_good "#{userhelper_path} is setuid"

    unless command_exists? 'script'
      vprint_error 'script is not installed. Exploitation will fail.'
      return CheckCode::Safe('script is not installed')
    end
    vprint_good 'script is installed'

    if immutable?('/etc/passwd')
      vprint_error 'File /etc/passwd is immutable'
      return CheckCode::Safe('/etc/passwd is immutable')
    end
    vprint_good 'File /etc/passwd is not immutable'

    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::Detected('Could not determine GNU C Library version')
    end

    # roothelper.c requires functions only available since glibc 2.6+
    if glibc_version < Rex::Version.new('2.6')
      vprint_error "GNU C Library version #{glibc_version} is not supported"
      return CheckCode::Safe("GNU C Library version #{glibc_version} is not supported")
    end
    vprint_good "GNU C Library version #{glibc_version} is supported"

    CheckCode::Detected("GNU C Library version #{glibc_version} detected but exploitability is uncertain")
  end