77using SharpHoundCommonLib . SMB . SMB1 ;
88using SharpHoundCommonLib . SMB . SMB2 ;
99using SharpHoundCommonLib . SMB . NetBIOS ;
10- using System . CodeDom ;
1110using Microsoft . Extensions . Logging ;
12- using SharpHoundRPC ;
1311using SharpHoundRPC . Registry ;
1412using Microsoft . Win32 ;
1513
@@ -45,23 +43,24 @@ public SmbScanner(ILogger log)
4543 /// <summary>
4644 /// Scans SMB on the remote server by sending an SMB negotiate message
4745 /// and analyzing the response. It will attempt to elicit a response using
48- /// an SMB1 message and then SMB2 (if SMB1 fails) .
46+ /// an SMB1 message and then SMB2.
4947 /// </summary>
5048 /// <param name="host">The hostname or IP address to check</param>
5149 /// <param name="port">The port to connect to (default SMB port is 445)</param>
5250 /// <returns>Result object containing SMB signing information</returns>
5351 public async Task < SharpHoundRPC . Result < SmbScanInfo > > ScanHost ( string host , int port = 445 )
5452 {
55-
56- var isLocalMachine = NativeUtils . IsCurrentMachineFqdn ( host ) ;
57- if ( isLocalMachine )
53+ if ( NativeUtils . IsCurrentMachineFqdn ( host ) )
5854 {
5955 // When accessing the SMB directly port from localhost, it'll disconnect.
6056 // Side step that by just collecting the data from the registry.
61- return CheckRegistrySigningRequired ( host ) ;
62- }
63-
57+ _log . LogTrace ( $ "Checking SMB registry on host { host } ") ;
58+ var registryResult = CheckRegistrySigningRequired ( host ) ;
6459
60+ // If registry check succeeds that's all we need, otherwise we'll follow up with SMB Negotiate
61+ if ( registryResult . IsSuccess )
62+ return registryResult ;
63+ }
6564
6665 // Try SMB1 negotiate first as it'll elicit an SMB1 or SMB2 response (if either is enabled)
6766 var smb1result = await TrySMBNegotiate ( host , port , true ) ;
@@ -78,7 +77,7 @@ public SmbScanner(ILogger log)
7877 /// </summary>
7978 private SharpHoundRPC . Result < SmbScanInfo > CheckRegistrySigningRequired ( string host )
8079 {
81- const string keyPath = @"SYSTEM\CurrentControlSet\Services\LanmanServer \Parameters" ;
80+ const string keyPath = @"SYSTEM\CurrentControlSet\Services\LanManServer \Parameters" ;
8281 const string requireValueName = "RequireSecuritySignature" ;
8382 const string enableValueName = "EnableSecuritySignature" ;
8483
@@ -87,23 +86,30 @@ private SharpHoundRPC.Result<SmbScanInfo> CheckRegistrySigningRequired(string ho
8786 var requireRegistryValue = Registry . GetValue ( $@ "HKEY_LOCAL_MACHINE\{ keyPath } ", requireValueName , null ) ;
8887 var enableRegistryValue = Registry . GetValue ( $@ "HKEY_LOCAL_MACHINE\{ keyPath } ", enableValueName , null ) ;
8988
90- bool signingRequired = false ;
91- bool signingEnabled = false ;
89+ bool required = false ;
9290
91+ // RequireSecuritySignature is enough to tell us whether or not signing is required
9392 if ( requireRegistryValue != null )
9493 {
95- signingRequired = Convert . ToInt32 ( requireRegistryValue ) != 0 ;
94+ required = Convert . ToInt32 ( requireRegistryValue ) ! = 0 ;
95+ return SharpHoundRPC . Result < SmbScanInfo > . Ok ( new SmbScanInfo ( host )
96+ {
97+ SigningRequired = required ,
98+ } ) ;
9699 }
97-
98- if ( enableRegistryValue != null )
100+ // But if it doesn't exist, we can know that signing ISN'T required if EnableSecuritySignature is False
101+ else if ( enableRegistryValue != null )
99102 {
100- signingEnabled = Convert . ToInt32 ( enableRegistryValue ) != 0 ;
103+ required = Convert . ToInt32 ( enableRegistryValue ) ! = 0 ;
104+ if ( ! required )
105+ return SharpHoundRPC . Result < SmbScanInfo > . Ok ( new SmbScanInfo ( host )
106+ {
107+ SigningRequired = false ,
108+ } ) ;
101109 }
102110
103- return SharpHoundRPC . Result < SmbScanInfo > . Ok ( new SmbScanInfo ( host )
104- {
105- SigningRequired = signingEnabled && signingRequired
106- } ) ;
111+ // But if EnableSecuritySignature is also missing or is True, we can't conclude anything
112+ return SharpHoundRPC . Result < SmbScanInfo > . Fail ( "Could not acquire enough registries to determine SMB Signing info" ) ;
107113 }
108114 catch ( Exception ex )
109115 {
@@ -256,7 +262,12 @@ internal bool CheckResponseRequiresSigning(byte[] responsePacket, bool parseSMB1
256262
257263 // Validate structure size of negotiate response
258264 var negotiateStructureSize = reader . ReadUInt16 ( ) ;
259-
265+
266+ if ( negotiateStructureSize != SMB2Constants . ExpectedNegotiateStructureSizeA )
267+ {
268+ _log . LogDebug ( $ "Expected fixed-value SMB2 response structure size { SMB2Constants . ExpectedNegotiateStructureSizeA } , got { negotiateStructureSize } . Packet: { Convert . ToBase64String ( responsePacket ) } ") ;
269+ return ( true , false ) ;
270+ }
260271
261272 // Read security mode, which contains signing information
262273 var securityMode = reader . ReadUInt16 ( ) ;
0 commit comments