├── README.md └── bluekeep.ps1 /README.md: -------------------------------------------------------------------------------- 1 | # BlueKeep Scanner 2 | Check if the BlueKeep vulnerability is present with powershell/c# 3 | 4 | This scanner is inspired from existing scanner (such as metasploit and https://github.com/Cyb0r9/ispy) 5 | 6 | 7 | -------------------------------------------------------------------------------- /bluekeep.ps1: -------------------------------------------------------------------------------- 1 | 2 | $source = @" 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Diagnostics; 6 | using System.IO; 7 | using System.Net; 8 | using System.Net.Sockets; 9 | using System.Security.Cryptography; 10 | using System.Text; 11 | 12 | namespace PingCastle 13 | { 14 | public class bluekeeptest 15 | { 16 | 17 | static public bool ScanForBlueKeep(string computer) 18 | { 19 | Trace.WriteLine("Checking " + computer + " for bluekeep"); 20 | TcpClient client = new TcpClient(); 21 | try 22 | { 23 | client.Connect(computer, 3389); 24 | 25 | 26 | } 27 | catch (Exception) 28 | { 29 | throw new Exception("RDP port closed " + computer); 30 | } 31 | try 32 | { 33 | NetworkStream stream = client.GetStream(); 34 | 35 | // https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/18a27ef9-6f9a-4501-b000-94b1fe3c2c10 36 | Console.WriteLine("-> Client X.224 Connection Request PDU"); 37 | SendPacket(x224ConnectionRequest("elton"), stream); 38 | 39 | // https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/13757f8f-66db-4273-9d2c-385c33b1e483 40 | byte[] inbuffer = ReadTPKT(stream); 41 | Console.WriteLine("<- Server X.224 Connection Confirm PDU"); 42 | 43 | // https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/db6713ee-1c0e-4064-a3b3-0fac30b4037b 44 | Console.WriteLine("-> Client MCS Connect Initial PDU with GCC Conference Create Request"); 45 | SendPacket(ConnectInitial("eltons-dev"), stream); 46 | 47 | // https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/927de44c-7fe8-4206-a14f-e5517dc24b1c 48 | inbuffer = ReadTPKT(stream); 49 | Console.WriteLine("<- Server MCS Connect Response PDU with GCC Conference Create Response"); 50 | 51 | byte[] rsmod; 52 | byte[] rsexp; 53 | byte[] server_random; 54 | int bitlen; 55 | ParseServerData(inbuffer, out rsmod, out rsexp, out server_random, out bitlen); 56 | 57 | // https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/04c60697-0d9a-4afd-a0cd-2cc133151a9c 58 | Console.WriteLine("-> Client MCS Erect Domain Request PDU"); 59 | SendPacket(new byte[] { 0x02, 0xf0, 0x80, 0x04, 0x00, 0x01, 0x00, 0x01 }, stream); 60 | 61 | // https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/f5d6a541-9b36-4100-b78f-18710f39f247 62 | Console.WriteLine("-> Client MCS Attach User Request PDU"); 63 | SendPacket(new byte[] { 0x02, 0xf0, 0x80, 0x28 }, stream); 64 | 65 | // https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/3b3d850b-99b1-4a9a-852b-1eb2da5024e5 66 | inbuffer = ReadTPKT(stream); 67 | Console.WriteLine("<- Server MCS Attach User Confirm PDU (len=" + inbuffer.Length + ")"); 68 | 69 | int user1= inbuffer[5] + inbuffer[6]; 70 | 71 | // https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/64564639-3b2d-4d2c-ae77-1105b4cc011b 72 | byte[] pdu_channel_request = new byte[] {0x02,0xf0,0x80,0x38, 0, 0, 3, 0}; 73 | pdu_channel_request[pdu_channel_request.Length - 3] = (byte)user1; 74 | 75 | Console.WriteLine("-> Client MCS Channel Join Request PDU"); 76 | pdu_channel_request[pdu_channel_request.Length - 1] = (byte)0xF1; 77 | SendPacket(pdu_channel_request, stream); 78 | 79 | inbuffer = ReadTPKT(stream); 80 | Console.WriteLine("<- Server MCS Channel Join Confirm PDU Received (len=" + inbuffer.Length + ")"); 81 | 82 | Console.WriteLine("-> Client MCS Channel Join Request PDU"); 83 | pdu_channel_request[pdu_channel_request.Length - 1] = (byte)0xEB; 84 | SendPacket(pdu_channel_request, stream); 85 | 86 | inbuffer = ReadTPKT(stream); 87 | Console.WriteLine("<- Server MCS Channel Join Confirm PDU Received (len=" + inbuffer.Length + ")"); 88 | 89 | Console.WriteLine("-> Client MCS Channel Join Request PDU"); 90 | pdu_channel_request[pdu_channel_request.Length - 1] = (byte)0xEC; 91 | SendPacket(pdu_channel_request, stream); 92 | 93 | inbuffer = ReadTPKT(stream); 94 | Console.WriteLine("<- Server MCS Channel Join Confirm PDU Received (len=" + inbuffer.Length + ")"); 95 | 96 | Console.WriteLine("-> Client MCS Channel Join Request PDU"); 97 | pdu_channel_request[pdu_channel_request.Length - 1] = (byte)0xED; 98 | SendPacket(pdu_channel_request, stream); 99 | 100 | inbuffer = ReadTPKT(stream); 101 | Console.WriteLine("<- Server MCS Channel Join Confirm PDU Received (len=" + inbuffer.Length + ")"); 102 | 103 | Console.WriteLine("-> Client MCS Channel Join Request PDU"); 104 | pdu_channel_request[pdu_channel_request.Length - 1] = (byte)0xEF; 105 | SendPacket(pdu_channel_request, stream); 106 | 107 | inbuffer = ReadTPKT(stream); 108 | Console.WriteLine("<- Server MCS Channel Join Confirm PDU Received (len=" + inbuffer.Length + ")"); 109 | 110 | Console.WriteLine("-> Client MCS Channel Join Request PDU"); 111 | pdu_channel_request[pdu_channel_request.Length - 1] = (byte)0xF0; 112 | SendPacket(pdu_channel_request, stream); 113 | 114 | inbuffer = ReadTPKT(stream); 115 | Console.WriteLine("<- Server MCS Channel Join Confirm PDU Received (len=" + inbuffer.Length + ")"); 116 | 117 | // https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/9cde84cd-5055-475a-ac8b-704db419b66f 118 | Console.WriteLine("-> Client Security Exchange PDU"); 119 | 120 | byte[] clientrand = new byte[32] { 121 | 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 122 | 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 123 | 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 124 | 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 125 | }; 126 | 127 | SendPacket(SecuritExchange(clientrand, rsexp, rsmod, bitlen), stream); 128 | 129 | byte[] clientEncryptKey, clientDecryptKey, macKey, sessionKeyBlob; 130 | ComputeRC4Keys(clientrand, server_random, out clientEncryptKey, out clientDecryptKey, out macKey, out sessionKeyBlob); 131 | 132 | RDP_RC4 encrypt = new RDP_RC4(clientEncryptKey); 133 | 134 | // https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/772d618e-b7d6-4cd0-b735-fa08af558f9d 135 | Console.WriteLine("-> Client Info PDU"); 136 | SendPacket(EncryptPkt(ConvertHexStringToByteArray(GetClientInfo()), encrypt, macKey, 0x48), stream); 137 | 138 | // https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/7d941d0d-d482-41c5-b728-538faa3efb31 139 | inbuffer = ReadTPKT(stream); 140 | Console.WriteLine("<- Server License Error PDU - Valid Client (len=" + inbuffer.Length + ")"); 141 | 142 | // https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/a07abad1-38bb-4a1a-96c9-253e3d5440df 143 | inbuffer = ReadTPKT(stream); 144 | Console.WriteLine("<- Demand Active PDU (len=" + inbuffer.Length + ")"); 145 | 146 | // https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/4c3c2710-0bf0-4c54-8e69-aff40ffcde66 147 | Console.WriteLine("-> Client Confirm Active PDU"); 148 | SendPacket(EncryptPkt(ConvertHexStringToByteArray(ConfirmActive()), encrypt, macKey, 0x38), stream); 149 | 150 | // https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/e0027486-f99a-4f0f-991c-eda3963521c2 151 | Console.WriteLine("-> client synchronize PDU"); 152 | SendPacket(EncryptPkt(ConvertHexStringToByteArray("16001700f103ea030100000108001f0000000100ea03"), encrypt, macKey), stream); 153 | 154 | // https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/9d1e1e21-d8b4-4bfd-9caf-4b72ee91a713 155 | Console.WriteLine("-> client control cooperate PDU"); 156 | SendPacket(EncryptPkt(ConvertHexStringToByteArray("1a001700f103ea03010000010c00140000000400000000000000"), encrypt, macKey), stream); 157 | 158 | // https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/4f94e123-970b-4242-8cf6-39820d8e3d35 159 | Console.WriteLine("-> client control request control PDU"); 160 | SendPacket(EncryptPkt(ConvertHexStringToByteArray("1a001700f103ea03010000010c00140000000100000000000000"), encrypt, macKey), stream); 161 | 162 | // https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/2d122191-af10-4e36-a781-381e91c182b7 163 | Console.WriteLine("-> client persistent key list PDU"); 164 | SendPacket(EncryptPkt(ConvertHexStringToByteArray(ClientPersistentKeyList()), encrypt, macKey, 0x38), stream); 165 | 166 | // https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/7067da0d-e318-4464-88e8-b11509cf0bd9 167 | Console.WriteLine("-> client font list PDU"); 168 | SendPacket(EncryptPkt(ConvertHexStringToByteArray("1a001700f103ea03010000010c00270000000000000003003200"), encrypt, macKey), stream); 169 | 170 | // https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/5186005a-36f5-4f5d-8c06-968f28e2d992 171 | inbuffer = ReadTPKT(stream); 172 | Console.WriteLine("<- Server Synchronize PDU (len=" + inbuffer.Length + ")"); 173 | 174 | // https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/43296a04-6324-4cbf-93d1-8e056e969082 175 | inbuffer = ReadTPKT(stream); 176 | Console.WriteLine("<- Server Control PDU - Cooperate (len=" + inbuffer.Length + ")"); 177 | 178 | // https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/ff7bae0e-cd13-4776-83b2-ef1f45e1fc41 179 | inbuffer = ReadTPKT(stream); 180 | Console.WriteLine("<- Server Control PDU - Granted Control (len=" + inbuffer.Length + ")"); 181 | 182 | // https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/7ba6ba81-e4f4-46a7-9062-2d57a821be26 183 | inbuffer = ReadTPKT(stream); 184 | Console.WriteLine("<- Server Font Map PDU (len=" + inbuffer.Length + ")"); 185 | 186 | Console.WriteLine("clear buffer"); 187 | byte[] temp = ReadAllAvailableData(stream); 188 | 189 | byte[] disconnect = new byte[] { 0x03, 0x00, 0x00, 0x09, 0x02, 0xf0, 0x80, 0x21, 0x80 }; 190 | 191 | for (int k = 0; k < 4; k++) 192 | { 193 | SendPacket(EncryptPkt(ConvertHexStringToByteArray("100000000300000000000000020000000000000000000000"), encrypt, macKey, 8, 0x3ed), stream); 194 | 195 | SendPacket(EncryptPkt(ConvertHexStringToByteArray("20000000030000000000000000000000020000000000000000000000000000000000000000000000"), encrypt, macKey, 8, 0x3ed), stream); 196 | inbuffer = ReadAllAvailableData(stream); 197 | if (inbuffer.Length >= disconnect.Length) 198 | { 199 | bool match = true; 200 | for (int j = 0; j < inbuffer.Length; j++) 201 | { 202 | if (inbuffer[inbuffer.Length - disconnect.Length + j] != disconnect[j]) 203 | { 204 | match = false; 205 | break; 206 | } 207 | } 208 | if (match) 209 | { 210 | Console.WriteLine("disconnect found - machine is vulnerable"); 211 | return true; 212 | } 213 | } 214 | } 215 | } 216 | catch (Exception) 217 | { 218 | throw; 219 | } 220 | return false; 221 | } 222 | 223 | // T.123 - 8. Packet header to delimit data units in an octet stream 224 | private static byte[] ReadTPKT(Stream stream) 225 | { 226 | byte[] inbuffer = new byte[65535]; 227 | if (!stream.CanRead) 228 | { 229 | throw new InvalidOperationException("no read"); 230 | } 231 | int bytesRead = stream.Read(inbuffer, 0, 4); 232 | if (bytesRead != 4) 233 | { 234 | throw new InvalidOperationException("incomplete packet"); 235 | } 236 | if (inbuffer[0] != 3) 237 | { 238 | throw new InvalidOperationException("invalid signature"); 239 | } 240 | if (inbuffer[1] != 0) 241 | { 242 | throw new InvalidOperationException("invalid reserved byte"); 243 | } 244 | int lenght = inbuffer[2] * 0x100 + inbuffer[3] - 4; 245 | bytesRead = stream.Read(inbuffer, 0, lenght); 246 | if (bytesRead < lenght) 247 | { 248 | throw new InvalidOperationException("data too short"); 249 | } 250 | byte[] output = new byte[lenght]; 251 | Array.Copy(inbuffer, output, lenght); 252 | return output; 253 | } 254 | 255 | static byte[] ReadAllAvailableData(Stream stream) 256 | { 257 | byte[] inbuffer = new byte[65535]; 258 | if (!stream.CanRead) 259 | { 260 | throw new InvalidOperationException("no read"); 261 | } 262 | int lenght = stream.Read(inbuffer, 0, inbuffer.Length); 263 | byte[] output = new byte[lenght]; 264 | Array.Copy(inbuffer, output, lenght); 265 | return output; 266 | } 267 | 268 | private static void SendPacket(byte[] data, Stream stream) 269 | { 270 | byte[] output = new byte[data.Length + 4]; 271 | output[0] = 3; 272 | output[1] = 0; 273 | output[2] = (byte) ((data.Length + 4) / 0x100); 274 | output[3] = (byte) ((data.Length + 4) % 0x100); 275 | Array.Copy(data, 0, output, 4, data.Length); 276 | stream.Write(output, 0, output.Length); 277 | stream.Flush(); 278 | } 279 | 280 | private static string GetClientInfo() 281 | { 282 | string data = "000000003301000000000a000000000000000000"; 283 | data+="75007300650072003000"; // FIXME: username 284 | data+="000000000000000002001c00"; 285 | data+="3100390032002e003100360038002e0031002e00320030003800"; // FIXME: ip 286 | data+="00003c0043003a005c00570049004e004e0054005c00530079007300740065006d00330032005c006d007300740073006300610078002e0064006c006c000000a40100004700540042002c0020006e006f0072006d0061006c0074006900640000000000000000000000000000000000000000000000000000000000000000000000000000000a00000005000300000000000000000000004700540042002c00200073006f006d006d006100720074006900640000000000000000000000000000000000000000000000000000000000000000000000000000000300000005000200000000000000c4ffffff00000000270000000000"; 287 | return data; 288 | } 289 | 290 | private static string ConfirmActive() 291 | { 292 | string data = "a4011300f103ea030100ea0306008e014d53545343000e00000001001800010003000002000000000d04000000000000000002001c00100001000100010020035802000001000100000001000000030058000000000000000000000000000000000000000000010014000000010047012a000101010100000000010101010001010000000000010101000001010100000000a1060000000000000084030000000000e40400001300280000000003780000007800000050010000000000000000000000000000000000000000000008000a000100140014000a0008000600000007000c00000000000000000005000c00000000000200020009000800000000000f000800010000000d005800010000000904000004000000000000000c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c000800010000000e0008000100000010003400fe000400fe000400fe000800fe000800fe001000fe002000fe004000fe008000fe000001400000080001000102000000"; 293 | return data; 294 | } 295 | 296 | 297 | private static string ClientPersistentKeyList() 298 | { 299 | string data = "49031700f103ea03010000013b031c00000001000000000000000000000000000000aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; 300 | return data; 301 | } 302 | 303 | private static byte[] ConvertHexStringToByteArray(string data) 304 | { 305 | int length = (data.Length) / 2; 306 | byte[] arr1 = new byte[length]; 307 | for (int i = 0; i < length; i++) 308 | arr1[i] = Convert.ToByte(data.Substring(2 * i, 2), 16); 309 | return arr1; 310 | } 311 | 312 | // https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/18a27ef9-6f9a-4501-b000-94b1fe3c2c10 313 | private static byte[] x224ConnectionRequest(string username) 314 | { 315 | MemoryStream ms = new MemoryStream(); 316 | BinaryReader reader = new BinaryReader(ms); 317 | byte[] b = Encoding.UTF8.GetBytes(username); 318 | byte[] part1 = new byte[] { 319 | (byte) (33+b.Length), // X.224: Length indicator 320 | 0xe0, // X.224: Type - TPDU 321 | 0x00,0x00, // X.224: Destination reference 322 | 0x00,0x00, // X.224: Source reference 323 | 0x00, // X.224: Class and options 324 | 0x43,0x6f,0x6f,0x6b,0x69,0x65,0x3a,0x20,0x6d,0x73,0x74,0x73,0x68,0x61,0x73,0x68,0x3d, // "Cookie: mstshash= 325 | }; 326 | byte[] part2 = new byte[] { 327 | 0x0d,0x0a, // Cookie terminator sequence 328 | 0x01, // Type: RDP_NEG_REQ) 329 | 0x00, // RDP_NEG_REQ::flags 330 | 0x08,0x00, // RDP_NEG_REQ::length (8 bytes) 331 | 0x00,0x00,0x00,0x00, // Requested protocols (PROTOCOL_RDP) 332 | }; 333 | 334 | ms.Write(part1, 0, part1.Length); 335 | ms.Write(b, 0, b.Length); 336 | ms.Write(part2, 0, part2.Length); 337 | ms.Seek(0, SeekOrigin.Begin); 338 | byte[] output = reader.ReadBytes((int) reader.BaseStream.Length); 339 | return output; 340 | } 341 | 342 | 343 | // https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/db6713ee-1c0e-4064-a3b3-0fac30b4037b 344 | private static byte[] ConnectInitial(string hostname) 345 | { 346 | MemoryStream ms = new MemoryStream(); 347 | BinaryReader reader = new BinaryReader(ms); 348 | byte[] b = Encoding.Unicode.GetBytes(hostname); 349 | byte[] part1 = new byte[] { 350 | 0x02,0xf0,0x80, // x.224 351 | 0x7f,0x65,0x82,0x01,0xbe, // change here 352 | 0x04,0x01,0x01,0x04, 353 | 0x01,0x01,0x01,0x01,0xff, 354 | 0x30,0x20,0x02,0x02,0x00,0x22,0x02,0x02,0x00,0x02,0x02,0x02,0x00,0x00,0x02,0x02,0x00,0x01,0x02,0x02,0x00,0x00,0x02,0x02,0x00,0x01,0x02,0x02,0xff,0xff,0x02,0x02,0x00,0x02,0x30,0x20, 355 | 0x02,0x02,0x00,0x01,0x02,0x02,0x00,0x01,0x02,0x02,0x00,0x01,0x02,0x02,0x00,0x01,0x02,0x02,0x00,0x00,0x02,0x02,0x00,0x01,0x02,0x02,0x04,0x20,0x02,0x02,0x00,0x02,0x30,0x20,0x02,0x02, 356 | 0xff,0xff,0x02,0x02,0xfc,0x17,0x02,0x02,0xff,0xff,0x02,0x02,0x00,0x01,0x02,0x02,0x00,0x00,0x02,0x02,0x00,0x01,0x02,0x02,0xff,0xff,0x02,0x02,0x00,0x02,0x04,0x82,0x01,0x4b, // chnage here 357 | 0x00,0x05,0x00,0x14,0x7c,0x00,0x01,0x81,0x42, // change here - ConnectPDU 358 | 0x00,0x08,0x00,0x10,0x00,0x01,0xc0,0x00,0x44,0x75,0x63,0x61,0x81,0x34, // chnage here 359 | 0x01,0xc0,0xd8,0x00,0x04,0x00,0x08,0x00,0x20,0x03,0x58,0x02,0x01,0xca,0x03,0xaa,0x09,0x04,0x00,0x00,0x28,0x0a,0x00,0x00 360 | }; 361 | ms.Write(part1, 0, part1.Length); 362 | 363 | ms.Write(b, 0, b.Length); 364 | for (int i = 0; i < 32 - b.Length; i++) 365 | { 366 | ms.WriteByte(0); 367 | } 368 | 369 | byte[] part2 = new byte[] { 370 | 0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0xca,0x01,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x07,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0xc0,0x0c,0x00,0x09,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0xc0,0x0c,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 371 | 0x03,0xc0, 372 | 0x44,0x00, 373 | 0x04,0x00,0x00,0x00, //channel count 374 | 0x63,0x6c,0x69,0x70,0x72,0x64,0x72,0x00,0xc0,0xa0,0x00,0x00, //cliprdr 375 | 0x4d,0x53,0x5f,0x54,0x31,0x32,0x30,0x00,0x00,0x00,0x00,0x00, //MS_T120 376 | 0x72,0x64,0x70,0x73,0x6e,0x64,0x00,0x00,0xc0,0x00,0x00,0x00, //rdpsnd 377 | 0x73,0x6e,0x64,0x64,0x62,0x67,0x00,0x00,0xc0,0x00,0x00,0x00, //snddbg 378 | 0x72,0x64,0x70,0x64,0x72,0x00,0x00,0x00,0x80,0x80,0x00,0x00, //rdpdr 379 | }; 380 | 381 | ms.Write(part2, 0, part2.Length); 382 | ms.Seek(0, SeekOrigin.Begin); 383 | byte[] output = reader.ReadBytes((int) reader.BaseStream.Length); 384 | return output; 385 | } 386 | 387 | // https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/927de44c-7fe8-4206-a14f-e5517dc24b1c 388 | private static void ParseServerData(byte[] inbuffer, out byte[] rsmod, out byte[] rsexp, out byte[] server_random,out int bitlen) 389 | { 390 | int ptr = 0x45; 391 | while (ptr < inbuffer.Length) 392 | { 393 | int headerType = BitConverter.ToInt16(inbuffer, ptr); 394 | int headerSize = BitConverter.ToInt16(inbuffer, ptr +2); 395 | Console.WriteLine("- Header: {0} Len: {1}", headerType, headerSize); 396 | if (headerType == 0xC02) 397 | { 398 | // https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/3e86b68d-3e2e-4433-b486-878875778f4b 399 | Console.WriteLine("- Security Header"); 400 | int magic = BitConverter.ToInt32(inbuffer, ptr + 68); 401 | if (magic == 0x31415352) 402 | { 403 | bitlen = BitConverter.ToInt32(inbuffer, ptr + 72) - 8; 404 | server_random = new byte[32]; 405 | Array.Copy(inbuffer, ptr + 20, server_random, 0, 32); 406 | rsexp = new byte[4]; 407 | Array.Copy(inbuffer, ptr + 84, rsexp, 0, 4); 408 | rsmod = new byte[bitlen]; 409 | Array.Copy(inbuffer, ptr + 88, rsmod, 0, bitlen); 410 | return; 411 | } 412 | } 413 | ptr += headerSize; 414 | } 415 | throw new NotImplementedException(); 416 | } 417 | 418 | static byte[] reserveBytes(byte[] input) 419 | { 420 | byte[] output = new byte[input.Length]; 421 | for (int i = 0; i < input.Length; i++) 422 | { 423 | output[input.Length - 1 - i] = input[i]; 424 | } 425 | return output; 426 | } 427 | 428 | static byte[] SecuritExchange(byte[] rcran, byte[] rsexp, byte[] rsmod, int bitlen) 429 | { 430 | MemoryStream ms = new MemoryStream(); 431 | BinaryReader reader = new BinaryReader(ms); 432 | 433 | RSAParameters rsaparameters = new RSAParameters(); 434 | rsaparameters.Exponent = reserveBytes(rsexp); 435 | rsaparameters.Modulus = reserveBytes(rsmod); 436 | RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(); 437 | rsa.ImportParameters(rsaparameters); 438 | 439 | byte[] encryptedSecret = reserveBytes(rsa.Encrypt(rcran, false)); 440 | 441 | byte[] part2 = new byte[] { 442 | 0x02,0xf0,0x80, // X.224 443 | 0x64, // sendDataRequest 444 | 0x00,0x08, // intiator userId 445 | 0x03,0xeb, //channelId = 1003 446 | 0x70, // dataPriority 447 | }; 448 | ms.Write(part2, 0, part2.Length); 449 | // FIX ME - hardcoded 450 | ms.WriteByte(0x81); 451 | ms.WriteByte(0x10); 452 | //ms.Write(BitConverter.GetBytes((short)(bitlen + 8)), 0, 2); 453 | 454 | // 2.2.1.10.1 Security Exchange PDU Data (TS_SECURITY_PACKET) 455 | // https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/ca73831d-3661-4700-9357-8f247640c02e 456 | byte[] part3 = new byte[] { 457 | 0x01,0x00, 458 | 0x00, 0x00 459 | }; // SEC_EXCHANGE_PKT 460 | ms.Write(part3, 0, part3.Length); 461 | ms.Write(BitConverter.GetBytes((uint)bitlen + 8), 0, 4); // securityPkt length 462 | ms.Write(encryptedSecret, 0, encryptedSecret.Length); // 64 bytes encrypted client random 463 | ms.Write(new byte[8] , 0, 8); //8 bytes rear padding (always present) 464 | 465 | ms.Seek(0, SeekOrigin.Begin); 466 | byte[] output = reader.ReadBytes((int) reader.BaseStream.Length); 467 | return output; 468 | } 469 | 470 | // https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/705f9542-b0e3-48be-b9a5-cf2ee582607f 471 | private static void ComputeRC4Keys(byte[] clientrand, byte[] server_random, out byte[] clientEncryptKey, out byte[] clientDecryptKey, out byte[] macKey, out byte[] sessionKey) 472 | { 473 | // pre master key 474 | byte[] preMasterKey = new byte[48]; 475 | Array.Copy(clientrand, preMasterKey, 24); 476 | Array.Copy(server_random, 0, preMasterKey, 24, 24); 477 | 478 | // master key 479 | byte[] m1 = SaltedHash(preMasterKey, new byte[] { 0x41 }, clientrand, server_random); 480 | byte[] m2 = SaltedHash(preMasterKey, new byte[] { 0x42, 0x42 }, clientrand, server_random); 481 | byte[] m3 = SaltedHash(preMasterKey, new byte[] { 0x43, 0x43, 0x43 }, clientrand, server_random); 482 | 483 | byte[] masterKey = new byte[m1.Length + m2.Length + m3.Length]; 484 | Array.Copy(m1, 0, masterKey, 0, m1.Length); 485 | Array.Copy(m2, 0, masterKey, m1.Length, m2.Length); 486 | Array.Copy(m3, 0, masterKey, m1.Length + m2.Length, m3.Length); 487 | 488 | // session key 489 | byte[] s1 = SaltedHash(masterKey, new byte[] { 0x58 }, clientrand, server_random); 490 | byte[] s2 = SaltedHash(masterKey, new byte[] { 0x59, 0x59 }, clientrand, server_random); 491 | byte[] s3 = SaltedHash(masterKey, new byte[] { 0x5A, 0x5A, 0x5A }, clientrand, server_random); 492 | 493 | sessionKey = new byte[s1.Length + s2.Length + s3.Length]; 494 | Array.Copy(s1, 0, sessionKey, 0, s1.Length); 495 | Array.Copy(s2, 0, sessionKey, s1.Length, s2.Length); 496 | Array.Copy(s3, 0, sessionKey, s1.Length + s2.Length, s3.Length); 497 | 498 | // keys 499 | clientDecryptKey = FinalHash(s2, clientrand, server_random); 500 | clientEncryptKey = FinalHash(s3, clientrand, server_random); 501 | macKey = s1; 502 | } 503 | 504 | // https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/705f9542-b0e3-48be-b9a5-cf2ee582607f 505 | static byte[] SaltedHash(byte[] s, byte[] i, byte[] clientRand, byte[] serverRand) 506 | { 507 | using (SHA1 sha1 = SHA1.Create()) 508 | using (MD5 md5 = MD5.Create()) 509 | { 510 | sha1.TransformBlock(i, 0, i.Length, i, 0); 511 | sha1.TransformBlock(s, 0, s.Length, s, 0); 512 | sha1.TransformBlock(clientRand, 0, clientRand.Length, clientRand, 0); 513 | sha1.TransformFinalBlock(serverRand, 0, serverRand.Length); 514 | md5.TransformBlock(s, 0, s.Length, s, 0); 515 | md5.TransformFinalBlock(sha1.Hash, 0, sha1.Hash.Length); 516 | return md5.Hash; 517 | } 518 | } 519 | 520 | // https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/705f9542-b0e3-48be-b9a5-cf2ee582607f 521 | static byte[] FinalHash(byte[] k, byte[] clientRand, byte[] serverRand) 522 | { 523 | using (MD5 md5 = MD5.Create()) 524 | { 525 | md5.TransformBlock(k, 0, k.Length, k, 0); 526 | md5.TransformBlock(clientRand, 0, clientRand.Length, clientRand, 0); 527 | md5.TransformFinalBlock(serverRand, 0, serverRand.Length); 528 | return md5.Hash; 529 | } 530 | } 531 | 532 | // https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpbcgr/7c61b54e-f6cd-4819-a59a-daf200f6bf94 533 | static byte[] Hmac(byte[] data, byte[] key) 534 | { 535 | byte[] pad1 = new byte[40]; 536 | byte[] pad2 = new byte[48]; 537 | for (int i = 0; i < pad1.Length; i++) pad1[i] = 0x36; 538 | for (int i = 0; i < pad2.Length; i++) pad2[i] = 0x5c; 539 | 540 | using (SHA1 sha1 = SHA1.Create()) 541 | using (MD5 md5 = MD5.Create()) 542 | { 543 | sha1.TransformBlock(key, 0, key.Length, key, 0); 544 | sha1.TransformBlock(pad1, 0, pad1.Length, pad1, 0); 545 | sha1.TransformBlock(BitConverter.GetBytes(data.Length), 0, 4, BitConverter.GetBytes(data.Length), 0); 546 | sha1.TransformFinalBlock(data, 0, data.Length); 547 | 548 | md5.TransformBlock(key, 0, key.Length, key, 0); 549 | md5.TransformBlock(pad2, 0, pad2.Length, pad2, 0); 550 | md5.TransformFinalBlock(sha1.Hash, 0, sha1.Hash.Length); 551 | 552 | byte[] output = new byte[8]; 553 | Array.Copy(md5.Hash, output, output.Length); 554 | return output; 555 | } 556 | } 557 | 558 | public class RDP_RC4 559 | { 560 | byte[] s; 561 | int i = 0; 562 | int j = 0; 563 | 564 | public RDP_RC4(byte[] key) 565 | { 566 | s = EncryptInitalize(key); 567 | } 568 | 569 | private static byte[] EncryptInitalize(byte[] key) 570 | { 571 | byte[] s = new byte[256]; 572 | for (int i = 0; i < 256; i++) 573 | { 574 | s[i] = (byte) i; 575 | } 576 | 577 | for (int i = 0, j = 0; i < 256; i++) 578 | { 579 | j = (j + key[i % key.Length] + s[i]) & 255; 580 | 581 | Swap(s, i, j); 582 | } 583 | 584 | return s; 585 | } 586 | 587 | public byte[] Encrypt(byte[] data) 588 | { 589 | 590 | byte[] output = new byte[data.Length]; 591 | for (int l = 0; l < data.Length; l++) 592 | { 593 | byte b = data[l]; 594 | i = (i + 1) & 255; 595 | j = (j + s[i]) & 255; 596 | 597 | Swap(s, i, j); 598 | 599 | output[l] = (byte)(b ^ s[(s[i] + s[j]) & 255]); 600 | } 601 | return output; 602 | } 603 | 604 | private static void Swap(byte[] s, int i, int j) 605 | { 606 | byte c = s[i]; 607 | 608 | s[i] = s[j]; 609 | s[j] = c; 610 | } 611 | } 612 | 613 | static byte[] EncryptPkt(byte[] data, RDP_RC4 Encrypt, byte[] hmacKey, int flags) 614 | { 615 | return EncryptPkt(data, Encrypt, hmacKey, flags, 0x3eb); 616 | } 617 | 618 | static byte[] EncryptPkt(byte[] data, RDP_RC4 Encrypt, byte[] hmacKey) 619 | { 620 | return EncryptPkt(data, Encrypt, hmacKey, 8, 0x3eb); 621 | } 622 | 623 | static byte[] EncryptPkt(byte[] data, RDP_RC4 Encrypt, byte[] hmacKey, int flags, int channelId) 624 | { 625 | int udl_with_flag = 0x8000 | (data.Length + 12); 626 | 627 | MemoryStream ms = new MemoryStream(); 628 | BinaryReader reader = new BinaryReader(ms); 629 | 630 | byte[] part1 = new byte[] { 631 | 0x02,0xf0, 0x80, // # X.224 632 | 0x64, // sendDataRequest 633 | 0x00, 0x08, // intiator userId .. TODO: for a functional client this isn't static 634 | (byte)(channelId / 0x100), (byte)(channelId % 0x100), // channelId = 1003 635 | 0x70, // dataPriority 636 | }; 637 | ms.Write(part1, 0, part1.Length); 638 | ms.WriteByte((byte) (udl_with_flag / 0x100)); 639 | ms.WriteByte((byte)(udl_with_flag % 0x100)); 640 | ms.Write(BitConverter.GetBytes(flags), 0, 2); 641 | ms.Write(BitConverter.GetBytes(0), 0, 2); 642 | 643 | byte[] hmac = Hmac(data, hmacKey); 644 | ms.Write(hmac, 0, hmac.Length); 645 | 646 | byte[] rc4 = Encrypt.Encrypt(data); 647 | ms.Write(rc4, 0, rc4.Length); 648 | 649 | ms.Seek(0, SeekOrigin.Begin); 650 | 651 | byte[] output = reader.ReadBytes((int)reader.BaseStream.Length); 652 | return output; 653 | } 654 | } 655 | } 656 | "@ 657 | 658 | Add-Type -TypeDefinition $source 659 | 660 | [PingCastle.bluekeeptest]::ScanForBlueKeep("192.168.0.15") 661 | --------------------------------------------------------------------------------