diff --git a/src/app-layer-dcerpc.c b/src/app-layer-dcerpc.c index 070f9c8f7b..8b7b9befe3 100644 --- a/src/app-layer-dcerpc.c +++ b/src/app-layer-dcerpc.c @@ -1067,10 +1067,10 @@ static int DCERPCParseHeader(DCERPC *dcerpc, uint8_t *input, uint32_t input_len) break; case 15: dcerpc->dcerpchdr.call_id |= *(p++); - if (dcerpc->dcerpchdr.packed_drep[0] == 0x01) { - SCByteSwap16(dcerpc->dcerpchdr.frag_length); - SCByteSwap16(dcerpc->dcerpchdr.auth_length); - SCByteSwap32(dcerpc->dcerpchdr.call_id); + if (dcerpc->dcerpchdr.packed_drep[0] == 0x10) { + dcerpc->dcerpchdr.frag_length = SCByteSwap16(dcerpc->dcerpchdr.frag_length); + dcerpc->dcerpchdr.auth_length = SCByteSwap16(dcerpc->dcerpchdr.auth_length); + dcerpc->dcerpchdr.call_id = SCByteSwap32(dcerpc->dcerpchdr.call_id); } --input_len; break; @@ -1354,6 +1354,10 @@ int32_t DCERPCParser(DCERPC *dcerpc, uint8_t *input, uint32_t input_len) { SCLogDebug("DCERPC Type 0x%02x not implemented yet", dcerpc->dcerpchdr.type); dcerpc->bytesprocessed = 0; dcerpc->pdu_fragged = 0; + /* reset type to REQUEST. Yeah, that's cool. Just like how we would + * otherwise behave if this is the first dce payload the parser is + * seeing */ + dcerpc->dcerpchdr.type = 0; break; } } @@ -3852,6 +3856,92 @@ end: return result; } +/** + * \test DCERPC fragmented PDU. + */ +int DCERPCParserTest07(void) { + int result = 1; + Flow f; + int r = 0; + + uint8_t fault[] = { + 0x05, 0x00, 0x03, 0x03, 0x10, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0xf7, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + uint32_t fault_len = sizeof(fault); + + uint8_t request1[] = { + 0x05, 0x00 + }; + uint32_t request1_len = sizeof(request1); + + uint8_t request2[] = { + 0x00, 0x03, 0x10, 0x00, 0x00, 0x00, 0x24, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x02, + 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, + 0x0B, 0x0C + }; + uint32_t request2_len = sizeof(request2); + + TcpSession ssn; + + memset(&f, 0, sizeof(f)); + memset(&ssn, 0, sizeof(ssn)); + + FLOW_INITIALIZE(&f); + f.protoctx = (void *)&ssn; + + StreamTcpInitConfig(TRUE); + FlowL7DataPtrInit(&f); + + r = AppLayerParse(&f, ALPROTO_DCERPC, STREAM_TOSERVER|STREAM_START, + fault, fault_len); + if (r != 0) { + printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); + result = 0; + goto end; + } + + DCERPCState *dcerpc_state = f.aldata[AlpGetStateIdx(ALPROTO_DCERPC)]; + if (dcerpc_state == NULL) { + printf("no dcerpc state: "); + result = 0; + goto end; + } + + r = AppLayerParse(&f, ALPROTO_DCERPC, STREAM_TOSERVER, + request1, request1_len); + if (r != 0) { + printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); + result = 0; + goto end; + } + + result &= (dcerpc_state->dcerpc.bytesprocessed == 2); + result &= (dcerpc_state->dcerpc.dcerpcrequest.stub_data_buffer == NULL); + + r = AppLayerParse(&f, ALPROTO_DCERPC, STREAM_TOSERVER, + request2, request2_len); + if (r != 0) { + printf("dcerpc header check returned %" PRId32 ", expected 0: ", r); + result = 0; + goto end; + } + + result &= (dcerpc_state->dcerpc.bytesprocessed == 0); + result &= (dcerpc_state->dcerpc.dcerpcrequest.stub_data_buffer != NULL && + dcerpc_state->dcerpc.dcerpcrequest.stub_data_buffer_len == 12); + +end: + FlowL7DataPtrFree(&f); + StreamTcpFreeConfig(TRUE); + FLOW_DESTROY(&f); + return result; +} + void DCERPCParserRegisterTests(void) { printf("DCERPCParserRegisterTests\n"); UtRegisterTest("DCERPCParserTest01", DCERPCParserTest01, 1); @@ -3860,6 +3950,7 @@ void DCERPCParserRegisterTests(void) { UtRegisterTest("DCERPCParserTest04", DCERPCParserTest04, 1); UtRegisterTest("DCERPCParserTest05", DCERPCParserTest05, 1); UtRegisterTest("DCERPCParserTest06", DCERPCParserTest06, 1); + UtRegisterTest("DCERPCParserTest07", DCERPCParserTest07, 1); } #endif