Feature/extended session security (#1)
* some parsing fixes: - make TargetInfo optional - make Version optional - make sure extended session security is only used when negotiated - remove obsolete assumptions from the code
This commit is contained in:
		
							parent
							
								
									f36cde2feb
								
							
						
					
					
						commit
						a3410e5aec
					
				| @ -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)) | ||||
| 
 | ||||
|  | ||||
| @ -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 | ||||
|  | ||||
| @ -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() | ||||
|  | ||||
| @ -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 | ||||
| } | ||||
| 
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user