mirror of
https://github.com/TalAloni/SMBLibrary.git
synced 2025-08-12 18:29:18 +02:00
NTLM: Improved CHALLENGE_MESSAGE implementation
This commit is contained in:
parent
7610056a0b
commit
3ce1ca6a30
3 changed files with 35 additions and 24 deletions
|
@ -13,36 +13,44 @@ namespace SMBLibrary.Authentication.NTLM
|
||||||
{
|
{
|
||||||
public class AVPairUtils
|
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[]>();
|
KeyValuePairList<AVPairKey, byte[]> pairs = new KeyValuePairList<AVPairKey, byte[]>();
|
||||||
pairs.Add(AVPairKey.NbDomainName, UnicodeEncoding.Unicode.GetBytes(domainName));
|
pairs.Add(AVPairKey.NbDomainName, UnicodeEncoding.Unicode.GetBytes(domainName));
|
||||||
pairs.Add(AVPairKey.NbComputerName, UnicodeEncoding.Unicode.GetBytes(computerName));
|
pairs.Add(AVPairKey.NbComputerName, UnicodeEncoding.Unicode.GetBytes(computerName));
|
||||||
return AVPairUtils.GetAVPairSequenceBytes(pairs);
|
return pairs;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] GetAVPairSequenceBytes(KeyValuePairList<AVPairKey, byte[]> pairs)
|
public static byte[] GetAVPairSequenceBytes(KeyValuePairList<AVPairKey, byte[]> pairs)
|
||||||
|
{
|
||||||
|
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;
|
int length = 0;
|
||||||
foreach (KeyValuePair<AVPairKey, byte[]> pair in pairs)
|
foreach (KeyValuePair<AVPairKey, byte[]> pair in pairs)
|
||||||
{
|
{
|
||||||
length += 4 + pair.Value.Length;
|
length += 4 + pair.Value.Length;
|
||||||
}
|
}
|
||||||
length += 4;
|
return length + 4;
|
||||||
|
}
|
||||||
|
|
||||||
byte[] result = new byte[length];
|
public static void WriteAVPairSequence(byte[] buffer, ref int offset, KeyValuePairList<AVPairKey, byte[]> pairs)
|
||||||
int offset = 0;
|
{
|
||||||
foreach (KeyValuePair<AVPairKey, byte[]> pair in 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(buffer, ref offset, (ushort)AVPairKey.EOL);
|
||||||
LittleEndianWriter.WriteUInt16(result, ref offset, 0);
|
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)key);
|
||||||
LittleEndianWriter.WriteUInt16(buffer, ref offset, (ushort)value.Length);
|
LittleEndianWriter.WriteUInt16(buffer, ref offset, (ushort)value.Length);
|
||||||
|
@ -63,7 +71,7 @@ namespace SMBLibrary.Authentication.NTLM
|
||||||
return result;
|
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);
|
AVPairKey key = (AVPairKey)LittleEndianReader.ReadUInt16(buffer, ref offset);
|
||||||
ushort length = LittleEndianReader.ReadUInt16(buffer, ref offset);
|
ushort length = LittleEndianReader.ReadUInt16(buffer, ref offset);
|
||||||
|
|
|
@ -22,7 +22,7 @@ namespace SMBLibrary.Authentication.NTLM
|
||||||
public NegotiateFlags NegotiateFlags;
|
public NegotiateFlags NegotiateFlags;
|
||||||
public byte[] ServerChallenge; // 8 bytes
|
public byte[] ServerChallenge; // 8 bytes
|
||||||
// Reserved - 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 NTLMVersion Version;
|
||||||
|
|
||||||
public ChallengeMessage()
|
public ChallengeMessage()
|
||||||
|
@ -39,7 +39,11 @@ namespace SMBLibrary.Authentication.NTLM
|
||||||
NegotiateFlags = (NegotiateFlags)LittleEndianConverter.ToUInt32(buffer, 20);
|
NegotiateFlags = (NegotiateFlags)LittleEndianConverter.ToUInt32(buffer, 20);
|
||||||
ServerChallenge = ByteReader.ReadBytes(buffer, 24, 8);
|
ServerChallenge = ByteReader.ReadBytes(buffer, 24, 8);
|
||||||
// Reserved
|
// 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)
|
if ((NegotiateFlags & NegotiateFlags.Version) > 0)
|
||||||
{
|
{
|
||||||
Version = new NTLMVersion(buffer, 48);
|
Version = new NTLMVersion(buffer, 48);
|
||||||
|
@ -53,9 +57,10 @@ namespace SMBLibrary.Authentication.NTLM
|
||||||
TargetName = String.Empty;
|
TargetName = String.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
byte[] targetInfoBytes = AVPairUtils.GetAVPairSequenceBytes(TargetInfo);
|
||||||
if ((NegotiateFlags & NegotiateFlags.TargetInfo) == 0)
|
if ((NegotiateFlags & NegotiateFlags.TargetInfo) == 0)
|
||||||
{
|
{
|
||||||
TargetInfo = new byte[0];
|
targetInfoBytes = new byte[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
int fixedLength = 48;
|
int fixedLength = 48;
|
||||||
|
@ -63,7 +68,7 @@ namespace SMBLibrary.Authentication.NTLM
|
||||||
{
|
{
|
||||||
fixedLength += 8;
|
fixedLength += 8;
|
||||||
}
|
}
|
||||||
int payloadLength = TargetName.Length * 2 + TargetInfo.Length;
|
int payloadLength = TargetName.Length * 2 + targetInfoBytes.Length;
|
||||||
byte[] buffer = new byte[fixedLength + payloadLength];
|
byte[] buffer = new byte[fixedLength + payloadLength];
|
||||||
ByteWriter.WriteAnsiString(buffer, 0, AuthenticateMessage.ValidSignature, 8);
|
ByteWriter.WriteAnsiString(buffer, 0, AuthenticateMessage.ValidSignature, 8);
|
||||||
LittleEndianWriter.WriteUInt32(buffer, 8, (uint)MessageType);
|
LittleEndianWriter.WriteUInt32(buffer, 8, (uint)MessageType);
|
||||||
|
@ -77,8 +82,8 @@ namespace SMBLibrary.Authentication.NTLM
|
||||||
int offset = fixedLength;
|
int offset = fixedLength;
|
||||||
AuthenticationMessageUtils.WriteBufferPointer(buffer, 12, (ushort)(TargetName.Length * 2), (uint)offset);
|
AuthenticationMessageUtils.WriteBufferPointer(buffer, 12, (ushort)(TargetName.Length * 2), (uint)offset);
|
||||||
ByteWriter.WriteUTF16String(buffer, ref offset, TargetName);
|
ByteWriter.WriteUTF16String(buffer, ref offset, TargetName);
|
||||||
AuthenticationMessageUtils.WriteBufferPointer(buffer, 40, (ushort)TargetInfo.Length, (uint)offset);
|
AuthenticationMessageUtils.WriteBufferPointer(buffer, 40, (ushort)targetInfoBytes.Length, (uint)offset);
|
||||||
ByteWriter.WriteBytes(buffer, ref offset, TargetInfo);
|
ByteWriter.WriteBytes(buffer, ref offset, targetInfoBytes);
|
||||||
|
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
|
@ -99,8 +99,7 @@ namespace SMBLibrary
|
||||||
message.Version = new NTLMVersion(6, 0, 6000, NTLMVersion.NTLMSSP_REVISION_W2K3);
|
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.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";
|
message.TargetName = "Server";
|
||||||
byte[] serverAVPair = AVPairUtils.GetAVPairSequence("Domain", "Server");
|
message.TargetInfo = AVPairUtils.GetAVPairSequence("Domain", "Server");
|
||||||
message.TargetInfo = serverAVPair;
|
|
||||||
|
|
||||||
byte[] messageBytes = message.GetBytes();
|
byte[] messageBytes = message.GetBytes();
|
||||||
bool success = ByteUtils.AreByteArraysEqual(expected, messageBytes);
|
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[] 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[] serverChallenge = new byte[] { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef };
|
||||||
byte[] clientChallenge = new byte[] { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa };
|
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]
|
DateTime time = DateTime.FromFileTimeUtc(0); // same as new byte[8]
|
||||||
NTLMv2ClientChallenge clientChallengeStructure = new NTLMv2ClientChallenge(time, clientChallenge, "Domain", "Server");
|
NTLMv2ClientChallenge clientChallengeStructure = new NTLMv2ClientChallenge(time, clientChallenge, "Domain", "Server");
|
||||||
byte[] clientChallengeStructurePadded = clientChallengeStructure.GetBytesPadded();
|
byte[] clientChallengeStructurePadded = clientChallengeStructure.GetBytesPadded();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue