generate challenge messages
This commit is contained in:
		
							parent
							
								
									a9e17c39f6
								
							
						
					
					
						commit
						d5082d0f01
					
				| @ -5,7 +5,6 @@ import ( | |||||||
| 	"encoding/binary" | 	"encoding/binary" | ||||||
| 	"encoding/hex" | 	"encoding/hex" | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"reflect" |  | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| type AvPairType uint16 | type AvPairType uint16 | ||||||
| @ -45,6 +44,11 @@ type AvPairs struct { | |||||||
| 	List []AvPair | 	List []AvPair | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func (p *AvPairs) AddAvPair(avId AvPairType, bytes []byte) { | ||||||
|  | 	a := &AvPair{AvId: avId, AvLen: uint16(len(bytes)), Value: bytes} | ||||||
|  |   p.List = append(p.List, *a) | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func ReadAvPairs(data []byte) *AvPairs { | func ReadAvPairs(data []byte) *AvPairs { | ||||||
| 	pairs := new(AvPairs) | 	pairs := new(AvPairs) | ||||||
| 
 | 
 | ||||||
| @ -153,10 +157,26 @@ func (a *AvPair) String() string { | |||||||
| 	switch a.AvId { | 	switch a.AvId { | ||||||
| 	case MsvAvEOL: | 	case MsvAvEOL: | ||||||
| 		outString = "MsvAvEOL" | 		outString = "MsvAvEOL" | ||||||
| 	case MsvAvNbComputerName, MsvAvNbDomainName, MsvAvDnsComputerName, MsvAvDnsDomainName, MsvAvDnsTreeName, MsvAvTargetName: | 	case MsvAvNbComputerName: | ||||||
| 		outString = fmt.Sprintf("%s: %s", reflect.TypeOf(a.AvId).Name(), a.UnicodeStringValue()) | 		outString = "MsAvNbComputerName: " + a.UnicodeStringValue() | ||||||
| 	case MsvAvFlags, MsvAvTimestamp, MsAvRestrictions, MsvChannelBindings: | 	case MsvAvNbDomainName: | ||||||
| 		outString = fmt.Sprintf("%s: %s", reflect.TypeOf(a.AvId).Name(), hex.EncodeToString(a.Value)) | 		outString = "MsvAvNbDomainName: " + a.UnicodeStringValue() | ||||||
|  | 	case MsvAvDnsComputerName: | ||||||
|  | 		outString = "MsvAvDnsComputerName: " + a.UnicodeStringValue() | ||||||
|  | 	case MsvAvDnsDomainName: | ||||||
|  | 		outString = "MsvAvDnsDomainName: " + a.UnicodeStringValue() | ||||||
|  | 	case MsvAvDnsTreeName: | ||||||
|  | 		outString = "MsvAvDnsTreeName: " + a.UnicodeStringValue() | ||||||
|  | 	case MsvAvFlags: | ||||||
|  | 		outString = "MsvAvFlags: " + hex.EncodeToString(a.Value) | ||||||
|  | 	case MsvAvTimestamp: | ||||||
|  | 		outString = "MsvAvTimestamp: " + hex.EncodeToString(a.Value) | ||||||
|  | 	case MsAvRestrictions: | ||||||
|  | 		outString = "MsAvRestrictions: " + hex.EncodeToString(a.Value) | ||||||
|  | 	case MsvAvTargetName: | ||||||
|  | 		outString = "MsvAvTargetName: " + a.UnicodeStringValue() | ||||||
|  | 	case MsvChannelBindings: | ||||||
|  | 		outString = "MsvChannelBindings: " + hex.EncodeToString(a.Value) | ||||||
| 	default: | 	default: | ||||||
| 		outString = fmt.Sprintf("unknown pair type: '%d'", a.AvId) | 		outString = fmt.Sprintf("unknown pair type: '%d'", a.AvId) | ||||||
| 	} | 	} | ||||||
|  | |||||||
| @ -95,7 +95,7 @@ func ParseChallengeMessage(body []byte) (*Challenge, error) { | |||||||
| 
 | 
 | ||||||
| func (c *Challenge) Bytes() []byte { | func (c *Challenge) Bytes() []byte { | ||||||
| 	payloadLen := int(c.TargetName.Len + c.TargetInfoPayloadStruct.Len) | 	payloadLen := int(c.TargetName.Len + c.TargetInfoPayloadStruct.Len) | ||||||
| 	messageLen := 8 + 4 + 12 + 4 + 8 + 8 + 12 + 8 | 	messageLen := 8 + 4 + 8 + 4 + 8 + 8 + 8 + 8 | ||||||
| 	payloadOffset := uint32(messageLen) | 	payloadOffset := uint32(messageLen) | ||||||
| 
 | 
 | ||||||
| 	messageBytes := make([]byte, 0, messageLen+payloadLen) | 	messageBytes := make([]byte, 0, messageLen+payloadLen) | ||||||
| @ -105,18 +105,21 @@ func (c *Challenge) Bytes() []byte { | |||||||
| 	binary.Write(buffer, binary.LittleEndian, c.MessageType) | 	binary.Write(buffer, binary.LittleEndian, c.MessageType) | ||||||
|    |    | ||||||
| 	c.TargetName.Offset = payloadOffset | 	c.TargetName.Offset = payloadOffset | ||||||
| 	payloadOffset += uint32(c.TargetName.Len) |  | ||||||
| 	buffer.Write(c.TargetName.Bytes()) | 	buffer.Write(c.TargetName.Bytes()) | ||||||
|  | 	payloadOffset += uint32(c.TargetName.Len) | ||||||
| 
 | 
 | ||||||
| 	binary.Write(buffer, binary.LittleEndian, c.NegotiateFlags) | 	binary.Write(buffer, binary.LittleEndian, c.NegotiateFlags) | ||||||
| 	buffer.Write(c.ServerChallenge) | 	buffer.Write(c.ServerChallenge) | ||||||
|   buffer.Write(make([]byte, 8)) |   buffer.Write(make([]byte, 8)) | ||||||
| 
 | 
 | ||||||
|   c.TargetInfoPayloadStruct.Offset = payloadOffset |   c.TargetInfoPayloadStruct.Offset = payloadOffset | ||||||
|   payloadOffset += uint32(c.TargetInfoPayloadStruct.Len) |  | ||||||
|   buffer.Write(c.TargetInfoPayloadStruct.Bytes()) |   buffer.Write(c.TargetInfoPayloadStruct.Bytes()) | ||||||
|  |   payloadOffset += uint32(c.TargetInfoPayloadStruct.Len) | ||||||
|  | 
 | ||||||
|   if(c.Version != nil) { |   if(c.Version != nil) { | ||||||
|     buffer.Write(c.Version.Bytes()) |     buffer.Write(c.Version.Bytes()) | ||||||
|  |   } else { | ||||||
|  | 	  buffer.Write(make([]byte, 8)) | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| 	// Write out the payloads | 	// Write out the payloads | ||||||
|  | |||||||
| @ -46,4 +46,18 @@ func TestDecodeChallenge(t *testing.T) { | |||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	challenge.String() | 	challenge.String() | ||||||
|  | 	 | ||||||
|  | 	outBytes := challenge.Bytes() | ||||||
|  | 
 | ||||||
|  | 	if len(outBytes) > 0 { | ||||||
|  | 		reparsed, err := ParseChallengeMessage(outBytes) | ||||||
|  | 		if err != nil { | ||||||
|  | 			t.Error("Could not re-parse challenge message") | ||||||
|  | 		} | ||||||
|  | 		if reparsed.String() != challenge.String() { | ||||||
|  | 			t.Error("Reparsed message is not the same") | ||||||
|  | 		} | ||||||
|  | 	} else { | ||||||
|  | 		t.Error("Invalid challenge messsage bytes") | ||||||
|  | 	} | ||||||
| } | } | ||||||
|  | |||||||
| @ -138,6 +138,34 @@ func (f NegotiateFlag) String() string { | |||||||
| 	return reflect.TypeOf(f).Name() | 	return reflect.TypeOf(f).Name() | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func GetFlagName(flag NegotiateFlag) string { | ||||||
|  | 	nameMap := map[NegotiateFlag]string{ | ||||||
|  | 		NTLMSSP_NEGOTIATE_56:                       "NTLMSSP_NEGOTIATE_56", | ||||||
|  | 		NTLMSSP_NEGOTIATE_KEY_EXCH:                 "NTLMSSP_NEGOTIATE_KEY_EXCH", | ||||||
|  | 		NTLMSSP_NEGOTIATE_128:                      "NTLMSSP_NEGOTIATE_128", | ||||||
|  | 		NTLMSSP_NEGOTIATE_VERSION:                  "NTLMSSP_NEGOTIATE_VERSION", | ||||||
|  | 		NTLMSSP_NEGOTIATE_TARGET_INFO:              "NTLMSSP_NEGOTIATE_TARGET_INFO", | ||||||
|  | 		NTLMSSP_REQUEST_NON_NT_SESSION_KEY:         "NTLMSSP_REQUEST_NON_NT_SESSION_KEY", | ||||||
|  | 		NTLMSSP_NEGOTIATE_IDENTIFY:                 "NTLMSSP_NEGOTIATE_IDENTIFY", | ||||||
|  | 		NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY: "NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY", | ||||||
|  | 		NTLMSSP_TARGET_TYPE_SERVER:                 "NTLMSSP_TARGET_TYPE_SERVER", | ||||||
|  | 		NTLMSSP_TARGET_TYPE_DOMAIN:                 "NTLMSSP_TARGET_TYPE_DOMAIN", | ||||||
|  | 		NTLMSSP_NEGOTIATE_ALWAYS_SIGN:              "NTLMSSP_NEGOTIATE_ALWAYS_SIGN", | ||||||
|  | 		NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED: "NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED", | ||||||
|  | 		NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED:      "NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED", | ||||||
|  | 		NTLMSSP_ANONYMOUS:                          "NTLMSSP_ANONYMOUS", | ||||||
|  | 		NTLMSSP_NEGOTIATE_NTLM:                     "NTLMSSP_NEGOTIATE_NTLM", | ||||||
|  | 		NTLMSSP_NEGOTIATE_LM_KEY:                   "NTLMSSP_NEGOTIATE_LM_KEY", | ||||||
|  | 		NTLMSSP_NEGOTIATE_DATAGRAM:                 "NTLMSSP_NEGOTIATE_DATAGRAM", | ||||||
|  | 		NTLMSSP_NEGOTIATE_SEAL:                     "NTLMSSP_NEGOTIATE_SEAL", | ||||||
|  | 		NTLMSSP_NEGOTIATE_SIGN:                     "NTLMSSP_NEGOTIATE_SIGN", | ||||||
|  | 		NTLMSSP_REQUEST_TARGET:                     "NTLMSSP_REQUEST_TARGET", | ||||||
|  | 		NTLM_NEGOTIATE_OEM:                         "NTLM_NEGOTIATE_OEM", | ||||||
|  | 		NTLMSSP_NEGOTIATE_UNICODE:                  "NTLMSSP_NEGOTIATE_UNICODE"} | ||||||
|  | 
 | ||||||
|  | 	return nameMap[flag] | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func FlagsToString(flags uint32) string { | func FlagsToString(flags uint32) string { | ||||||
| 	allFlags := [...]NegotiateFlag{ | 	allFlags := [...]NegotiateFlag{ | ||||||
| 		NTLMSSP_NEGOTIATE_56, | 		NTLMSSP_NEGOTIATE_56, | ||||||
| @ -166,7 +194,7 @@ func FlagsToString(flags uint32) string { | |||||||
| 	var buffer bytes.Buffer | 	var buffer bytes.Buffer | ||||||
| 	for i := range allFlags { | 	for i := range allFlags { | ||||||
| 		f := allFlags[i] | 		f := allFlags[i] | ||||||
| 		buffer.WriteString(fmt.Sprintf("%s: %v\n", f.String(), f.IsSet(flags))) | 		buffer.WriteString(fmt.Sprintf("%s: %v\n", GetFlagName(f), f.IsSet(flags))) | ||||||
| 	} | 	} | ||||||
| 	return buffer.String() | 	return buffer.String() | ||||||
| } | } | ||||||
|  | |||||||
| @ -81,8 +81,42 @@ func (n *V2ServerSession) ProcessNegotiateMessage(nm *messages.Negotiate) (err e | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (n *V2ServerSession) GenerateChallengeMessage() (cm *messages.Challenge, err error) { | func (n *V2ServerSession) GenerateChallengeMessage() (cm *messages.Challenge, err error) { | ||||||
| 	// TODO: Generate this challenge message | 	cm = new(messages.Challenge) | ||||||
| 	return | 	cm.Signature = []byte("NTLMSSP\x00") | ||||||
|  | 	cm.MessageType = uint32(2) | ||||||
|  | 	cm.TargetName,_ = messages.CreateBytePayload(make([]byte, 0)) | ||||||
|  | 
 | ||||||
|  | 	flags := uint32(0) | ||||||
|  | 	flags = messages.NTLMSSP_NEGOTIATE_KEY_EXCH.Set(flags) | ||||||
|  |   // NOTE: Unsetting this in order for the signatures to work | ||||||
|  |   // flags = messages.NTLMSSP_NEGOTIATE_VERSION.Set(flags) | ||||||
|  |   flags = messages.NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY.Set(flags) | ||||||
|  | 	flags = messages.NTLMSSP_NEGOTIATE_TARGET_INFO.Set(flags) | ||||||
|  | 	flags = messages.NTLMSSP_NEGOTIATE_IDENTIFY.Set(flags) | ||||||
|  | 	flags = messages.NTLMSSP_NEGOTIATE_ALWAYS_SIGN.Set(flags) | ||||||
|  | 	flags = messages.NTLMSSP_NEGOTIATE_NTLM.Set(flags) | ||||||
|  | 	flags = messages.NTLMSSP_NEGOTIATE_DATAGRAM.Set(flags) | ||||||
|  | 	flags = messages.NTLMSSP_NEGOTIATE_SIGN.Set(flags) | ||||||
|  | 	flags = messages.NTLMSSP_REQUEST_TARGET.Set(flags) | ||||||
|  | 	flags = messages.NTLMSSP_NEGOTIATE_UNICODE.Set(flags) | ||||||
|  | 	cm.NegotiateFlags = flags | ||||||
|  | 
 | ||||||
|  | 	cm.ServerChallenge = randomBytes(8) | ||||||
|  | 	cm.Reserved = make([]byte, 8) | ||||||
|  | 	 | ||||||
|  | 	// Create the AvPairs we need | ||||||
|  | 	pairs := new(messages.AvPairs) | ||||||
|  | 	pairs.AddAvPair(messages.MsvAvNbDomainName, messages.StringToUtf16("REUTERS")) | ||||||
|  | 	pairs.AddAvPair(messages.MsvAvNbComputerName, messages.StringToUtf16("UKBP-CBTRMFE06")) | ||||||
|  | 	pairs.AddAvPair(messages.MsvAvDnsDomainName, messages.StringToUtf16("Reuters.net")) | ||||||
|  | 	pairs.AddAvPair(messages.MsvAvDnsComputerName, messages.StringToUtf16("ukbp-cbtrmfe06.Reuters.net")) | ||||||
|  |   pairs.AddAvPair(messages.MsvAvDnsTreeName, messages.StringToUtf16("Reuters.net")) | ||||||
|  | 	pairs.AddAvPair(messages.MsvAvEOL, make([]byte, 0)) | ||||||
|  | 	cm.TargetInfo = pairs | ||||||
|  |   cm.TargetInfoPayloadStruct,_ = messages.CreateBytePayload(pairs.Bytes()) | ||||||
|  | 
 | ||||||
|  | 	cm.Version = &messages.VersionStruct{ProductMajorVersion: uint8(5), ProductMinorVersion: uint8(1), ProductBuild: uint16(2600), NTLMRevisionCurrent: uint8(10)} | ||||||
|  | 	return cm, nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (n *V2ServerSession) ProcessAuthenticateMessage(am *messages.Authenticate) (err error) { | func (n *V2ServerSession) ProcessAuthenticateMessage(am *messages.Authenticate) (err error) { | ||||||
|  | |||||||
| @ -62,14 +62,14 @@ func TestNTLMv2(t *testing.T) { | |||||||
| 	challengeMessageBytes, _ := hex.DecodeString("4e544c4d53535000020000000c000c003800000033828ae20123456789abcdef00000000000000002400240044000000060070170000000f53006500720076006500720002000c0044006f006d00610069006e0001000c0053006500720076006500720000000000") | 	challengeMessageBytes, _ := hex.DecodeString("4e544c4d53535000020000000c000c003800000033828ae20123456789abcdef00000000000000002400240044000000060070170000000f53006500720076006500720002000c0044006f006d00610069006e0001000c0053006500720076006500720000000000") | ||||||
| 	challengeMessage, err := messages.ParseChallengeMessage(challengeMessageBytes) | 	challengeMessage, err := messages.ParseChallengeMessage(challengeMessageBytes) | ||||||
| 	if err == nil { | 	if err == nil { | ||||||
| 		challengeMessage.String() | 	        challengeMessage.String() | ||||||
| 	} else { | 	} else { | ||||||
| 		t.Errorf("Could not parse challenge message: %s", err) | 	        t.Errorf("Could not parse challenge message: %s", err) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	err = client.ProcessChallengeMessage(challengeMessage) | 	err = client.ProcessChallengeMessage(challengeMessage) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		t.Errorf("Could not process challenge message: %s", err) | 	        t.Errorf("Could not process challenge message: %s", err) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	server := new(V2ServerSession) | 	server := new(V2ServerSession) | ||||||
| @ -113,4 +113,16 @@ func TestNTLMv2(t *testing.T) { | |||||||
| 
 | 
 | ||||||
| 	checkV2Value(t, "client seal key", server.clientSealingKey, "59f600973cc4960a25480a7c196e4c58", nil) | 	checkV2Value(t, "client seal key", server.clientSealingKey, "59f600973cc4960a25480a7c196e4c58", nil) | ||||||
| 	checkV2Value(t, "client seal key", server.clientSigningKey, "4788dc861b4782f35d43fd98fe1a2d39", nil) | 	checkV2Value(t, "client seal key", server.clientSigningKey, "4788dc861b4782f35d43fd98fe1a2d39", nil) | ||||||
|  | 	 | ||||||
|  | 	// Have the server generate an initial challenge message | ||||||
|  | 	challenge, err := server.GenerateChallengeMessage() | ||||||
|  | 	challenge.String() | ||||||
|  | 
 | ||||||
|  |   // Have the client process this server challenge message | ||||||
|  | 	client = new(V2ClientSession) | ||||||
|  | 	client.SetUserInfo("User", "Password", "Domain") | ||||||
|  | 	err = client.ProcessChallengeMessage(challenge) | ||||||
|  | 	if err != nil { | ||||||
|  | 	  t.Errorf("Could not process server generated challenge message: %s", err) | ||||||
|  | 	} | ||||||
| } | } | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user