From 9fe283762a21546be5787735a6fe719fa2e20172 Mon Sep 17 00:00:00 2001 From: Tal Aloni Date: Wed, 26 Jul 2017 19:14:08 +0300 Subject: [PATCH] Bugfix: Last SessionSetupResponse was not signed, final async response was not signed --- .../ConnectionState/SMB2ConnectionState.cs | 4 +-- .../Server/ConnectionState/SMB2Session.cs | 12 +++++++- SMBLibrary/Server/SMB2/ChangeNotifyHelper.cs | 1 + SMBLibrary/Server/SMB2/SessionSetupHelper.cs | 5 ++-- SMBLibrary/Server/SMBServer.SMB2.cs | 28 ++++++++++++------- 5 files changed, 35 insertions(+), 15 deletions(-) diff --git a/SMBLibrary/Server/ConnectionState/SMB2ConnectionState.cs b/SMBLibrary/Server/ConnectionState/SMB2ConnectionState.cs index cc3bfea..4bc03ca 100644 --- a/SMBLibrary/Server/ConnectionState/SMB2ConnectionState.cs +++ b/SMBLibrary/Server/ConnectionState/SMB2ConnectionState.cs @@ -43,9 +43,9 @@ namespace SMBLibrary.Server return null; } - public SMB2Session CreateSession(ulong sessionID, string userName, string machineName, byte[] sessionKey, object accessToken) + public SMB2Session CreateSession(ulong sessionID, string userName, string machineName, byte[] sessionKey, object accessToken, bool signingRequired) { - SMB2Session session = new SMB2Session(this, sessionID, userName, machineName, sessionKey, accessToken); + SMB2Session session = new SMB2Session(this, sessionID, userName, machineName, sessionKey, accessToken, signingRequired); lock (m_sessions) { m_sessions.Add(sessionID, session); diff --git a/SMBLibrary/Server/ConnectionState/SMB2Session.cs b/SMBLibrary/Server/ConnectionState/SMB2Session.cs index 1cee357..81e0412 100644 --- a/SMBLibrary/Server/ConnectionState/SMB2Session.cs +++ b/SMBLibrary/Server/ConnectionState/SMB2Session.cs @@ -19,6 +19,7 @@ namespace SMBLibrary.Server private byte[] m_sessionKey; private SecurityContext m_securityContext; private DateTime m_creationDT; + private bool m_signingRequired; // Key is TreeID private Dictionary m_connectedTrees = new Dictionary(); @@ -31,13 +32,14 @@ namespace SMBLibrary.Server // Key is the volatile portion of the FileID private Dictionary m_openSearches = new Dictionary(); - public SMB2Session(SMB2ConnectionState connection, ulong sessionID, string userName, string machineName, byte[] sessionKey, object accessToken) + public SMB2Session(SMB2ConnectionState connection, ulong sessionID, string userName, string machineName, byte[] sessionKey, object accessToken, bool signingRequired) { m_connection = connection; m_sessionID = sessionID; m_sessionKey = sessionKey; m_securityContext = new SecurityContext(userName, machineName, connection.ClientEndPoint, connection.AuthenticationContext, accessToken); m_creationDT = DateTime.Now; + m_signingRequired = signingRequired; } private uint? AllocateTreeID() @@ -245,5 +247,13 @@ namespace SMBLibrary.Server return m_creationDT; } } + + public bool SigningRequired + { + get + { + return m_signingRequired; + } + } } } diff --git a/SMBLibrary/Server/SMB2/ChangeNotifyHelper.cs b/SMBLibrary/Server/SMB2/ChangeNotifyHelper.cs index 8a63125..83c8d32 100644 --- a/SMBLibrary/Server/SMB2/ChangeNotifyHelper.cs +++ b/SMBLibrary/Server/SMB2/ChangeNotifyHelper.cs @@ -59,6 +59,7 @@ namespace SMBLibrary.Server.SMB2 ChangeNotifyResponse response = new ChangeNotifyResponse(); response.Header.Status = status; response.Header.IsAsync = true; + response.Header.IsSigned = session.SigningRequired; response.Header.AsyncID = asyncContext.AsyncID; response.Header.SessionID = asyncContext.SessionID; response.OutputBuffer = buffer; diff --git a/SMBLibrary/Server/SMB2/SessionSetupHelper.cs b/SMBLibrary/Server/SMB2/SessionSetupHelper.cs index 81f1f99..47d9f33 100644 --- a/SMBLibrary/Server/SMB2/SessionSetupHelper.cs +++ b/SMBLibrary/Server/SMB2/SessionSetupHelper.cs @@ -66,12 +66,13 @@ namespace SMBLibrary.Server.SMB2 if (!isGuest.HasValue || !isGuest.Value) { state.LogToServer(Severity.Information, "Session Setup: User '{0}' authenticated successfully (Domain: '{1}', Workstation: '{2}', OS version: '{3}').", userName, domainName, machineName, osVersion); - state.CreateSession(request.Header.SessionID, userName, machineName, sessionKey, accessToken); + bool signingRequired = (request.SecurityMode == SecurityMode.SigningRequired); + state.CreateSession(request.Header.SessionID, userName, machineName, sessionKey, accessToken, signingRequired); } else { state.LogToServer(Severity.Information, "Session Setup: User '{0}' failed authentication (Domain: '{1}', Workstation: '{2}', OS version: '{3}'), logged in as guest.", userName, domainName, machineName, osVersion); - state.CreateSession(request.Header.SessionID, "Guest", machineName, sessionKey, accessToken); + state.CreateSession(request.Header.SessionID, "Guest", machineName, sessionKey, accessToken, false); response.SessionFlags = SessionFlags.IsGuest; } } diff --git a/SMBLibrary/Server/SMBServer.SMB2.cs b/SMBLibrary/Server/SMBServer.SMB2.cs index 14af160..c16e96c 100644 --- a/SMBLibrary/Server/SMBServer.SMB2.cs +++ b/SMBLibrary/Server/SMBServer.SMB2.cs @@ -28,7 +28,7 @@ namespace SMBLibrary.Server SMB2Command response = ProcessSMB2Command(request, ref state); if (response != null) { - UpdateSMB2Header(response, request); + UpdateSMB2Header(response, request, state); responseChain.Add(response); if (!request.Header.IsRelatedOperations) { @@ -185,10 +185,9 @@ namespace SMBLibrary.Server internal static void EnqueueResponse(ConnectionState state, SMB2Command response) { - SessionMessagePacket packet = new SessionMessagePacket(); - packet.Trailer = response.GetBytes(); - state.SendQueue.Enqueue(packet); - state.LogToServer(Severity.Verbose, "SMB2 response queued: {0}, Packet length: {1}", response.CommandName.ToString(), packet.Length); + List responseChain = new List(); + responseChain.Add(response); + EnqueueResponseChain(state, responseChain); } private static void EnqueueResponseChain(ConnectionState state, List responseChain) @@ -216,16 +215,12 @@ namespace SMBLibrary.Server state.LogToServer(Severity.Verbose, "SMB2 response chain queued: Response count: {0}, First response: {1}, Packet length: {2}", responseChain.Count, responseChain[0].CommandName.ToString(), packet.Length); } - private static void UpdateSMB2Header(SMB2Command response, SMB2Command request) + private static void UpdateSMB2Header(SMB2Command response, SMB2Command request, ConnectionState state) { response.Header.MessageID = request.Header.MessageID; response.Header.CreditCharge = request.Header.CreditCharge; response.Header.Credits = Math.Max((ushort)1, request.Header.Credits); response.Header.IsRelatedOperations = request.Header.IsRelatedOperations; - // [MS-SMB2] The server SHOULD sign the message [..] if the request was signed by the client, - // and the response is not an interim response to an asynchronously processed request. - bool isInterimResponse = (request.Header.IsAsync && request.Header.Status == NTStatus.STATUS_PENDING); - response.Header.IsSigned = request.Header.IsSigned && !isInterimResponse; response.Header.Reserved = request.Header.Reserved; if (response.Header.SessionID == 0) { @@ -235,6 +230,19 @@ namespace SMBLibrary.Server { response.Header.TreeID = request.Header.TreeID; } + bool signingRequired = false; + if (state is SMB2ConnectionState) + { + SMB2Session session = ((SMB2ConnectionState)state).GetSession(response.Header.SessionID); + if (session != null && session.SigningRequired) + { + signingRequired = true; + } + } + // [MS-SMB2] The server SHOULD sign the message [..] if the request was signed by the client, + // and the response is not an interim response to an asynchronously processed request. + bool isInterimResponse = (response.Header.IsAsync && response.Header.Status == NTStatus.STATUS_PENDING); + response.Header.IsSigned = (request.Header.IsSigned || signingRequired) && !isInterimResponse; } private static void SetRequestFileID(SMB2Command command, FileID fileID)