diff --git a/ntlm/message_challenge.go b/ntlm/message_challenge.go index a57c454..de8d9b1 100644 --- a/ntlm/message_challenge.go +++ b/ntlm/message_challenge.go @@ -76,24 +76,27 @@ func ParseChallengeMessage(body []byte) (*ChallengeMessage, error) { challenge.NegotiateFlags = binary.LittleEndian.Uint32(body[20:24]) challenge.ServerChallenge = body[24:32] + offset := 32 - challenge.Reserved = body[32:40] + if NTLMSSP_NEGOTIATE_TARGET_INFO.IsSet(challenge.NegotiateFlags) { + challenge.Reserved = body[32:40] - challenge.TargetInfoPayloadStruct, err = ReadBytePayload(40, body) - if err != nil { - return nil, err - } - - challenge.TargetInfo = ReadAvPairs(challenge.TargetInfoPayloadStruct.Payload) - - offset := 48 - - if NTLMSSP_NEGOTIATE_VERSION.IsSet(challenge.NegotiateFlags) { - challenge.Version, err = ReadVersionStruct(body[offset : offset+8]) + challenge.TargetInfoPayloadStruct, err = ReadBytePayload(40, body) if err != nil { return nil, err } - offset = offset + 8 + + challenge.TargetInfo = ReadAvPairs(challenge.TargetInfoPayloadStruct.Payload) + + offset = 48 + + if NTLMSSP_NEGOTIATE_VERSION.IsSet(challenge.NegotiateFlags) { + challenge.Version, err = ReadVersionStruct(body[offset : offset+8]) + if err != nil { + return nil, err + } + offset = offset + 8 + } } challenge.Payload = body[offset:] @@ -163,7 +166,9 @@ func (c *ChallengeMessage) String() string { buffer.WriteString(fmt.Sprintf("\nVersion: %s\n", c.Version.String())) } buffer.WriteString("\nTargetInfo") - buffer.WriteString(c.TargetInfo.String()) + if c.TargetInfo != nil { + buffer.WriteString(c.TargetInfo.String()) + } buffer.WriteString(fmt.Sprintf("\nFlags %d\n", c.NegotiateFlags)) buffer.WriteString(FlagsToString(c.NegotiateFlags)) diff --git a/ntlm/ntlmv1.go b/ntlm/ntlmv1.go index 4ad2b84..d999449 100644 --- a/ntlm/ntlmv1.go +++ b/ntlm/ntlmv1.go @@ -90,14 +90,6 @@ func (n *V1Session) computeKeyExchangeKey() (err error) { } func (n *V1Session) calculateKeys(ntlmRevisionCurrent uint8) (err error) { - // This lovely piece of code comes courtesy of an the excellent Open Document support system from MSFT - // In order to calculate the keys correctly when the client has set the NTLMRevisionCurrent to 0xF (15) - // We must treat the flags as if NTLMSSP_NEGOTIATE_LM_KEY is set. - // This information is not contained (at least currently, until they correct it) in the MS-NLMP document - if ntlmRevisionCurrent == 15 { - n.NegotiateFlags = NTLMSSP_NEGOTIATE_LM_KEY.Set(n.NegotiateFlags) - } - n.ClientSigningKey = signKey(n.NegotiateFlags, n.exportedSessionKey, "Client") n.ServerSigningKey = signKey(n.NegotiateFlags, n.exportedSessionKey, "Server") n.ClientSealingKey = sealKey(n.NegotiateFlags, n.exportedSessionKey, "Client") @@ -278,23 +270,7 @@ func (n *V1ClientSession) ProcessChallengeMessage(cm *ChallengeMessage) (err err n.serverChallenge = cm.ServerChallenge n.clientChallenge = randomBytes(8) - // Set up the default flags for processing the response. These are the flags that we will return - // in the authenticate message - flags := uint32(0) - flags = NTLMSSP_NEGOTIATE_KEY_EXCH.Set(flags) - // NOTE: Unsetting this flag in order to get the server to generate the signatures we can recognize - flags = NTLMSSP_NEGOTIATE_VERSION.Set(flags) - flags = NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY.Set(flags) - flags = NTLMSSP_NEGOTIATE_TARGET_INFO.Set(flags) - flags = NTLMSSP_NEGOTIATE_IDENTIFY.Set(flags) - flags = NTLMSSP_NEGOTIATE_ALWAYS_SIGN.Set(flags) - flags = NTLMSSP_NEGOTIATE_NTLM.Set(flags) - flags = NTLMSSP_NEGOTIATE_DATAGRAM.Set(flags) - flags = NTLMSSP_NEGOTIATE_SIGN.Set(flags) - flags = NTLMSSP_REQUEST_TARGET.Set(flags) - flags = NTLMSSP_NEGOTIATE_UNICODE.Set(flags) - - n.NegotiateFlags = flags + n.NegotiateFlags = cm.NegotiateFlags err = n.fetchResponseKeys() if err != nil { @@ -321,18 +297,27 @@ func (n *V1ClientSession) ProcessChallengeMessage(cm *ChallengeMessage) (err err return err } - err = n.calculateKeys(cm.Version.NTLMRevisionCurrent) + ntlmRevision := uint8(0) + if cm.Version != nil { + ntlmRevision = cm.Version.NTLMRevisionCurrent + } + err = n.calculateKeys(ntlmRevision) if err != nil { return err } - n.clientHandle, err = rc4Init(n.ClientSealingKey) - if err != nil { - return err + if len(n.ClientSigningKey) > 0 { + n.clientHandle, err = rc4Init(n.ClientSealingKey) + if err != nil { + return err + } } - n.serverHandle, err = rc4Init(n.ServerSealingKey) - if err != nil { - return err + + if len(n.ServerSealingKey) > 0 { + n.serverHandle, err = rc4Init(n.ServerSealingKey) + if err != nil { + return err + } } return nil diff --git a/ntlm/ntlmv1_test.go b/ntlm/ntlmv1_test.go index eaa6331..c56960f 100644 --- a/ntlm/ntlmv1_test.go +++ b/ntlm/ntlmv1_test.go @@ -136,7 +136,8 @@ func TestNtlmV1(t *testing.T) { n.NegotiateFlags = NTLMSSP_NEGOTIATE_LM_KEY.Unset(n.NegotiateFlags) // 4.2.2.3 Messages - challengeMessageBytes, _ := hex.DecodeString("4e544c4d53535000020000000c000c003800000033820a820123456789abcdef00000000000000000000000000000000060070170000000f530065007200760065007200") + // challengeMessageBytes, _ := hex.DecodeString("4e544c4d53535000020000000c000c003800000033820a820123456789abcdef00000000000000000000000000000000060070170000000f530065007200760065007200") + challengeMessageBytes, _ := hex.DecodeString("4e544c4d53535000020000000c000c003800000033828ae20123456789abcdef00000000000000002400240044000000060070170000000f53006500720076006500720002000c0044006f006d00610069006e0001000c0053006500720076006500720000000000") challengeMessage, err := ParseChallengeMessage(challengeMessageBytes) if err == nil { challengeMessage.String() @@ -201,7 +202,8 @@ func TestNTLMv1WithClientChallenge(t *testing.T) { err = n.computeKeyExchangeKey() checkV1Value(t, "keyExchangeKey", n.keyExchangeKey, "eb93429a8bd952f8b89c55b87f475edc", err) - challengeMessageBytes, _ := hex.DecodeString("4e544c4d53535000020000000c000c003800000033820a820123456789abcdef00000000000000000000000000000000060070170000000f530065007200760065007200") + // challengeMessageBytes, _ := hex.DecodeString("4e544c4d53535000020000000c000c003800000033820a820123456789abcdef00000000000000000000000000000000060070170000000f530065007200760065007200") + challengeMessageBytes, _ := hex.DecodeString("4e544c4d53535000020000000c000c003800000033828ae20123456789abcdef00000000000000002400240044000000060070170000000f53006500720076006500720002000c0044006f006d00610069006e0001000c0053006500720076006500720000000000") challengeMessage, err := ParseChallengeMessage(challengeMessageBytes) if err == nil { challengeMessage.String() diff --git a/ntlm/ntlmv2.go b/ntlm/ntlmv2.go index a511f89..5a6fb42 100644 --- a/ntlm/ntlmv2.go +++ b/ntlm/ntlmv2.go @@ -67,14 +67,6 @@ func (n *V2Session) computeKeyExchangeKey() (err error) { } func (n *V2Session) calculateKeys(ntlmRevisionCurrent uint8) (err error) { - // This lovely piece of code comes courtesy of an the excellent Open Document support system from MSFT - // In order to calculate the keys correctly when the client has set the NTLMRevisionCurrent to 0xF (15) - // We must treat the flags as if NTLMSSP_NEGOTIATE_LM_KEY is set. - // This information is not contained (at least currently, until they correct it) in the MS-NLMP document - if ntlmRevisionCurrent == 15 { - n.NegotiateFlags = NTLMSSP_NEGOTIATE_LM_KEY.Set(n.NegotiateFlags) - } - n.ClientSigningKey = signKey(n.NegotiateFlags, n.exportedSessionKey, "Client") n.ServerSigningKey = signKey(n.NegotiateFlags, n.exportedSessionKey, "Server") n.ClientSealingKey = sealKey(n.NegotiateFlags, n.exportedSessionKey, "Client") @@ -296,31 +288,19 @@ func (n *V2ClientSession) ProcessChallengeMessage(cm *ChallengeMessage) (err err n.serverChallenge = cm.ServerChallenge n.clientChallenge = randomBytes(8) - // Set up the default flags for processing the response. These are the flags that we will return - // in the authenticate message - flags := uint32(0) - flags = NTLMSSP_NEGOTIATE_KEY_EXCH.Set(flags) - flags = NTLMSSP_NEGOTIATE_VERSION.Set(flags) - flags = NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY.Set(flags) - flags = NTLMSSP_NEGOTIATE_TARGET_INFO.Set(flags) - flags = NTLMSSP_NEGOTIATE_IDENTIFY.Set(flags) - flags = NTLMSSP_NEGOTIATE_ALWAYS_SIGN.Set(flags) - flags = NTLMSSP_NEGOTIATE_NTLM.Set(flags) - flags = NTLMSSP_NEGOTIATE_DATAGRAM.Set(flags) - flags = NTLMSSP_NEGOTIATE_SIGN.Set(flags) - flags = NTLMSSP_REQUEST_TARGET.Set(flags) - flags = NTLMSSP_NEGOTIATE_UNICODE.Set(flags) - flags = NTLMSSP_NEGOTIATE_128.Set(flags) - - n.NegotiateFlags = flags + n.NegotiateFlags = cm.NegotiateFlags err = n.fetchResponseKeys() if err != nil { return err } + var payload []byte + if NTLMSSP_NEGOTIATE_TARGET_INFO.IsSet(cm.NegotiateFlags) { + payload = cm.TargetInfoPayloadStruct.Payload + } timestamp := timeToWindowsFileTime(time.Now()) - err = n.computeExpectedResponses(timestamp, cm.TargetInfoPayloadStruct.Payload) + err = n.computeExpectedResponses(timestamp, payload) if err != nil { return err } @@ -335,19 +315,30 @@ func (n *V2ClientSession) ProcessChallengeMessage(cm *ChallengeMessage) (err err return err } - err = n.calculateKeys(cm.Version.NTLMRevisionCurrent) + ntlmRevision := uint8(0) + if cm.Version != nil { + ntlmRevision = cm.Version.NTLMRevisionCurrent + } + + err = n.calculateKeys(ntlmRevision) if err != nil { return err } - n.clientHandle, err = rc4Init(n.ClientSealingKey) - if err != nil { - return err + if len(n.ClientSigningKey) > 0 { + n.clientHandle, err = rc4Init(n.ClientSealingKey) + if err != nil { + return err + } } - n.serverHandle, err = rc4Init(n.ServerSealingKey) - if err != nil { - return err + + if len(n.ServerSealingKey) > 0 { + n.serverHandle, err = rc4Init(n.ServerSealingKey) + if err != nil { + return err + } } + return nil }