├── README.md └── smbscanner.ps1 /README.md: -------------------------------------------------------------------------------- 1 | # SmbScanner 2 | A Smb Scanner written in powershell 3 | Extracted from [PingCastle](https://www.pingcastle.com) and adapted to fit in a script. 4 | 5 | Check for SMBv1 and SMBv2 (SMBv3 is a dialect of SMBv2) 6 | 7 | -------------------------------------------------------------------------------- /smbscanner.ps1: -------------------------------------------------------------------------------- 1 | $Source = @" 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Diagnostics; 5 | using System.IO; 6 | using System.Net; 7 | using System.Net.Sockets; 8 | using System.Text; 9 | using System.Runtime.InteropServices; 10 | 11 | namespace PingCastle.Scanners 12 | { 13 | public class SmbScanner 14 | { 15 | [StructLayout(LayoutKind.Explicit)] 16 | struct SMB_Header { 17 | [FieldOffset(0)] 18 | public UInt32 Protocol; 19 | [FieldOffset(4)] 20 | public byte Command; 21 | [FieldOffset(5)] 22 | public int Status; 23 | [FieldOffset(9)] 24 | public byte Flags; 25 | [FieldOffset(10)] 26 | public UInt16 Flags2; 27 | [FieldOffset(12)] 28 | public UInt16 PIDHigh; 29 | [FieldOffset(14)] 30 | public UInt64 SecurityFeatures; 31 | [FieldOffset(22)] 32 | public UInt16 Reserved; 33 | [FieldOffset(24)] 34 | public UInt16 TID; 35 | [FieldOffset(26)] 36 | public UInt16 PIDLow; 37 | [FieldOffset(28)] 38 | public UInt16 UID; 39 | [FieldOffset(30)] 40 | public UInt16 MID; 41 | }; 42 | // https://msdn.microsoft.com/en-us/library/cc246529.aspx 43 | [StructLayout(LayoutKind.Explicit)] 44 | struct SMB2_Header { 45 | [FieldOffset(0)] 46 | public UInt32 ProtocolId; 47 | [FieldOffset(4)] 48 | public UInt16 StructureSize; 49 | [FieldOffset(6)] 50 | public UInt16 CreditCharge; 51 | [FieldOffset(8)] 52 | public UInt32 Status; // to do SMB3 53 | [FieldOffset(12)] 54 | public UInt16 Command; 55 | [FieldOffset(14)] 56 | public UInt16 CreditRequest_Response; 57 | [FieldOffset(16)] 58 | public UInt32 Flags; 59 | [FieldOffset(20)] 60 | public UInt32 NextCommand; 61 | [FieldOffset(24)] 62 | public UInt64 MessageId; 63 | [FieldOffset(32)] 64 | public UInt32 Reserved; 65 | [FieldOffset(36)] 66 | public UInt32 TreeId; 67 | [FieldOffset(40)] 68 | public UInt64 SessionId; 69 | [FieldOffset(48)] 70 | public UInt64 Signature1; 71 | [FieldOffset(56)] 72 | public UInt64 Signature2; 73 | } 74 | 75 | [StructLayout(LayoutKind.Explicit)] 76 | struct SMB2_NegotiateRequest 77 | { 78 | [FieldOffset(0)] 79 | public UInt16 StructureSize; 80 | [FieldOffset(2)] 81 | public UInt16 DialectCount; 82 | [FieldOffset(4)] 83 | public UInt16 SecurityMode; 84 | [FieldOffset(6)] 85 | public UInt16 Reserved; 86 | [FieldOffset(8)] 87 | public UInt32 Capabilities; 88 | [FieldOffset(12)] 89 | public Guid ClientGuid; 90 | [FieldOffset(28)] 91 | public UInt64 ClientStartTime; 92 | [FieldOffset(36)] 93 | public UInt16 DialectToTest; 94 | } 95 | 96 | const int SMB_COM_NEGOTIATE = 0x72; 97 | const int SMB2_NEGOTIATE = 0; 98 | 99 | const int SMB_FLAGS_CASE_INSENSITIVE = 0x08; 100 | const int SMB_FLAGS_CANONICALIZED_PATHS = 0x10; 101 | 102 | const int SMB_FLAGS2_LONG_NAMES = 0x0001; 103 | const int SMB_FLAGS2_EAS = 0x0002; 104 | 105 | const int SMB_FLAGS2_SECURITY_SIGNATURE_REQUIRED = 0x0010 ; 106 | const int SMB_FLAGS2_IS_LONG_NAME = 0x0040; 107 | 108 | const int SMB_FLAGS2_ESS = 0x0800; 109 | 110 | const int SMB_FLAGS2_NT_STATUS = 0x4000; 111 | const int SMB_FLAGS2_UNICODE = 0x8000; 112 | 113 | const int SMB_DB_FORMAT_DIALECT = 0x02; 114 | 115 | static byte[] GenerateSmbHeaderFromCommand(byte command) 116 | { 117 | SMB_Header header = new SMB_Header(); 118 | header.Protocol = 0x424D53FF; 119 | header.Command = command; 120 | header.Status = 0; 121 | header.Flags = SMB_FLAGS_CASE_INSENSITIVE | SMB_FLAGS_CANONICALIZED_PATHS; 122 | header.Flags2 = SMB_FLAGS2_LONG_NAMES | SMB_FLAGS2_EAS | SMB_FLAGS2_SECURITY_SIGNATURE_REQUIRED | SMB_FLAGS2_IS_LONG_NAME | SMB_FLAGS2_ESS | SMB_FLAGS2_NT_STATUS | SMB_FLAGS2_UNICODE; 123 | header.PIDHigh = 0; 124 | header.SecurityFeatures = 0; 125 | header.Reserved = 0; 126 | header.TID = 0xffff; 127 | header.PIDLow = 0xFEFF; 128 | header.UID = 0; 129 | header.MID = 0; 130 | return getBytes(header); 131 | } 132 | 133 | static byte[] GenerateSmb2HeaderFromCommand(byte command) 134 | { 135 | SMB2_Header header = new SMB2_Header(); 136 | header.ProtocolId = 0x424D53FE; 137 | header.Command = command; 138 | header.StructureSize = 64; 139 | header.Command = command; 140 | header.MessageId = 0; 141 | header.Reserved = 0xFEFF; 142 | return getBytes(header); 143 | } 144 | 145 | static byte[] getBytes(object structure) 146 | { 147 | int size = Marshal.SizeOf(structure); 148 | byte[] arr = new byte[size]; 149 | 150 | IntPtr ptr = Marshal.AllocHGlobal(size); 151 | Marshal.StructureToPtr(structure, ptr, true); 152 | Marshal.Copy(ptr, arr, 0, size); 153 | Marshal.FreeHGlobal(ptr); 154 | return arr; 155 | } 156 | 157 | static byte[] getDialect(string dialect) 158 | { 159 | byte[] dialectBytes = Encoding.ASCII.GetBytes(dialect); 160 | byte[] output = new byte[dialectBytes.Length + 2]; 161 | output[0] = 2; 162 | output[output.Length - 1] = 0; 163 | Array.Copy(dialectBytes, 0, output, 1, dialectBytes.Length); 164 | return output; 165 | } 166 | 167 | static byte[] GetNegotiateMessage(byte[] dialect) 168 | { 169 | byte[] output = new byte[dialect.Length + 3]; 170 | output[0] = 0; 171 | output[1] = (byte) dialect.Length; 172 | output[2] = 0; 173 | Array.Copy(dialect, 0, output, 3, dialect.Length); 174 | return output; 175 | } 176 | 177 | // MS-SMB2 2.2.3 SMB2 NEGOTIATE Request 178 | static byte[] GetNegotiateMessageSmbv2(int DialectToTest) 179 | { 180 | SMB2_NegotiateRequest request = new SMB2_NegotiateRequest(); 181 | request.StructureSize = 36; 182 | request.DialectCount = 1; 183 | request.SecurityMode = 1; // signing enabled 184 | request.ClientGuid = Guid.NewGuid(); 185 | request.DialectToTest = (UInt16) DialectToTest; 186 | return getBytes(request); 187 | } 188 | 189 | static byte[] GetNegotiatePacket(byte[] header, byte[] smbPacket) 190 | { 191 | byte[] output = new byte[smbPacket.Length + header.Length + 4]; 192 | output[0] = 0; 193 | output[1] = 0; 194 | output[2] = 0; 195 | output[3] = (byte)(smbPacket.Length + header.Length); 196 | Array.Copy(header, 0, output, 4, header.Length); 197 | Array.Copy(smbPacket, 0, output, 4 + header.Length, smbPacket.Length); 198 | return output; 199 | } 200 | 201 | public static bool DoesServerSupportDialect(string server, string dialect) 202 | { 203 | Trace.WriteLine("Checking " + server + " for SMBV1 dialect " + dialect); 204 | TcpClient client = new TcpClient(); 205 | try 206 | { 207 | client.Connect(server, 445); 208 | } 209 | catch (Exception) 210 | { 211 | throw new Exception("port 445 is closed on " + server); 212 | } 213 | try 214 | { 215 | NetworkStream stream = client.GetStream(); 216 | byte[] header = GenerateSmbHeaderFromCommand(SMB_COM_NEGOTIATE); 217 | byte[] dialectEncoding = getDialect(dialect); 218 | byte[] negotiatemessage = GetNegotiateMessage(dialectEncoding); 219 | byte[] packet = GetNegotiatePacket(header, negotiatemessage); 220 | stream.Write(packet, 0, packet.Length); 221 | stream.Flush(); 222 | byte[] netbios = new byte[4]; 223 | if (stream.Read(netbios, 0, netbios.Length) != netbios.Length) 224 | return false; 225 | byte[] smbHeader = new byte[Marshal.SizeOf(typeof(SMB_Header))]; 226 | if (stream.Read(smbHeader, 0, smbHeader.Length) != smbHeader.Length) 227 | return false; 228 | byte[] negotiateresponse = new byte[3]; 229 | if (stream.Read(negotiateresponse, 0, negotiateresponse.Length) != negotiateresponse.Length) 230 | return false; 231 | if (negotiateresponse[1] == 0 && negotiateresponse[2] == 0) 232 | { 233 | Trace.WriteLine("Checking " + server + " for SMBV1 dialect " + dialect + " = Supported"); 234 | return true; 235 | } 236 | Trace.WriteLine("Checking " + server + " for SMBV1 dialect " + dialect + " = Not supported"); 237 | return false; 238 | } 239 | catch (Exception) 240 | { 241 | throw new ApplicationException("Smb1 is not supported on " + server); 242 | } 243 | } 244 | 245 | public static bool DoesServerSupportDialectWithSmbV2(string server, int dialect) 246 | { 247 | Trace.WriteLine("Checking " + server + " for SMBV2 dialect 0x" + dialect.ToString("X2")); 248 | TcpClient client = new TcpClient(); 249 | try 250 | { 251 | client.Connect(server, 445); 252 | } 253 | catch (Exception) 254 | { 255 | throw new Exception("port 445 is closed on " + server); 256 | } 257 | try 258 | { 259 | NetworkStream stream = client.GetStream(); 260 | byte[] header = GenerateSmb2HeaderFromCommand(SMB2_NEGOTIATE); 261 | byte[] negotiatemessage = GetNegotiateMessageSmbv2(dialect); 262 | byte[] packet = GetNegotiatePacket(header, negotiatemessage); 263 | stream.Write(packet, 0, packet.Length); 264 | stream.Flush(); 265 | byte[] netbios = new byte[4]; 266 | if( stream.Read(netbios, 0, netbios.Length) != netbios.Length) 267 | return false; 268 | byte[] smbHeader = new byte[Marshal.SizeOf(typeof(SMB2_Header))]; 269 | if (stream.Read(smbHeader, 0, smbHeader.Length) != smbHeader.Length) 270 | return false; 271 | if (smbHeader[8] != 0 || smbHeader[9] != 0 || smbHeader[10] != 0 || smbHeader[11] != 0) 272 | { 273 | Trace.WriteLine("Checking " + server + " for SMBV1 dialect 0x" + dialect.ToString("X2") + " = Not supported via error code"); 274 | return false; 275 | } 276 | byte[] negotiateresponse = new byte[6]; 277 | if (stream.Read(negotiateresponse, 0, negotiateresponse.Length) != negotiateresponse.Length) 278 | return false; 279 | int selectedDialect = negotiateresponse[5] * 0x100 + negotiateresponse[4]; 280 | if (selectedDialect == dialect) 281 | { 282 | Trace.WriteLine("Checking " + server + " for SMBV1 dialect 0x" + dialect.ToString("X2") + " = Supported"); 283 | return true; 284 | } 285 | Trace.WriteLine("Checking " + server + " for SMBV1 dialect 0x" + dialect.ToString("X2") + " = Not supported via not returned dialect"); 286 | return false; 287 | } 288 | catch (Exception) 289 | { 290 | throw new ApplicationException("Smb2 is not supported on " + server); 291 | } 292 | } 293 | 294 | public static bool SupportSMB1(string server) 295 | { 296 | try 297 | { 298 | return DoesServerSupportDialect(server, "NT LM 0.12"); 299 | } 300 | catch (Exception) 301 | { 302 | return false; 303 | } 304 | } 305 | 306 | public static bool SupportSMB2(string server) 307 | { 308 | try 309 | { 310 | return (DoesServerSupportDialectWithSmbV2(server, 0x0202) || DoesServerSupportDialectWithSmbV2(server, 0x0210)); 311 | } 312 | catch (Exception) 313 | { 314 | return false; 315 | } 316 | } 317 | 318 | public static bool SupportSMB3(string server) 319 | { 320 | try 321 | { 322 | return (DoesServerSupportDialectWithSmbV2(server, 0x0300) || DoesServerSupportDialectWithSmbV2(server, 0x0302) || DoesServerSupportDialectWithSmbV2(server, 0x0311)); 323 | } 324 | catch (Exception) 325 | { 326 | return false; 327 | } 328 | } 329 | 330 | public static string Name { get { return "smb"; } } 331 | 332 | public static string GetCsvHeader() 333 | { 334 | return "Computer\tSMB Port Open\tSMB1(NT LM 0.12)\tSMB2(0x0202)\tSMB2(0x0210)\tSMB3(0x0300)\tSMB3(0x0302)\tSMB3(0x0311)"; 335 | } 336 | 337 | public static string GetCsvData(string computer) 338 | { 339 | bool isPortOpened = true; 340 | bool SMBv1 = false; 341 | bool SMBv2_0x0202 = false; 342 | bool SMBv2_0x0210 = false; 343 | bool SMBv2_0x0300 = false; 344 | bool SMBv2_0x0302 = false; 345 | bool SMBv2_0x0311 = false; 346 | try 347 | { 348 | try 349 | { 350 | SMBv1 = DoesServerSupportDialect(computer, "NT LM 0.12"); 351 | } 352 | catch (ApplicationException) 353 | { 354 | } 355 | try 356 | { 357 | SMBv2_0x0202 = DoesServerSupportDialectWithSmbV2(computer, 0x0202); 358 | SMBv2_0x0210 = DoesServerSupportDialectWithSmbV2(computer, 0x0210); 359 | SMBv2_0x0300 = DoesServerSupportDialectWithSmbV2(computer, 0x0300); 360 | SMBv2_0x0302 = DoesServerSupportDialectWithSmbV2(computer, 0x0302); 361 | SMBv2_0x0311 = DoesServerSupportDialectWithSmbV2(computer, 0x0311); 362 | } 363 | catch (ApplicationException) 364 | { 365 | } 366 | } 367 | catch (Exception) 368 | { 369 | isPortOpened = false; 370 | } 371 | return computer + "\t" + (isPortOpened ? "Yes" : "No") + "\t" + (SMBv1 ? "Yes" : "No") 372 | + "\t" + (SMBv2_0x0202 ? "Yes" : "No") 373 | + "\t" + (SMBv2_0x0210 ? "Yes" : "No") 374 | + "\t" + (SMBv2_0x0300 ? "Yes" : "No") 375 | + "\t" + (SMBv2_0x0302 ? "Yes" : "No") 376 | + "\t" + (SMBv2_0x0311 ? "Yes" : "No"); 377 | } 378 | 379 | public static void GetCsv(string computer) 380 | { 381 | Console.WriteLine(GetCsvHeader()); 382 | Console.WriteLine(GetCsvData(computer)); 383 | } 384 | } 385 | } 386 | "@ 387 | Add-Type -TypeDefinition $Source 388 | 389 | # Run example: 390 | # [PingCastle.Scanners.SmbScanner]::GetCsv("192.168.0.25") 391 | --------------------------------------------------------------------------------