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