NTSTATUS SMB2PacketVerifySignature( PSMB_PACKET pPacket, PBYTE pSessionKey, ULONG ulSessionKeyLength ) { NTSTATUS ntStatus = 0; if (pSessionKey) { BYTE sessionKey[16]; PBYTE pBuffer = pPacket->pRawBuffer + sizeof(NETBIOS_HEADER); ULONG ulBytesAvailable = pPacket->pNetBIOSHeader->len; uint8_t origSignature[16]; UCHAR ucDigest[EVP_MAX_MD_SIZE]; ULONG ulDigest = sizeof(ucDigest); if (!pBuffer) { ntStatus = STATUS_INVALID_NETWORK_RESPONSE; BAIL_ON_NT_STATUS(ntStatus); } memset(&sessionKey[0], 0, sizeof(sessionKey)); memcpy(&sessionKey[0], pSessionKey, SMB_MIN(ulSessionKeyLength, sizeof(sessionKey))); while (pBuffer) { PSMB2_HEADER pHeader = NULL; ULONG ulPacketSize = ulBytesAvailable; if (ulBytesAvailable < sizeof(SMB2_HEADER)) { ntStatus = STATUS_INVALID_NETWORK_RESPONSE; BAIL_ON_NT_STATUS(ntStatus); } pHeader = (PSMB2_HEADER)pBuffer; if (pHeader->ulChainOffset) { if (ulBytesAvailable < pHeader->ulChainOffset) { ntStatus = STATUS_INVALID_NETWORK_RESPONSE; BAIL_ON_NT_STATUS(ntStatus); } ulPacketSize = pHeader->ulChainOffset; } memcpy(origSignature, &pHeader->signature[0], sizeof(pHeader->signature)); memset(&pHeader->signature[0], 0, sizeof(pHeader->signature)); HMAC(EVP_sha256(), &sessionKey[0], sizeof(sessionKey), pBuffer, ulPacketSize, &ucDigest[0], &ulDigest); if (memcmp(&origSignature[0], &ucDigest[0], sizeof(origSignature))) { ntStatus = STATUS_INVALID_NETWORK_RESPONSE; } // restore signature memcpy(&pHeader->signature[0], &origSignature[0], sizeof(origSignature)); BAIL_ON_NT_STATUS(ntStatus); if (pHeader->ulChainOffset) { pBuffer += pHeader->ulChainOffset; ulBytesAvailable -= pHeader->ulChainOffset; } else { pBuffer = NULL; } } } cleanup: return ntStatus; error: LWIO_LOG_WARNING("SMB2 Packet verification failed (status = 0x%08X)", ntStatus); goto cleanup; }
static VOID RdrNegotiateGssContextWorkItem( PVOID pParam ) { NTSTATUS status = STATUS_SUCCESS; PRDR_OP_CONTEXT pContext = pParam; PRDR_SESSION pSession = pContext->State.TreeConnect.pSession; PRDR_SOCKET pSocket = pSession->pSocket; PSMB_PACKET pPacket = pContext->State.TreeConnect.pPacket; PWSTR pwszNativeOS = NULL; PWSTR pwszNativeLanman = NULL; PWSTR pwszNativeDomain = NULL; PBYTE pInBlob = NULL; DWORD dwInBlobLength = 0; PBYTE pOutBlob = NULL; DWORD dwOutBlobLength = 0; PSESSION_SETUP_RESPONSE_HEADER_WC_4 pResponseHeader = NULL; BOOLEAN bSessionLocked = FALSE; if (pPacket) { status = UnmarshallSessionSetupResponse_WC_4( pPacket->pParams, pPacket->bufferLen - pPacket->bufferUsed, 0, &pResponseHeader, &pInBlob, &pwszNativeOS, &pwszNativeLanman, &pwszNativeDomain); BAIL_ON_NT_STATUS(status); dwInBlobLength = pResponseHeader->securityBlobLength; } else { pInBlob = pSession->pSocket->pSecurityBlob; dwInBlobLength = pSession->pSocket->securityBlobLen; } if (pContext->State.TreeConnect.pszCachePath) { status = SMBKrb5SetDefaultCachePath( pContext->State.TreeConnect.pszCachePath, NULL); BAIL_ON_NT_STATUS(status); } if (!pContext->State.TreeConnect.hGssContext) { status = SMBGSSContextBuild( pSocket->pwszCanonicalName, pContext->State.TreeConnect.pCreds, &pContext->State.TreeConnect.hGssContext); BAIL_ON_NT_STATUS(status); } status = SMBGSSContextNegotiate( pContext->State.TreeConnect.hGssContext, pInBlob, dwInBlobLength, &pOutBlob, &dwOutBlobLength); BAIL_ON_NT_STATUS(status); if (!SMBGSSContextNegotiateComplete(pContext->State.TreeConnect.hGssContext)) { pContext->Continue = RdrProcessSessionSetupResponse; status = RdrTransceiveSessionSetup( pContext, pSession, pOutBlob, dwOutBlobLength); BAIL_ON_NT_STATUS(status); } else { LWIO_LOCK_MUTEX(bSessionLocked, &pSession->mutex); if (pContext->Packet.haveSignature && (!memcmp(pPacket->pSMBHeader->extra.securitySignature, pContext->Packet.pSMBHeader->extra.securitySignature, sizeof(pContext->Packet.pSMBHeader->extra.securitySignature)))) { LWIO_LOG_WARNING("Server is exhibiting signing bug; ignoring signatures from server"); RdrSocketSetIgnoreServerSignatures(pSocket, TRUE); } status = SMBGSSContextGetSessionKey( pContext->State.TreeConnect.hGssContext, &pSession->pSessionKey, &pSession->dwSessionKeyLength); BAIL_ON_NT_STATUS(status); if (!pSocket->pSessionKey && pSession->pSessionKey && !(pContext->State.TreeConnect.pCreds->type == IO_CREDS_TYPE_PLAIN && pContext->State.TreeConnect.pCreds->payload.plain.pwszUsername[0] == '\0')) { status = LwIoAllocateMemory( pSession->dwSessionKeyLength, OUT_PPVOID(&pSocket->pSessionKey)); BAIL_ON_NT_STATUS(status); memcpy(pSocket->pSessionKey, pSession->pSessionKey, pSession->dwSessionKeyLength); pSocket->dwSessionKeyLength = pSession->dwSessionKeyLength; RdrSocketBeginSequence(pSocket); } status = RdrSocketAddSessionByUID(pSocket, pSession); BAIL_ON_NT_STATUS(status); pSession->state = RDR_SESSION_STATE_READY; RdrNotifyContextList( &pSession->StateWaiters, bSessionLocked, &pSession->mutex, status, pSession); LWIO_UNLOCK_MUTEX(bSessionLocked, &pSession->mutex); RdrSessionSetupComplete(pContext, status, pSession); status = STATUS_PENDING; BAIL_ON_NT_STATUS(status); } cleanup: LWIO_UNLOCK_MUTEX(bSessionLocked, &pSession->mutex); RTL_FREE(&pOutBlob); if (status != STATUS_PENDING) { if (pContext->State.TreeConnect.hGssContext) { SMBGSSContextFree(pContext->State.TreeConnect.hGssContext); } RdrSessionInvalidate(pSession, status); RdrSessionRelease(pSession); RdrSessionSetupComplete(pContext, status, NULL); } return; error: goto cleanup; }
NTSTATUS SMBPacketVerifySignature( PSMB_PACKET pPacket, ULONG ulExpectedSequence, PBYTE pSessionKey, ULONG ulSessionKeyLength ) { NTSTATUS ntStatus = 0; uint8_t digest[16]; uint8_t origSignature[8]; MD5_CTX md5Value; uint32_t littleEndianSequence = SMB_HTOL32(ulExpectedSequence); assert (sizeof(origSignature) == sizeof(pPacket->pSMBHeader->extra.securitySignature)); memcpy(origSignature, pPacket->pSMBHeader->extra.securitySignature, sizeof(pPacket->pSMBHeader->extra.securitySignature)); memset(&pPacket->pSMBHeader->extra.securitySignature[0], 0, sizeof(pPacket->pSMBHeader->extra.securitySignature)); memcpy(&pPacket->pSMBHeader->extra.securitySignature[0], &littleEndianSequence, sizeof(littleEndianSequence)); MD5_Init(&md5Value); if (pSessionKey) { MD5_Update(&md5Value, pSessionKey, ulSessionKeyLength); } MD5_Update(&md5Value, (PBYTE)pPacket->pSMBHeader, pPacket->pNetBIOSHeader->len); MD5_Final(digest, &md5Value); if (memcmp(&origSignature[0], &digest[0], sizeof(origSignature))) { ntStatus = STATUS_INVALID_NETWORK_RESPONSE; } // restore signature memcpy(&pPacket->pSMBHeader->extra.securitySignature[0], &origSignature[0], sizeof(origSignature)); BAIL_ON_NT_STATUS(ntStatus); cleanup: return ntStatus; error: LWIO_LOG_WARNING("SMB Packet verification failed (status = 0x%08X)", ntStatus); goto cleanup; }