NTLM: Improved CHALLENGE_MESSAGE implementation

This commit is contained in:
Tal Aloni 2017-09-01 23:13:26 +03:00
parent 7610056a0b
commit 3ce1ca6a30
3 changed files with 35 additions and 24 deletions

View file

@ -13,36 +13,44 @@ namespace SMBLibrary.Authentication.NTLM
{
public class AVPairUtils
{
public static byte[] GetAVPairSequence(string domainName, string computerName)
public static KeyValuePairList<AVPairKey, byte[]> GetAVPairSequence(string domainName, string computerName)
{
KeyValuePairList<AVPairKey, byte[]> pairs = new KeyValuePairList<AVPairKey, byte[]>();
pairs.Add(AVPairKey.NbDomainName, UnicodeEncoding.Unicode.GetBytes(domainName));
pairs.Add(AVPairKey.NbComputerName, UnicodeEncoding.Unicode.GetBytes(computerName));
return AVPairUtils.GetAVPairSequenceBytes(pairs);
return pairs;
}
public static byte[] GetAVPairSequenceBytes(KeyValuePairList<AVPairKey, byte[]> pairs)
{
int length = 0;
int length = GetAVPairSequenceLength(pairs);
byte[] result = new byte[length];
int offset = 0;
WriteAVPairSequence(result, ref offset, pairs);
return result;
}
public static int GetAVPairSequenceLength(KeyValuePairList<AVPairKey, byte[]> pairs)
{
int length = 0;
foreach (KeyValuePair<AVPairKey, byte[]> pair in pairs)
{
length += 4 + pair.Value.Length;
}
length += 4;
return length + 4;
}
byte[] result = new byte[length];
int offset = 0;
foreach (KeyValuePair<AVPairKey, byte[]> pair in pairs)
public static void WriteAVPairSequence(byte[] buffer, ref int offset, KeyValuePairList<AVPairKey, byte[]> pairs)
{
foreach (KeyValuePair<AVPairKey, byte[]> pair in pairs)
{
WriteAVPair(result, ref offset, pair.Key, pair.Value);
WriteAVPair(buffer, ref offset, pair.Key, pair.Value);
}
LittleEndianWriter.WriteUInt16(result, ref offset, (ushort)AVPairKey.EOL);
LittleEndianWriter.WriteUInt16(result, ref offset, 0);
LittleEndianWriter.WriteUInt16(buffer, ref offset, (ushort)AVPairKey.EOL);
LittleEndianWriter.WriteUInt16(buffer, ref offset, 0);
}
return result;
}
public static void WriteAVPair(byte[] buffer, ref int offset, AVPairKey key, byte[] value)
private static void WriteAVPair(byte[] buffer, ref int offset, AVPairKey key, byte[] value)
{
LittleEndianWriter.WriteUInt16(buffer, ref offset, (ushort)key);
LittleEndianWriter.WriteUInt16(buffer, ref offset, (ushort)value.Length);
@ -63,7 +71,7 @@ namespace SMBLibrary.Authentication.NTLM
return result;
}
public static KeyValuePair<AVPairKey, byte[]> ReadAVPair(byte[] buffer, ref int offset)
private static KeyValuePair<AVPairKey, byte[]> ReadAVPair(byte[] buffer, ref int offset)
{
AVPairKey key = (AVPairKey)LittleEndianReader.ReadUInt16(buffer, ref offset);
ushort length = LittleEndianReader.ReadUInt16(buffer, ref offset);

View file

@ -22,7 +22,7 @@ namespace SMBLibrary.Authentication.NTLM
public NegotiateFlags NegotiateFlags;
public byte[] ServerChallenge; // 8 bytes
// Reserved - 8 bytes
public byte[] TargetInfo; // sequence of AV_PAIR structures
public KeyValuePairList<AVPairKey, byte[]> TargetInfo = new KeyValuePairList<AVPairKey,byte[]>();
public NTLMVersion Version;
public ChallengeMessage()
@ -39,7 +39,11 @@ namespace SMBLibrary.Authentication.NTLM
NegotiateFlags = (NegotiateFlags)LittleEndianConverter.ToUInt32(buffer, 20);
ServerChallenge = ByteReader.ReadBytes(buffer, 24, 8);
// Reserved
TargetInfo = AuthenticationMessageUtils.ReadBufferPointer(buffer, 40);
byte[] targetInfoBytes = AuthenticationMessageUtils.ReadBufferPointer(buffer, 40);
if (targetInfoBytes.Length > 0)
{
TargetInfo = AVPairUtils.ReadAVPairSequence(targetInfoBytes, 0);
}
if ((NegotiateFlags & NegotiateFlags.Version) > 0)
{
Version = new NTLMVersion(buffer, 48);
@ -53,9 +57,10 @@ namespace SMBLibrary.Authentication.NTLM
TargetName = String.Empty;
}
byte[] targetInfoBytes = AVPairUtils.GetAVPairSequenceBytes(TargetInfo);
if ((NegotiateFlags & NegotiateFlags.TargetInfo) == 0)
{
TargetInfo = new byte[0];
targetInfoBytes = new byte[0];
}
int fixedLength = 48;
@ -63,7 +68,7 @@ namespace SMBLibrary.Authentication.NTLM
{
fixedLength += 8;
}
int payloadLength = TargetName.Length * 2 + TargetInfo.Length;
int payloadLength = TargetName.Length * 2 + targetInfoBytes.Length;
byte[] buffer = new byte[fixedLength + payloadLength];
ByteWriter.WriteAnsiString(buffer, 0, AuthenticateMessage.ValidSignature, 8);
LittleEndianWriter.WriteUInt32(buffer, 8, (uint)MessageType);
@ -77,8 +82,8 @@ namespace SMBLibrary.Authentication.NTLM
int offset = fixedLength;
AuthenticationMessageUtils.WriteBufferPointer(buffer, 12, (ushort)(TargetName.Length * 2), (uint)offset);
ByteWriter.WriteUTF16String(buffer, ref offset, TargetName);
AuthenticationMessageUtils.WriteBufferPointer(buffer, 40, (ushort)TargetInfo.Length, (uint)offset);
ByteWriter.WriteBytes(buffer, ref offset, TargetInfo);
AuthenticationMessageUtils.WriteBufferPointer(buffer, 40, (ushort)targetInfoBytes.Length, (uint)offset);
ByteWriter.WriteBytes(buffer, ref offset, targetInfoBytes);
return buffer;
}

View file

@ -99,8 +99,7 @@ namespace SMBLibrary
message.Version = new NTLMVersion(6, 0, 6000, NTLMVersion.NTLMSSP_REVISION_W2K3);
message.NegotiateFlags = NegotiateFlags.UnicodeEncoding | NegotiateFlags.OEMEncoding | NegotiateFlags.TargetNameSupplied | NegotiateFlags.Sign | NegotiateFlags.Seal | NegotiateFlags.NTLMSessionSecurity | NegotiateFlags.AlwaysSign | NegotiateFlags.TargetTypeServer | NegotiateFlags.ExtendedSessionSecurity | NegotiateFlags.TargetInfo | NegotiateFlags.Version | NegotiateFlags.Use128BitEncryption | NegotiateFlags.KeyExchange | NegotiateFlags.Use56BitEncryption;
message.TargetName = "Server";
byte[] serverAVPair = AVPairUtils.GetAVPairSequence("Domain", "Server");
message.TargetInfo = serverAVPair;
message.TargetInfo = AVPairUtils.GetAVPairSequence("Domain", "Server");
byte[] messageBytes = message.GetBytes();
bool success = ByteUtils.AreByteArraysEqual(expected, messageBytes);
@ -130,7 +129,6 @@ namespace SMBLibrary
byte[] sessionKey = {0xc5, 0xda, 0xd2, 0x54, 0x4f, 0xc9, 0x79, 0x90, 0x94, 0xce, 0x1c, 0xe9, 0x0b, 0xc9, 0xd0, 0x3e};
byte[] serverChallenge = new byte[] { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef };
byte[] clientChallenge = new byte[] { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa };
byte[] serverAVPair = AVPairUtils.GetAVPairSequence("Domain", "Server");
DateTime time = DateTime.FromFileTimeUtc(0); // same as new byte[8]
NTLMv2ClientChallenge clientChallengeStructure = new NTLMv2ClientChallenge(time, clientChallenge, "Domain", "Server");
byte[] clientChallengeStructurePadded = clientChallengeStructure.GetBytesPadded();