为什么 CDOSYS 向我发送带有 56 字节响应的类型 3 消息?
Why is CDOSYS sending me a type 3 message with a 56 byte response?
我有一些非常旧的代码,我想使用 CDO.Message 对象。许多年前,我认为这段代码确实有效(Windows 98?),但后来它从 Windows XP 开始不起作用(现在我在 Windows 10)。
我的代码首先检查 sResponse2.cLength,如果是 24,则执行 NTLM 计算。如果做不到这一点,如果 sResponse1.cLength 也是 24,那么它会改为执行 LM 计算。这就是我曾经实施过的所有内容。
今天,通过 CDO.Message 测试,它采用了 LM 代码路径,并且我的代码计算的哈希值与 CDO.Message 提供的不匹配。那是另一个问题。
我现在比较感兴趣的是为什么sResponse2.cLength是56。56的值表示什么?鉴于该值和标志,我是否应该使用不同的算法测试类型 3 消息响应?
当我向客户端发送类型 2 消息时,我只指定了这两个标志:
#define F_NEGOTIATE_OEM 0x00000002
#define F_NEGOTIATE_NTLM 0x00000200
响应大于 24 个字节,因为它是 NTLMv2 响应。这 56 个字节包括 16 字节的 HMAC-MD5 哈希、一个 blob 签名、两个“保留”字段、一个 8 字节的时间戳、一个 8 字节的客户端随机数和可变长度目标数据(在本例中为 12 字节的开销). 56 字节可能是空目标 server/domain 字符串的最小可能大小。
如果它是 24 个字节,它可能是 NTLMv2 会话响应,这是不同的。
可在此处找到详细信息:
http://davenport.sourceforge.net/ntlm.html
我创建了以下代码来解析 NTLMv2 响应:
struct TYPE3_BLOCK
{
const BYTE* pcbHash; // 16 bytes
const BYTE* pcbBlockPtr; // Points to the block after the hash
DWORD cbBlockPtr;
DWORD dwSignature;
FILETIME ftStamp;
const BYTE* pcbNonce; // 8 bytes
DWORD dwReserved1;
DWORD dwReserved2;
const BYTE* pcbTarget; // Remainder, less dwReserved2
DWORD cbTarget;
};
template <typename T>
BOOL TConsumePtr (const BYTE*& pcbData, DWORD& cbData, T** pptPtr, DWORD cbPtr)
{
if(cbData >= cbPtr)
{
*pptPtr = reinterpret_cast<T*>(pcbData);
pcbData += cbPtr;
cbData -= cbPtr;
return TRUE;
}
return FALSE;
}
template <typename T>
BOOL TConsumeData (const BYTE*& pcbData, DWORD& cbData, T* ptPtr)
{
if(cbData >= sizeof(T))
{
CopyMemory(ptPtr, pcbData, sizeof(T));
pcbData += sizeof(T);
cbData -= sizeof(T);
return TRUE;
}
return FALSE;
}
BOOL CrackType3Response (const BYTE* pcbResponse, DWORD cbResponse, __out TYPE3_BLOCK* pBlock)
{
if(TConsumePtr(pcbResponse, cbResponse, &pBlock->pcbHash, 16))
{
pBlock->pcbBlockPtr = pcbResponse;
pBlock->cbBlockPtr = cbResponse;
if(TConsumeData(pcbResponse, cbResponse, &pBlock->dwSignature) &&
TConsumeData(pcbResponse, cbResponse, &pBlock->dwReserved1) &&
TConsumeData(pcbResponse, cbResponse, &pBlock->ftStamp) &&
TConsumePtr(pcbResponse, cbResponse, &pBlock->pcbNonce, 8))
{
pBlock->cbTarget = cbResponse - sizeof(pBlock->dwReserved2);
return TConsumePtr(pcbResponse, cbResponse, &pBlock->pcbTarget, pBlock->cbTarget) &&
TConsumeData(pcbResponse, cbResponse, &pBlock->dwReserved2);
}
}
return FALSE;
}
我有一些非常旧的代码,我想使用 CDO.Message 对象。许多年前,我认为这段代码确实有效(Windows 98?),但后来它从 Windows XP 开始不起作用(现在我在 Windows 10)。
我的代码首先检查 sResponse2.cLength,如果是 24,则执行 NTLM 计算。如果做不到这一点,如果 sResponse1.cLength 也是 24,那么它会改为执行 LM 计算。这就是我曾经实施过的所有内容。
今天,通过 CDO.Message 测试,它采用了 LM 代码路径,并且我的代码计算的哈希值与 CDO.Message 提供的不匹配。那是另一个问题。
我现在比较感兴趣的是为什么sResponse2.cLength是56。56的值表示什么?鉴于该值和标志,我是否应该使用不同的算法测试类型 3 消息响应?
当我向客户端发送类型 2 消息时,我只指定了这两个标志:
#define F_NEGOTIATE_OEM 0x00000002
#define F_NEGOTIATE_NTLM 0x00000200
响应大于 24 个字节,因为它是 NTLMv2 响应。这 56 个字节包括 16 字节的 HMAC-MD5 哈希、一个 blob 签名、两个“保留”字段、一个 8 字节的时间戳、一个 8 字节的客户端随机数和可变长度目标数据(在本例中为 12 字节的开销). 56 字节可能是空目标 server/domain 字符串的最小可能大小。
如果它是 24 个字节,它可能是 NTLMv2 会话响应,这是不同的。
可在此处找到详细信息: http://davenport.sourceforge.net/ntlm.html
我创建了以下代码来解析 NTLMv2 响应:
struct TYPE3_BLOCK
{
const BYTE* pcbHash; // 16 bytes
const BYTE* pcbBlockPtr; // Points to the block after the hash
DWORD cbBlockPtr;
DWORD dwSignature;
FILETIME ftStamp;
const BYTE* pcbNonce; // 8 bytes
DWORD dwReserved1;
DWORD dwReserved2;
const BYTE* pcbTarget; // Remainder, less dwReserved2
DWORD cbTarget;
};
template <typename T>
BOOL TConsumePtr (const BYTE*& pcbData, DWORD& cbData, T** pptPtr, DWORD cbPtr)
{
if(cbData >= cbPtr)
{
*pptPtr = reinterpret_cast<T*>(pcbData);
pcbData += cbPtr;
cbData -= cbPtr;
return TRUE;
}
return FALSE;
}
template <typename T>
BOOL TConsumeData (const BYTE*& pcbData, DWORD& cbData, T* ptPtr)
{
if(cbData >= sizeof(T))
{
CopyMemory(ptPtr, pcbData, sizeof(T));
pcbData += sizeof(T);
cbData -= sizeof(T);
return TRUE;
}
return FALSE;
}
BOOL CrackType3Response (const BYTE* pcbResponse, DWORD cbResponse, __out TYPE3_BLOCK* pBlock)
{
if(TConsumePtr(pcbResponse, cbResponse, &pBlock->pcbHash, 16))
{
pBlock->pcbBlockPtr = pcbResponse;
pBlock->cbBlockPtr = cbResponse;
if(TConsumeData(pcbResponse, cbResponse, &pBlock->dwSignature) &&
TConsumeData(pcbResponse, cbResponse, &pBlock->dwReserved1) &&
TConsumeData(pcbResponse, cbResponse, &pBlock->ftStamp) &&
TConsumePtr(pcbResponse, cbResponse, &pBlock->pcbNonce, 8))
{
pBlock->cbTarget = cbResponse - sizeof(pBlock->dwReserved2);
return TConsumePtr(pcbResponse, cbResponse, &pBlock->pcbTarget, pBlock->cbTarget) &&
TConsumeData(pcbResponse, cbResponse, &pBlock->dwReserved2);
}
}
return FALSE;
}