Exemple #1
0
        private bool NegotiateDialect()
        {
            NegotiateRequest request = new NegotiateRequest();

            request.SecurityMode    = SecurityMode.SigningEnabled;
            request.ClientGuid      = Guid.NewGuid();
            request.ClientStartTime = DateTime.Now;
            request.Dialects.Add(SMB2Dialect.SMB202);
            request.Dialects.Add(SMB2Dialect.SMB210);

            TrySendCommand(request);
            NegotiateResponse response = WaitForCommand(SMB2CommandName.Negotiate) as NegotiateResponse;

            if (response != null && response.Header.Status == NTStatus.STATUS_SUCCESS)
            {
                m_dialect         = response.DialectRevision;
                m_signingRequired = (response.SecurityMode & SecurityMode.SigningRequired) > 0;
                m_maxTransactSize = Math.Min(response.MaxTransactSize, ClientMaxTransactSize);
                m_maxReadSize     = Math.Min(response.MaxReadSize, ClientMaxReadSize);
                m_maxWriteSize    = Math.Min(response.MaxWriteSize, ClientMaxWriteSize);
                m_securityBlob    = response.SecurityBuffer;
                return(true);
            }
            return(false);
        }
Exemple #2
0
        private static void EnqueueResponseChain(ConnectionState state, List <SMB2Command> responseChain)
        {
            byte[] signingKey = null;
            if (state is SMB2ConnectionState)
            {
                // Note: multiple sessions MAY be multiplexed on the same connection, so theoretically
                // we could have compounding unrelated requests from different sessions.
                // In practice however this is not a real problem.
                ulong sessionID = responseChain[0].Header.SessionID;
                if (sessionID != 0)
                {
                    SMB2Session session = ((SMB2ConnectionState)state).GetSession(sessionID);
                    if (session != null)
                    {
                        signingKey = session.SigningKey;
                    }
                }
            }

            SessionMessagePacket packet      = new SessionMessagePacket();
            SMB2Dialect          smb2Dialect = (signingKey != null) ? ToSMB2Dialect(state.Dialect) : SMB2Dialect.SMB2xx;

            packet.Trailer = SMB2Command.GetCommandChainBytes(responseChain, signingKey, smb2Dialect);
            state.SendQueue.Enqueue(packet);
            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);
        }
        public static byte[] CalculateSignature(byte[] signingKey, SMB2Dialect dialect, byte[] buffer, int offset, int paddedLength)
        {
            if (dialect != SMB2Dialect.SMB202 && dialect != SMB2Dialect.SMB210)
            {
                return(AesCmac.CalculateAesCmac(signingKey, buffer, offset, paddedLength));
            }

            using HMACSHA256 sha256 = new HMACSHA256(signingKey);
            return(sha256.ComputeHash(buffer, offset, paddedLength));
        }
Exemple #4
0
 public static byte[] CalculateSignature(byte[] signingKey, SMB2Dialect dialect, byte[] buffer, int offset, int paddedLength)
 {
     if (dialect == SMB2Dialect.SMB202 || dialect == SMB2Dialect.SMB210)
     {
         return(new HMACSHA256(signingKey).ComputeHash(buffer, offset, paddedLength));
     }
     else
     {
         return(AesCmac.CalculateAesCmac(signingKey, buffer, offset, paddedLength));
     }
 }
        public static byte[] GenerateClientDecryptionKey(byte[] sessionKey, SMB2Dialect dialect, byte[] preauthIntegrityHashValue)
        {
            if (dialect == SMB2Dialect.SMB311 && preauthIntegrityHashValue == null)
            {
                throw new ArgumentNullException(nameof(preauthIntegrityHashValue));
            }

            string labelString = (dialect == SMB2Dialect.SMB311) ? "SMBS2CCipherKey" : "SMB2AESCCM";

            byte[] label   = GetNullTerminatedAnsiString(labelString);
            byte[] context = (dialect == SMB2Dialect.SMB311) ? preauthIntegrityHashValue : GetNullTerminatedAnsiString("ServerOut");

            using HMACSHA256 hmac = new HMACSHA256(sessionKey);
            return(SP800_1008.DeriveKey(hmac, label, context, 128));
        }
Exemple #6
0
        public override void WriteCommandBytes(byte[] buffer, int offset)
        {
            LittleEndianWriter.WriteUInt16(buffer, offset + 0, StructureSize);
            LittleEndianWriter.WriteUInt16(buffer, offset + 2, (ushort)Dialects.Count);
            LittleEndianWriter.WriteUInt16(buffer, offset + 4, (ushort)SecurityMode);
            LittleEndianWriter.WriteUInt16(buffer, offset + 6, Reserved);
            LittleEndianWriter.WriteUInt32(buffer, offset + 8, (uint)Capabilities);
            LittleEndianWriter.WriteGuid(buffer, offset + 12, ClientGuid);
            LittleEndianWriter.WriteInt64(buffer, offset + 28, ClientStartTime.ToFileTimeUtc());

            for (int index = 0; index < Dialects.Count; index++)
            {
                SMB2Dialect dialect = Dialects[index];
                LittleEndianWriter.WriteUInt16(buffer, offset + 36 + index * 2, (ushort)dialect);
            }
        }
        public NegotiateRequest(byte[] buffer, int offset) : base(buffer, offset)
        {
            StructureSize   = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 0);
            DialectCount    = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 2);
            SecurityMode    = (SecurityMode)LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 4);
            Reserved        = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 6);
            Capabilities    = (ServerCapabilities)LittleEndianConverter.ToUInt32(buffer, offset + SMB2Header.Length + 8);
            ClientGuid      = LittleEndianConverter.ToGuid(buffer, offset + SMB2Header.Length + 12);
            ClientStartTime = DateTime.FromFileTimeUtc(LittleEndianConverter.ToInt64(buffer, offset + SMB2Header.Length + 28));

            for (int index = 0; index < DialectCount; index++)
            {
                SMB2Dialect dialect = (SMB2Dialect)LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 36 + index * 2);
                Dialects.Add(dialect);
            }
        }
Exemple #8
0
 public NegotiateResponse(byte[] buffer, int offset) : base(buffer, offset)
 {
     StructureSize          = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 0);
     SecurityMode           = (SecurityMode)LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 2);
     DialectRevision        = (SMB2Dialect)LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 4);
     NegotiateContextCount  = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 6);
     ServerGuid             = LittleEndianConverter.ToGuid(buffer, offset + SMB2Header.Length + 8);
     Capabilities           = (Capabilities)LittleEndianConverter.ToUInt32(buffer, offset + SMB2Header.Length + 24);
     MaxTransactSize        = LittleEndianConverter.ToUInt32(buffer, offset + SMB2Header.Length + 28);
     MaxReadSize            = LittleEndianConverter.ToUInt32(buffer, offset + SMB2Header.Length + 32);
     MaxWriteSize           = LittleEndianConverter.ToUInt32(buffer, offset + SMB2Header.Length + 36);
     SystemTime             = DateTime.FromFileTimeUtc(LittleEndianConverter.ToInt64(buffer, offset + SMB2Header.Length + 40));
     ServerStartTime        = DateTime.FromFileTimeUtc(LittleEndianConverter.ToInt64(buffer, offset + SMB2Header.Length + 48));
     SecurityBufferOffset   = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 56);
     SecurityBufferLength   = LittleEndianConverter.ToUInt16(buffer, offset + SMB2Header.Length + 58);
     NegotiateContextOffset = LittleEndianConverter.ToUInt32(buffer, offset + SMB2Header.Length + 60);
     SecurityBuffer         = ByteReader.ReadBytes(buffer, offset + SecurityBufferOffset, SecurityBufferLength);
     NegotiateContextList   = NegotiateContext.ReadNegotiateContextList(buffer, (int)NegotiateContextOffset, NegotiateContextCount);
 }
        public static byte[] GenerateSigningKey(byte[] sessionKey, SMB2Dialect dialect, byte[]?preauthIntegrityHashValue)
        {
            if (dialect == SMB2Dialect.SMB202 || dialect == SMB2Dialect.SMB210)
            {
                return(sessionKey);
            }

            if (dialect == SMB2Dialect.SMB311 && preauthIntegrityHashValue == null)
            {
                throw new ArgumentNullException(nameof(preauthIntegrityHashValue));
            }

            string labelString = (dialect == SMB2Dialect.SMB311) ? "SMBSigningKey" : "SMB2AESCMAC";

            byte[] label   = GetNullTerminatedAnsiString(labelString);
            byte[] context = (dialect == SMB2Dialect.SMB311) ? preauthIntegrityHashValue ! : GetNullTerminatedAnsiString("SmbSign");

            using HMACSHA256 hmac = new HMACSHA256(sessionKey);
            return(SP800_1008.DeriveKey(hmac, label, context, 128));
        }
        internal static SMB2Command GetSessionSetupResponse(SessionSetupRequest request, GSSProvider securityProvider, SMB2ConnectionState state)
        {
            // [MS-SMB2] Windows [..] will also accept raw Kerberos messages and implicit NTLM messages as part of GSS authentication.
            SessionSetupResponse response = new SessionSetupResponse();

            byte[]   outputToken;
            NTStatus status = securityProvider.AcceptSecurityContext(ref state.AuthenticationContext, request.SecurityBuffer, out outputToken);

            if (status != NTStatus.STATUS_SUCCESS && status != NTStatus.SEC_I_CONTINUE_NEEDED)
            {
                string userName    = securityProvider.GetContextAttribute(state.AuthenticationContext, GSSAttributeName.UserName) as string;
                string domainName  = securityProvider.GetContextAttribute(state.AuthenticationContext, GSSAttributeName.DomainName) as string;
                string machineName = securityProvider.GetContextAttribute(state.AuthenticationContext, GSSAttributeName.MachineName) as string;
                string osVersion   = securityProvider.GetContextAttribute(state.AuthenticationContext, GSSAttributeName.OSVersion) as string;
                state.LogToServer(Severity.Information, "Session Setup: User '{0}' failed authentication (Domain: '{1}', Workstation: '{2}', OS version: '{3}'), NTStatus: {4}", userName, domainName, machineName, osVersion, status);
                return(new ErrorResponse(request.CommandName, status));
            }

            if (outputToken != null)
            {
                response.SecurityBuffer = outputToken;
            }

            // According to [MS-SMB2] 3.3.5.5.3, response.Header.SessionID must be allocated if the server returns STATUS_MORE_PROCESSING_REQUIRED
            if (request.Header.SessionID == 0)
            {
                ulong?sessionID = state.AllocateSessionID();
                if (!sessionID.HasValue)
                {
                    return(new ErrorResponse(request.CommandName, NTStatus.STATUS_TOO_MANY_SESSIONS));
                }
                response.Header.SessionID = sessionID.Value;
            }

            if (status == NTStatus.SEC_I_CONTINUE_NEEDED)
            {
                response.Header.Status = NTStatus.STATUS_MORE_PROCESSING_REQUIRED;
            }
            else // status == STATUS_SUCCESS
            {
                string userName    = securityProvider.GetContextAttribute(state.AuthenticationContext, GSSAttributeName.UserName) as string;
                string domainName  = securityProvider.GetContextAttribute(state.AuthenticationContext, GSSAttributeName.DomainName) as string;
                string machineName = securityProvider.GetContextAttribute(state.AuthenticationContext, GSSAttributeName.MachineName) as string;
                string osVersion   = securityProvider.GetContextAttribute(state.AuthenticationContext, GSSAttributeName.OSVersion) as string;
                byte[] sessionKey  = securityProvider.GetContextAttribute(state.AuthenticationContext, GSSAttributeName.SessionKey) as byte[];
                object accessToken = securityProvider.GetContextAttribute(state.AuthenticationContext, GSSAttributeName.AccessToken);
                bool?  isGuest     = securityProvider.GetContextAttribute(state.AuthenticationContext, GSSAttributeName.IsGuest) as bool?;
                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);
                    bool        signingRequired = (request.SecurityMode & SecurityMode.SigningRequired) > 0;
                    SMB2Dialect smb2Dialect     = SMBServer.ToSMB2Dialect(state.Dialect);
                    byte[]      signingKey      = SMB2Cryptography.GenerateSigningKey(sessionKey, smb2Dialect, null);
                    state.CreateSession(request.Header.SessionID, userName, machineName, sessionKey, accessToken, signingRequired, signingKey);
                }
                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, false, null);
                    response.SessionFlags = SessionFlags.IsGuest;
                }
            }
            return(response);
        }
Exemple #11
0
        /// <param name="signingKey">
        /// Message will be signed using this key if (not null and) SMB2_FLAGS_SIGNED is set.
        /// </param>
        /// <param name="dialect">
        /// Used for signature calculation when applicable.
        /// </param>
        public static byte[] GetCommandChainBytes(List <SMB2Command> commands, byte[] signingKey, SMB2Dialect dialect)
        {
            int totalLength = 0;

            for (int index = 0; index < commands.Count; index++)
            {
                // Any subsequent SMB2 header MUST be 8-byte aligned
                int length = commands[index].Length;
                if (index < commands.Count - 1)
                {
                    int paddedLength = (int)Math.Ceiling((double)length / 8) * 8;
                    totalLength += paddedLength;
                }
                else
                {
                    totalLength += length;
                }
            }
            byte[] buffer = new byte[totalLength];
            int    offset = 0;

            for (int index = 0; index < commands.Count; index++)
            {
                SMB2Command command       = commands[index];
                int         commandLength = command.Length;
                int         paddedLength;
                if (index < commands.Count - 1)
                {
                    paddedLength = (int)Math.Ceiling((double)commandLength / 8) * 8;
                    command.Header.NextCommand = (uint)paddedLength;
                }
                else
                {
                    paddedLength = commandLength;
                }
                command.WriteBytes(buffer, offset);
                if (command.Header.IsSigned && signingKey != null)
                {
                    // [MS-SMB2] Any padding at the end of the message MUST be used in the hash computation.
                    byte[] signature = SMB2Cryptography.CalculateSignature(signingKey, dialect, buffer, offset, paddedLength);
                    // [MS-SMB2] The first 16 bytes of the hash MUST be copied into the 16-byte signature field of the SMB2 Header.
                    ByteWriter.WriteBytes(buffer, offset + SMB2Header.SignatureOffset, signature, 16);
                }
                offset += paddedLength;
            }
            return(buffer);
        }