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.NegotiateFlags = binary.LittleEndian.Uint32(body[20:24]) | ||||||
| 
 | 
 | ||||||
| 	challenge.ServerChallenge = body[24:32] | 	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) | 		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]) |  | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 			return nil, err | 			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:] | 	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(fmt.Sprintf("\nVersion: %s\n", c.Version.String())) | ||||||
| 	} | 	} | ||||||
| 	buffer.WriteString("\nTargetInfo") | 	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(fmt.Sprintf("\nFlags %d\n", c.NegotiateFlags)) | ||||||
| 	buffer.WriteString(FlagsToString(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) { | 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.ClientSigningKey = signKey(n.NegotiateFlags, n.exportedSessionKey, "Client") | ||||||
| 	n.ServerSigningKey = signKey(n.NegotiateFlags, n.exportedSessionKey, "Server") | 	n.ServerSigningKey = signKey(n.NegotiateFlags, n.exportedSessionKey, "Server") | ||||||
| 	n.ClientSealingKey = sealKey(n.NegotiateFlags, n.exportedSessionKey, "Client") | 	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.serverChallenge = cm.ServerChallenge | ||||||
| 	n.clientChallenge = randomBytes(8) | 	n.clientChallenge = randomBytes(8) | ||||||
| 
 | 
 | ||||||
| 	// Set up the default flags for processing the response. These are the flags that we will return | 	n.NegotiateFlags = cm.NegotiateFlags | ||||||
| 	// 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 |  | ||||||
| 
 | 
 | ||||||
| 	err = n.fetchResponseKeys() | 	err = n.fetchResponseKeys() | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| @ -321,18 +297,27 @@ func (n *V1ClientSession) ProcessChallengeMessage(cm *ChallengeMessage) (err err | |||||||
| 		return 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 { | 	if err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	n.clientHandle, err = rc4Init(n.ClientSealingKey) | 	if len(n.ClientSigningKey) > 0 { | ||||||
| 	if err != nil { | 		n.clientHandle, err = rc4Init(n.ClientSealingKey) | ||||||
| 		return err | 		if err != nil { | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
| 	n.serverHandle, err = rc4Init(n.ServerSealingKey) | 
 | ||||||
| 	if err != nil { | 	if len(n.ServerSealingKey) > 0 { | ||||||
| 		return err | 		n.serverHandle, err = rc4Init(n.ServerSealingKey) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	return nil | 	return nil | ||||||
|  | |||||||
| @ -136,7 +136,8 @@ func TestNtlmV1(t *testing.T) { | |||||||
| 	n.NegotiateFlags = NTLMSSP_NEGOTIATE_LM_KEY.Unset(n.NegotiateFlags) | 	n.NegotiateFlags = NTLMSSP_NEGOTIATE_LM_KEY.Unset(n.NegotiateFlags) | ||||||
| 
 | 
 | ||||||
| 	// 4.2.2.3 Messages | 	// 4.2.2.3 Messages | ||||||
| 	challengeMessageBytes, _ := hex.DecodeString("4e544c4d53535000020000000c000c003800000033820a820123456789abcdef00000000000000000000000000000000060070170000000f530065007200760065007200") | 	// challengeMessageBytes, _ := hex.DecodeString("4e544c4d53535000020000000c000c003800000033820a820123456789abcdef00000000000000000000000000000000060070170000000f530065007200760065007200") | ||||||
|  | 	challengeMessageBytes, _ := hex.DecodeString("4e544c4d53535000020000000c000c003800000033828ae20123456789abcdef00000000000000002400240044000000060070170000000f53006500720076006500720002000c0044006f006d00610069006e0001000c0053006500720076006500720000000000") | ||||||
| 	challengeMessage, err := ParseChallengeMessage(challengeMessageBytes) | 	challengeMessage, err := ParseChallengeMessage(challengeMessageBytes) | ||||||
| 	if err == nil { | 	if err == nil { | ||||||
| 		challengeMessage.String() | 		challengeMessage.String() | ||||||
| @ -201,7 +202,8 @@ func TestNTLMv1WithClientChallenge(t *testing.T) { | |||||||
| 	err = n.computeKeyExchangeKey() | 	err = n.computeKeyExchangeKey() | ||||||
| 	checkV1Value(t, "keyExchangeKey", n.keyExchangeKey, "eb93429a8bd952f8b89c55b87f475edc", err) | 	checkV1Value(t, "keyExchangeKey", n.keyExchangeKey, "eb93429a8bd952f8b89c55b87f475edc", err) | ||||||
| 
 | 
 | ||||||
| 	challengeMessageBytes, _ := hex.DecodeString("4e544c4d53535000020000000c000c003800000033820a820123456789abcdef00000000000000000000000000000000060070170000000f530065007200760065007200") | 	// challengeMessageBytes, _ := hex.DecodeString("4e544c4d53535000020000000c000c003800000033820a820123456789abcdef00000000000000000000000000000000060070170000000f530065007200760065007200") | ||||||
|  | 	challengeMessageBytes, _ := hex.DecodeString("4e544c4d53535000020000000c000c003800000033828ae20123456789abcdef00000000000000002400240044000000060070170000000f53006500720076006500720002000c0044006f006d00610069006e0001000c0053006500720076006500720000000000") | ||||||
| 	challengeMessage, err := ParseChallengeMessage(challengeMessageBytes) | 	challengeMessage, err := ParseChallengeMessage(challengeMessageBytes) | ||||||
| 	if err == nil { | 	if err == nil { | ||||||
| 		challengeMessage.String() | 		challengeMessage.String() | ||||||
|  | |||||||
| @ -67,14 +67,6 @@ func (n *V2Session) computeKeyExchangeKey() (err error) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (n *V2Session) calculateKeys(ntlmRevisionCurrent uint8) (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.ClientSigningKey = signKey(n.NegotiateFlags, n.exportedSessionKey, "Client") | ||||||
| 	n.ServerSigningKey = signKey(n.NegotiateFlags, n.exportedSessionKey, "Server") | 	n.ServerSigningKey = signKey(n.NegotiateFlags, n.exportedSessionKey, "Server") | ||||||
| 	n.ClientSealingKey = sealKey(n.NegotiateFlags, n.exportedSessionKey, "Client") | 	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.serverChallenge = cm.ServerChallenge | ||||||
| 	n.clientChallenge = randomBytes(8) | 	n.clientChallenge = randomBytes(8) | ||||||
| 
 | 
 | ||||||
| 	// Set up the default flags for processing the response. These are the flags that we will return | 	n.NegotiateFlags = cm.NegotiateFlags | ||||||
| 	// 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 |  | ||||||
| 
 | 
 | ||||||
| 	err = n.fetchResponseKeys() | 	err = n.fetchResponseKeys() | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	var payload []byte | ||||||
|  | 	if NTLMSSP_NEGOTIATE_TARGET_INFO.IsSet(cm.NegotiateFlags) { | ||||||
|  | 		payload = cm.TargetInfoPayloadStruct.Payload | ||||||
|  | 	} | ||||||
| 	timestamp := timeToWindowsFileTime(time.Now()) | 	timestamp := timeToWindowsFileTime(time.Now()) | ||||||
| 	err = n.computeExpectedResponses(timestamp, cm.TargetInfoPayloadStruct.Payload) | 	err = n.computeExpectedResponses(timestamp, payload) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| @ -335,19 +315,30 @@ func (n *V2ClientSession) ProcessChallengeMessage(cm *ChallengeMessage) (err err | |||||||
| 		return 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 { | 	if err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	n.clientHandle, err = rc4Init(n.ClientSealingKey) | 	if len(n.ClientSigningKey) > 0 { | ||||||
| 	if err != nil { | 		n.clientHandle, err = rc4Init(n.ClientSealingKey) | ||||||
| 		return err | 		if err != nil { | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
| 	n.serverHandle, err = rc4Init(n.ServerSealingKey) | 
 | ||||||
| 	if err != nil { | 	if len(n.ServerSealingKey) > 0 { | ||||||
| 		return err | 		n.serverHandle, err = rc4Init(n.ServerSealingKey) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
|  | 
 | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user