Skip to content

Commit 801f2c5

Browse files
[BED-5934] First pass to provide better SMB Signing query transparency in logging (#206)
* First pass to provide better SMB Signing query behaviors in logging * Small logging info polish for SMB2 StructureSize message * ExpectedNegotiateStructureSize is a hex value * Trying more strategies to get SMB Info * CheckRegistrySigningRequired may make confident conclusions from partial registry collection * Undo try-both changes made to TrySMBNegotiate attempts * SigningRequired implies SigningEnabled * Fix logging statement for Expected Negotiate Structure Size for SMB2 Negotiation response * Making CheckRegistrySigningRequired intent a little clearer
1 parent 367fc76 commit 801f2c5

1 file changed

Lines changed: 32 additions & 21 deletions

File tree

src/CommonLib/SMB/SmbScanner.cs

Lines changed: 32 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,7 @@
77
using SharpHoundCommonLib.SMB.SMB1;
88
using SharpHoundCommonLib.SMB.SMB2;
99
using SharpHoundCommonLib.SMB.NetBIOS;
10-
using System.CodeDom;
1110
using Microsoft.Extensions.Logging;
12-
using SharpHoundRPC;
1311
using SharpHoundRPC.Registry;
1412
using 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

Comments
 (0)