The response was greater than 24 bytes because it was an NTLMv2 response. The 56 bytes include the 16-byte HMAC-MD5 hash, a blob signature, two "reserved" fields, an 8-byte time stamp, an 8-byte client nonce, and variable length target data (12 bytes of overhead in this case). 56 bytes may be the minimum possible size with an empty target server/domain string.
Had it been 24 bytes, it could have instead been an NTLMv2 Session Response, which is different.
Details can be found here:
http://davenport.sourceforge.net/ntlm.html
I've created the following code to parse the NTLMv2 response:
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;
}