generate challenge messages

This commit is contained in:
Conor Hunt 2012-11-10 15:15:12 -05:00
parent a9e17c39f6
commit d5082d0f01
6 changed files with 125 additions and 14 deletions

View File

@ -5,7 +5,6 @@ import (
"encoding/binary"
"encoding/hex"
"fmt"
"reflect"
)
type AvPairType uint16
@ -45,6 +44,11 @@ type AvPairs struct {
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 {
pairs := new(AvPairs)
@ -153,10 +157,26 @@ func (a *AvPair) String() string {
switch a.AvId {
case MsvAvEOL:
outString = "MsvAvEOL"
case MsvAvNbComputerName, MsvAvNbDomainName, MsvAvDnsComputerName, MsvAvDnsDomainName, MsvAvDnsTreeName, MsvAvTargetName:
outString = fmt.Sprintf("%s: %s", reflect.TypeOf(a.AvId).Name(), a.UnicodeStringValue())
case MsvAvFlags, MsvAvTimestamp, MsAvRestrictions, MsvChannelBindings:
outString = fmt.Sprintf("%s: %s", reflect.TypeOf(a.AvId).Name(), hex.EncodeToString(a.Value))
case MsvAvNbComputerName:
outString = "MsAvNbComputerName: " + a.UnicodeStringValue()
case MsvAvNbDomainName:
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:
outString = fmt.Sprintf("unknown pair type: '%d'", a.AvId)
}

View File

@ -95,7 +95,7 @@ func ParseChallengeMessage(body []byte) (*Challenge, error) {
func (c *Challenge) Bytes() []byte {
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)
messageBytes := make([]byte, 0, messageLen+payloadLen)
@ -105,18 +105,21 @@ func (c *Challenge) Bytes() []byte {
binary.Write(buffer, binary.LittleEndian, c.MessageType)
c.TargetName.Offset = payloadOffset
payloadOffset += uint32(c.TargetName.Len)
buffer.Write(c.TargetName.Bytes())
payloadOffset += uint32(c.TargetName.Len)
binary.Write(buffer, binary.LittleEndian, c.NegotiateFlags)
buffer.Write(c.ServerChallenge)
buffer.Write(make([]byte, 8))
c.TargetInfoPayloadStruct.Offset = payloadOffset
payloadOffset += uint32(c.TargetInfoPayloadStruct.Len)
buffer.Write(c.TargetInfoPayloadStruct.Bytes())
payloadOffset += uint32(c.TargetInfoPayloadStruct.Len)
if(c.Version != nil) {
buffer.Write(c.Version.Bytes())
} else {
buffer.Write(make([]byte, 8))
}
// Write out the payloads

View File

@ -46,4 +46,18 @@ func TestDecodeChallenge(t *testing.T) {
}
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")
}
}

View File

@ -138,6 +138,34 @@ func (f NegotiateFlag) String() string {
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 {
allFlags := [...]NegotiateFlag{
NTLMSSP_NEGOTIATE_56,
@ -166,7 +194,7 @@ func FlagsToString(flags uint32) string {
var buffer bytes.Buffer
for i := range allFlags {
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()
}

View File

@ -81,8 +81,42 @@ func (n *V2ServerSession) ProcessNegotiateMessage(nm *messages.Negotiate) (err e
}
func (n *V2ServerSession) GenerateChallengeMessage() (cm *messages.Challenge, err error) {
// TODO: Generate this challenge message
return
cm = new(messages.Challenge)
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) {

View File

@ -62,14 +62,14 @@ func TestNTLMv2(t *testing.T) {
challengeMessageBytes, _ := hex.DecodeString("4e544c4d53535000020000000c000c003800000033828ae20123456789abcdef00000000000000002400240044000000060070170000000f53006500720076006500720002000c0044006f006d00610069006e0001000c0053006500720076006500720000000000")
challengeMessage, err := messages.ParseChallengeMessage(challengeMessageBytes)
if err == nil {
challengeMessage.String()
challengeMessage.String()
} else {
t.Errorf("Could not parse challenge message: %s", err)
t.Errorf("Could not parse challenge message: %s", err)
}
err = client.ProcessChallengeMessage(challengeMessage)
if err != nil {
t.Errorf("Could not process challenge message: %s", err)
t.Errorf("Could not process challenge message: %s", err)
}
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.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)
}
}