From: Russ Combs (rucombs) Date: Tue, 2 Aug 2016 17:42:47 +0000 (-0400) Subject: Merge pull request #573 in SNORT/snort3 from smb_segmentation to master X-Git-Tag: 3.0.0-233~317 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=9b4b81e;p=thirdparty%2Fsnort3.git Merge pull request #573 in SNORT/snort3 from smb_segmentation to master Squashed commit of the following: commit 3b5cd0bd44a3a79c0c55dca9a3aee990deb1f3f6 Author: mdagon Date: Mon Aug 1 13:48:37 2016 -0400 Smb segmentation port Code review: delete space before **, replace comment with assert --- diff --git a/src/service_inspectors/dce_rpc/dce_co.cc b/src/service_inspectors/dce_rpc/dce_co.cc index 8e1fc3612..baf1591e9 100644 --- a/src/service_inspectors/dce_rpc/dce_co.cc +++ b/src/service_inspectors/dce_rpc/dce_co.cc @@ -30,6 +30,7 @@ #include "log/messages.h" #include "main/snort_debug.h" #include "utils/util.h" +#include THREAD_LOCAL int co_reassembled = 0; @@ -2246,12 +2247,14 @@ static void DCE2_CoSegDecode(DCE2_SsnData* sd, DCE2_CoTracker* cot, DCE2_CoSeg* } static DCE2_Ret DCE2_HandleSegmentation(DCE2_Buffer* seg_buf, const uint8_t* data_ptr, - uint16_t data_len, uint32_t need_len) + uint16_t data_len, uint32_t need_len, uint16_t* data_used) { uint32_t copy_len; DCE2_Ret status; - // FIXIT-L PORT_IF_NEEDED data_used +/* Initialize in case we return early without adding + * any data to the buffer */ + *data_used = 0; if (seg_buf == nullptr) return DCE2_RET__ERROR; @@ -2280,6 +2283,10 @@ static DCE2_Ret DCE2_HandleSegmentation(DCE2_Buffer* seg_buf, const uint8_t* dat if (status != DCE2_RET__SUCCESS) return DCE2_RET__ERROR; + assert (copy_len <= data_len); + + *data_used = (uint16_t)copy_len; + if (DCE2_BufferLength(seg_buf) == need_len) return DCE2_RET__SUCCESS; @@ -2294,7 +2301,7 @@ static DCE2_Ret DCE2_HandleSegmentation(DCE2_Buffer* seg_buf, const uint8_t* dat * ********************************************************************/ static DCE2_Ret DCE2_CoHandleSegmentation(DCE2_SsnData* sd, DCE2_CoSeg* seg, - const uint8_t* data_ptr, uint16_t data_len, uint16_t need_len) + const uint8_t* data_ptr, uint16_t data_len, uint16_t need_len, uint16_t* data_used) { DCE2_Ret status; @@ -2322,7 +2329,7 @@ static DCE2_Ret DCE2_CoHandleSegmentation(DCE2_SsnData* sd, DCE2_CoSeg* seg, } status = DCE2_HandleSegmentation(seg->buf, - data_ptr, data_len, need_len); + data_ptr, data_len, need_len, data_used); return status; } @@ -2359,9 +2366,20 @@ void DCE2_CoProcess(DCE2_SsnData* sd, DCE2_CoTracker* cot, { const uint8_t* frag_ptr = data_ptr; uint16_t frag_len; + uint16_t data_used; + + /* Not enough data left for a header. Buffer it and return */ + if (data_len < sizeof(DceRpcCoHdr)) + { + DebugMessage(DEBUG_DCE_COMMON, + "Not enough data in packet for DCE/RPC Connection-oriented header.\n"); - // FIXIT-L PORT_IF_NEEDED - //Not enough data left for a headerr + DCE2_CoHandleSegmentation(sd, seg, data_ptr, data_len, sizeof(DceRpcCoHdr), + &data_used); + + /* Just break out of loop in case early detect is enabled */ + break; + } if (DCE2_CoHdrChecks(sd, cot, (DceRpcCoHdr*)data_ptr) != DCE2_RET__SUCCESS) return; @@ -2377,7 +2395,7 @@ void DCE2_CoProcess(DCE2_SsnData* sd, DCE2_CoTracker* cot, /* Set frag length so we don't have to check it again in seg code */ seg->frag_len = frag_len; - DCE2_CoHandleSegmentation(sd, seg, data_ptr, data_len, frag_len); + DCE2_CoHandleSegmentation(sd, seg, data_ptr, data_len, frag_len, &data_used); goto dce2_coprocess_exit; } @@ -2398,25 +2416,58 @@ void DCE2_CoProcess(DCE2_SsnData* sd, DCE2_CoTracker* cot, } else /* We've already buffered data */ { + uint16_t data_used = 0; + DebugFormat(DEBUG_DCE_COMMON, "Segmentation buffer has %u bytes\n", DCE2_BufferLength(seg->buf)); - // FIXIT-L PORT_IF_NEEDED - //Need more data to get header + // Need more data to get header + if (DCE2_BufferLength(seg->buf) < sizeof(DceRpcCoHdr)) + { + DCE2_Ret status = DCE2_CoHandleSegmentation(sd, seg, data_ptr, data_len, + sizeof(DceRpcCoHdr), &data_used); + + /* Still not enough for header */ + if (status != DCE2_RET__SUCCESS) + break; + + /* Move the length of the amount of data we used to get header */ + DCE2_MOVE(data_ptr, data_len, data_used); + + if (DCE2_CoHdrChecks(sd, cot, (DceRpcCoHdr*)DCE2_BufferData(seg->buf)) != + DCE2_RET__SUCCESS) + { + int data_back; + DCE2_BufferEmpty(seg->buf); + /* Move back to original packet header */ + data_back = -data_used; + DCE2_MOVE(data_ptr, data_len, data_back); + /*Check the original packet*/ + if (DCE2_CoHdrChecks(sd, cot, (DceRpcCoHdr*)data_ptr) != DCE2_RET__SUCCESS) + return; + else + { + /*Only use the original packet, ignore the data in seg_buffer*/ + num_frags = 0; + continue; + } + } + + seg->frag_len = DceRpcCoFragLen((DceRpcCoHdr*)DCE2_BufferData(seg->buf)); + } /* Need more data for full pdu */ if (DCE2_BufferLength(seg->buf) < seg->frag_len) { DCE2_Ret status = DCE2_CoHandleSegmentation(sd, seg, data_ptr, data_len, - seg->frag_len); + seg->frag_len, &data_used); /* Still not enough */ if (status != DCE2_RET__SUCCESS) - goto dce2_coprocess_exit; - } + break; - // FIXIT-L PORT_IF_NEEDED - // DCE_MOVE, data_used + DCE2_MOVE(data_ptr, data_len, data_used); + } /* Do this before calling DCE2_CoSegDecode since it will empty * seg buffer */ @@ -2425,6 +2476,9 @@ void DCE2_CoProcess(DCE2_SsnData* sd, DCE2_CoTracker* cot, /* Got the full DCE/RPC pdu. Need to create new packet before decoding */ DCE2_CoSegDecode(sd, cot, seg); + + if ( !data_used ) + break; } } diff --git a/src/service_inspectors/dce_rpc/dce_smb.cc b/src/service_inspectors/dce_rpc/dce_smb.cc index b3c735065..f6878f78d 100644 --- a/src/service_inspectors/dce_rpc/dce_smb.cc +++ b/src/service_inspectors/dce_rpc/dce_smb.cc @@ -686,13 +686,16 @@ static uint32_t DCE2_IgnoreJunkData(const uint8_t* data_ptr, uint16_t data_len, static DCE2_Ret DCE2_SmbHdrChecks(DCE2_SmbSsnData* ssd, const SmbNtHdr* smb_hdr) { Packet* p = ssd->sd.wire_pkt; + bool is_seg_buf = DCE2_SmbIsSegBuffer(ssd, (uint8_t*)smb_hdr); if ((DCE2_SsnFromServer(p) && (SmbType(smb_hdr) == SMB_TYPE__REQUEST)) || (DCE2_SsnFromClient(p) && (SmbType(smb_hdr) == SMB_TYPE__RESPONSE))) { - // FIXIT-M port segment check - // Same for all cases below - dce_alert(GID_DCE2, DCE2_SMB_BAD_TYPE, (dce2CommonStats*)&dce2_smb_stats); + if (is_seg_buf) + DCE2_SmbSegAlert(ssd, DCE2_SMB_BAD_TYPE); + else + dce_alert(GID_DCE2, DCE2_SMB_BAD_TYPE, (dce2CommonStats*)&dce2_smb_stats); + // Continue looking at traffic. Neither Windows nor Samba seem // to care, or even look at this flag } @@ -700,7 +703,11 @@ static DCE2_Ret DCE2_SmbHdrChecks(DCE2_SmbSsnData* ssd, const SmbNtHdr* smb_hdr) if ((SmbId(smb_hdr) != DCE2_SMB_ID) && (SmbId(smb_hdr) != DCE2_SMB2_ID)) { - dce_alert(GID_DCE2, DCE2_SMB_BAD_ID, (dce2CommonStats*)&dce2_smb_stats); + if (is_seg_buf) + DCE2_SmbSegAlert(ssd, DCE2_SMB_BAD_ID); + else + dce_alert(GID_DCE2, DCE2_SMB_BAD_ID, (dce2CommonStats*)&dce2_smb_stats); + return DCE2_RET__IGNORE; } @@ -1192,7 +1199,7 @@ static void DCE2_SmbProcessCommand(DCE2_SmbSsnData* ssd, const SmbNtHdr* smb_hdr DCE2_MOVE(nb_ptr, nb_len, (off2_ptr - nb_ptr)); - // FIXIT Need to test more. + // FIXIT-L Need to test more. switch (smb_com) { case SMB_COM_SESSION_SETUP_ANDX: @@ -1773,6 +1780,7 @@ static DCE2_SmbSsnData* dce2_handle_smb_session(Packet* p, dce2SmbProtoConf* con static DCE2_Ret DCE2_NbssHdrChecks(DCE2_SmbSsnData* ssd, const NbssHdr* nb_hdr) { Packet* p = ssd->sd.wire_pkt; + bool is_seg_buf = DCE2_SmbIsSegBuffer(ssd, (uint8_t*)nb_hdr); DebugMessage(DEBUG_DCE_SMB, "NetBIOS Session Service type: "); @@ -1794,9 +1802,11 @@ static DCE2_Ret DCE2_NbssHdrChecks(DCE2_SmbSsnData* ssd, const NbssHdr* nb_hdr) DebugFormat(DEBUG_DCE_SMB, "NetBIOS SS len(%zu) < SMB header len(%zu).\n", sizeof(SmbNtHdr), sizeof(NbssHdr) + nb_len); - // FIXIT-M port segment check - // Same for all cases below - dce_alert(GID_DCE2, DCE2_SMB_NB_LT_SMBHDR, (dce2CommonStats*)&dce2_smb_stats); + if (is_seg_buf) + DCE2_SmbSegAlert(ssd, DCE2_SMB_NB_LT_SMBHDR); + else + dce_alert(GID_DCE2, DCE2_SMB_NB_LT_SMBHDR, (dce2CommonStats*)&dce2_smb_stats); + return DCE2_RET__IGNORE; } } @@ -1807,7 +1817,10 @@ static DCE2_Ret DCE2_NbssHdrChecks(DCE2_SmbSsnData* ssd, const NbssHdr* nb_hdr) DebugMessage(DEBUG_DCE_SMB, "Session Request\n"); if (DCE2_SsnFromServer(p)) { - dce_alert(GID_DCE2, DCE2_SMB_BAD_NBSS_TYPE, (dce2CommonStats*)&dce2_smb_stats); + if (is_seg_buf) + DCE2_SmbSegAlert(ssd, DCE2_SMB_BAD_NBSS_TYPE); + else + dce_alert(GID_DCE2, DCE2_SMB_BAD_NBSS_TYPE, (dce2CommonStats*)&dce2_smb_stats); } break; @@ -1817,7 +1830,10 @@ static DCE2_Ret DCE2_NbssHdrChecks(DCE2_SmbSsnData* ssd, const NbssHdr* nb_hdr) case NBSS_SESSION_TYPE__RETARGET_RESPONSE: if (DCE2_SsnFromClient(p)) { - dce_alert(GID_DCE2, DCE2_SMB_BAD_NBSS_TYPE, (dce2CommonStats*)&dce2_smb_stats); + if (is_seg_buf) + DCE2_SmbSegAlert(ssd, DCE2_SMB_BAD_NBSS_TYPE); + else + dce_alert(GID_DCE2, DCE2_SMB_BAD_NBSS_TYPE, (dce2CommonStats*)&dce2_smb_stats); } break; @@ -1829,7 +1845,11 @@ static DCE2_Ret DCE2_NbssHdrChecks(DCE2_SmbSsnData* ssd, const NbssHdr* nb_hdr) default: DebugFormat(DEBUG_DCE_SMB, "Invalid Session Service type: 0x%02X\n", NbssType(nb_hdr)); - dce_alert(GID_DCE2, DCE2_SMB_BAD_NBSS_TYPE, (dce2CommonStats*)&dce2_smb_stats); + + if (is_seg_buf) + DCE2_SmbSegAlert(ssd, DCE2_SMB_BAD_NBSS_TYPE); + else + dce_alert(GID_DCE2, DCE2_SMB_BAD_NBSS_TYPE, (dce2CommonStats*)&dce2_smb_stats); return DCE2_RET__ERROR; } @@ -1857,6 +1877,7 @@ static void DCE2_SmbProcess(DCE2_SmbSsnData* ssd) const Packet* p = ssd->sd.wire_pkt; const uint8_t* data_ptr = p->data; uint16_t data_len = p->dsize; + DCE2_Buffer** seg_buf = DCE2_SmbGetSegBuffer(ssd); /* Have to account for segmentation. Even though stream will give * us larger chunks, we might end up in the middle of something */ @@ -1901,12 +1922,35 @@ static void DCE2_SmbProcess(DCE2_SmbSsnData* ssd) DebugFormat(DEBUG_DCE_SMB, "Data len(%hu) < NetBIOS SS header(%u). " "Queueing data.\n", data_len, data_need); - // FIXIT-M port segmentation code + if (DCE2_SmbHandleSegmentation(seg_buf, data_ptr, + data_len, sizeof(NbssHdr)) != DCE2_RET__SUCCESS) + { + DCE2_BufferEmpty(*seg_buf); + } + return; } // Set the NetBIOS header structure - NbssHdr* nb_hdr = (NbssHdr*)data_ptr; + NbssHdr* nb_hdr; + if (DCE2_BufferIsEmpty(*seg_buf)) + { + nb_hdr = (NbssHdr*)data_ptr; + } + else + { + // If data already buffered add the remainder for the + // size of the NetBIOS header + if (DCE2_SmbHandleSegmentation(seg_buf, data_ptr, + data_need, sizeof(NbssHdr)) != DCE2_RET__SUCCESS) + { + DCE2_BufferEmpty(*seg_buf); + return; + } + + nb_hdr = (NbssHdr*)DCE2_BufferData(*seg_buf); + } + uint32_t nb_len = NbssLen(nb_hdr); DebugFormat(DEBUG_DCE_SMB, "NetBIOS PDU length: %u\n", nb_len); @@ -1930,10 +1974,14 @@ static void DCE2_SmbProcess(DCE2_SmbSsnData* ssd) *ignore_bytes = DCE2_IgnoreJunkData(data_ptr, data_len, data_need + nb_len); } + DCE2_BufferEmpty(*seg_buf); dce2_smb_stats.smb_ignored_bytes += *ignore_bytes; continue; } + if (!DCE2_BufferIsEmpty(*seg_buf)) + DCE2_MOVE(data_ptr, data_len, (uint16_t)data_need); + switch (ssd->pdu_state) { case DCE2_SMB_PDU_STATE__COMMAND: @@ -1959,9 +2007,9 @@ static void DCE2_SmbProcess(DCE2_SmbSsnData* ssd) // there won't be any DCE/RPC traffic associated with it. case DCE2_SMB_DATA_STATE__SMB_HEADER: { - // FIXIT-M add segmentation code path, including seg_buf code to the entire state + uint32_t data_need = (sizeof(NbssHdr) + sizeof(SmbNtHdr)) - DCE2_BufferLength( + *seg_buf); - uint32_t data_need = (sizeof(NbssHdr) + sizeof(SmbNtHdr)); // See if there is enough data to process the SMB header if (data_len < data_need) { @@ -1969,12 +2017,34 @@ static void DCE2_SmbProcess(DCE2_SmbSsnData* ssd) "NetBIOS SS header + SMB header (%u). Queueing data.\n", data_len, data_need); - // FIXIT-M add segmentation code path + if (DCE2_SmbHandleSegmentation(seg_buf, data_ptr, data_len, + sizeof(NbssHdr) + sizeof(SmbNtHdr)) != DCE2_RET__SUCCESS) + { + DCE2_BufferEmpty(*seg_buf); + *data_state = DCE2_SMB_DATA_STATE__NETBIOS_HEADER; + } + return; } - // FIXIT-M add segmentation checks - SmbNtHdr* smb_hdr = (SmbNtHdr*)(data_ptr + sizeof(NbssHdr)); + // Set the SMB header structure + SmbNtHdr* smb_hdr; + if (DCE2_BufferIsEmpty(*seg_buf)) + { + smb_hdr = (SmbNtHdr*)(data_ptr + sizeof(NbssHdr)); + } + else + { + if (DCE2_SmbHandleSegmentation(seg_buf, data_ptr, data_need, + sizeof(NbssHdr) + sizeof(SmbNtHdr)) != DCE2_RET__SUCCESS) + { + DCE2_BufferEmpty(*seg_buf); + *data_state = DCE2_SMB_DATA_STATE__NETBIOS_HEADER; + return; + } + + smb_hdr = (SmbNtHdr*)(DCE2_BufferData(*seg_buf) + sizeof(NbssHdr)); + } // FIXIT-L Don't support SMB2 yet if (SmbId(smb_hdr) == DCE2_SMB2_ID) @@ -1989,8 +2059,16 @@ static void DCE2_SmbProcess(DCE2_SmbSsnData* ssd) { DebugMessage(DEBUG_DCE_SMB, "Not inspecting SMB packet.\n"); - // FIXIT-M add segmentation - *ignore_bytes = sizeof(NbssHdr) + NbssLen((NbssHdr*)data_ptr); + if (DCE2_BufferIsEmpty(*seg_buf)) + { + *ignore_bytes = sizeof(NbssHdr) + NbssLen((NbssHdr*)data_ptr); + } + else + { + *ignore_bytes = (NbssLen((NbssHdr*)DCE2_BufferData(*seg_buf)) + - sizeof(SmbNtHdr)) + data_need; + DCE2_BufferEmpty(*seg_buf); + } *data_state = DCE2_SMB_DATA_STATE__NETBIOS_HEADER; dce2_smb_stats.smb_ignored_bytes += *ignore_bytes; @@ -2002,7 +2080,16 @@ static void DCE2_SmbProcess(DCE2_SmbSsnData* ssd) { DebugMessage(DEBUG_DCE_SMB, "Bad SMB header.\n"); - *ignore_bytes = sizeof(NbssHdr) + NbssLen((NbssHdr*)data_ptr); + if (DCE2_BufferIsEmpty(*seg_buf)) + { + *ignore_bytes = sizeof(NbssHdr) + NbssLen((NbssHdr*)data_ptr); + } + else + { + *ignore_bytes = (NbssLen((NbssHdr*)DCE2_BufferData(*seg_buf)) + - sizeof(SmbNtHdr)) + data_need; + DCE2_BufferEmpty(*seg_buf); + } *data_state = DCE2_SMB_DATA_STATE__NETBIOS_HEADER; @@ -2010,6 +2097,9 @@ static void DCE2_SmbProcess(DCE2_SmbSsnData* ssd) continue; } + if (!DCE2_BufferIsEmpty(*seg_buf)) + DCE2_MOVE(data_ptr, data_len, (uint16_t)data_need); + *data_state = DCE2_SMB_DATA_STATE__NETBIOS_PDU; } @@ -2019,8 +2109,19 @@ static void DCE2_SmbProcess(DCE2_SmbSsnData* ssd) // to process. case DCE2_SMB_DATA_STATE__NETBIOS_PDU: { - uint32_t nb_len = NbssLen((NbssHdr*)data_ptr); - uint32_t data_need = sizeof(NbssHdr) + nb_len; + uint32_t nb_len; + uint32_t data_need; + + if (DCE2_BufferIsEmpty(*seg_buf)) + { + nb_len = NbssLen((NbssHdr*)data_ptr); + data_need = sizeof(NbssHdr) + nb_len; + } + else + { + nb_len = NbssLen((NbssHdr*)DCE2_BufferData(*seg_buf)); + data_need = (sizeof(NbssHdr) + nb_len) - DCE2_BufferLength(*seg_buf); + } /* It's something we want to inspect so make sure we have the full NBSS packet */ if (data_len < data_need) @@ -2029,7 +2130,12 @@ static void DCE2_SmbProcess(DCE2_SmbSsnData* ssd) "NetBIOS SS header + NetBIOS len(%zu). " "Queueing data.\n", data_len, sizeof(NbssHdr) + nb_len); - // FIXIT-M add segmentation code + if (DCE2_SmbHandleSegmentation(seg_buf, data_ptr, data_len, + sizeof(NbssHdr) + nb_len) != DCE2_RET__SUCCESS) + { + DCE2_BufferEmpty(*seg_buf); + *data_state = DCE2_SMB_DATA_STATE__NETBIOS_HEADER; + } return; } @@ -2039,9 +2145,52 @@ static void DCE2_SmbProcess(DCE2_SmbSsnData* ssd) *data_state = DCE2_SMB_DATA_STATE__NETBIOS_HEADER; - const uint8_t* nb_ptr = data_ptr; - nb_len = data_need; - DCE2_MOVE(data_ptr, data_len, (uint16_t)data_need); + const uint8_t* nb_ptr; + if (DCE2_BufferIsEmpty(*seg_buf)) + { + nb_ptr = data_ptr; + nb_len = data_need; + DCE2_MOVE(data_ptr, data_len, (uint16_t)data_need); + } + else + { + if (DCE2_SmbHandleSegmentation(seg_buf, data_ptr, data_need, + sizeof(NbssHdr) + nb_len) != DCE2_RET__SUCCESS) + { + DCE2_BufferEmpty(*seg_buf); + DCE2_MOVE(data_ptr, data_len, (uint16_t)data_need); + continue; + } + + DCE2_MOVE(data_ptr, data_len, (uint16_t)data_need); + + nb_ptr = DCE2_BufferData(*seg_buf); + nb_len = DCE2_BufferLength(*seg_buf); + + // Get reassembled packet + Packet* rpkt = DCE2_SmbGetRpkt(ssd, &nb_ptr, &nb_len, + DCE2_RPKT_TYPE__SMB_SEG); + if (rpkt == nullptr) + { + DCE2_BufferEmpty(*seg_buf); + continue; + } + + nb_ptr = DCE2_BufferData(*seg_buf); + nb_len = DCE2_BufferLength(*seg_buf); + + DebugFormat(DEBUG_DCE_SMB, + "Segmentation buffer: len: %u, size: %u\n", + DCE2_BufferLength(*seg_buf), DCE2_BufferSize(*seg_buf)); + + if (DCE2_SsnFromClient(ssd->sd.wire_pkt)) + dce2_smb_stats.smb_cli_seg_reassembled++; + else + dce2_smb_stats.smb_srv_seg_reassembled++; + + DebugMessage(DEBUG_DCE_SMB, "TCP reassembled SMB PDU\n"); + DCE2_PrintPktData(rpkt->data, rpkt->dsize); + } switch (ssd->pdu_state) { @@ -2068,6 +2217,14 @@ static void DCE2_SmbProcess(DCE2_SmbSsnData* ssd) "state: %d\n", __FILE__, __LINE__, ssd->pdu_state); return; } + + if (!DCE2_BufferIsEmpty(*seg_buf)) + { + DCE2_SmbReturnRpkt(ssd); + DCE2_BufferDestroy(*seg_buf); + *seg_buf = nullptr; + } + break; } diff --git a/src/service_inspectors/dce_rpc/dce_smb_utils.cc b/src/service_inspectors/dce_rpc/dce_smb_utils.cc index 94ff9aba1..bb57cf8d5 100644 --- a/src/service_inspectors/dce_rpc/dce_smb_utils.cc +++ b/src/service_inspectors/dce_rpc/dce_smb_utils.cc @@ -1318,3 +1318,129 @@ Packet* DCE2_SmbGetRpkt(DCE2_SmbSsnData* ssd, return rpkt; } +/******************************************************************** + * Function: DCE2_SmbHandleSegmentation() + * + * Wrapper around DCE2_HandleSegmentation() to allocate a new + * buffer object if necessary. + * + * Arguments: + * DCE2_SmbBuffer ** + * Pointer to pointer of buffer to add data to. If NULL + * a new buffer will be allocated. + * uint8_t * + * Pointer to the current data cursor in packet. + * uint32_t + * Length of data to add to buffer. + * uint32_t + * The minimum allocation size so that small allocations + * aren't consistently done. + * + * Returns: + * DCE2_Ret + * DCE2_RET__ERROR if an error occured. Nothing can + * be trusted. + * DCE2_RET__SUCCESS if data was successfully added. + * + ********************************************************************/ +DCE2_Ret DCE2_SmbHandleSegmentation(DCE2_Buffer** buf, + const uint8_t* data_ptr, uint32_t add_len, uint32_t alloc_size) +{ + Profile profile(dce2_smb_pstat_smb_seg); + + if (buf == nullptr) + { + return DCE2_RET__ERROR; + } + + if (*buf == nullptr) + { + /* No initial size or min alloc size */ + *buf = DCE2_BufferNew(alloc_size, alloc_size); + } + + DCE2_Ret status = DCE2_BufferAddData(*buf, data_ptr, add_len, + DCE2_BufferLength(*buf), DCE2_BUFFER_MIN_ADD_FLAG__IGNORE); + + return status; +} + +/******************************************************************** + * Function: DCE2_SmbIsSegBuffer() + * + * Purpose: + * Determines whether the pointer passed in lies within one of the + * segmentation buffers or not. + * + * Arguments: + * DCE2_SmbSsnData * + * Pointer to SMB session data. + * + * Returns: + * bool - True is the pointer lies within one of the segmentation + * buffers. + * False if it doesn't. + * + ********************************************************************/ +bool DCE2_SmbIsSegBuffer(DCE2_SmbSsnData* ssd, const uint8_t* ptr) +{ + DCE2_Buffer* seg_buf; + + if (DCE2_SsnFromServer(ssd->sd.wire_pkt)) + seg_buf = ssd->srv_seg; + else + seg_buf = ssd->cli_seg; + + if (DCE2_BufferIsEmpty(seg_buf)) + return false; + + /* See if we're looking at a segmentation buffer */ + if ((ptr < DCE2_BufferData(seg_buf)) || + (ptr > (DCE2_BufferData(seg_buf) + DCE2_BufferLength(seg_buf)))) + { + return false; + } + + return true; +} + +/******************************************************************** + * Function: DCE2_SmbSegAlert() + * + * Purpose: + * To create a reassembled packet using the data in one of the + * segmentation buffers in order to generate an alert with the + * correct, or more complete data. + * + * Arguments: + * DCE2_SmbSsnData * - Pointer to SMB session data. + * rule_id - rule id . + * + * Returns: None + * + ********************************************************************/ +void DCE2_SmbSegAlert(DCE2_SmbSsnData* ssd, uint32_t rule_id) +{ + DCE2_Buffer* buf; + + if (DCE2_SsnFromClient(ssd->sd.wire_pkt)) + buf = ssd->cli_seg; + else + buf = ssd->srv_seg; + + /* This should be called from the desegmentation code. */ + if (DCE2_BufferIsEmpty(buf)) + return; + + const uint8_t* data_ptr = DCE2_BufferData(buf); + uint32_t data_len = DCE2_BufferLength(buf); + + Packet* rpkt = DCE2_SmbGetRpkt(ssd, &data_ptr, &data_len, DCE2_RPKT_TYPE__SMB_SEG); + if (rpkt == nullptr) + return; + + dce_alert(GID_DCE2, rule_id, (dce2CommonStats*)&dce2_smb_stats); + + DCE2_SmbReturnRpkt(ssd); +} + diff --git a/src/service_inspectors/dce_rpc/dce_smb_utils.h b/src/service_inspectors/dce_rpc/dce_smb_utils.h index 369663591..7720cd079 100644 --- a/src/service_inspectors/dce_rpc/dce_smb_utils.h +++ b/src/service_inspectors/dce_rpc/dce_smb_utils.h @@ -165,8 +165,12 @@ DCE2_Ret DCE2_SmbProcessResponseData(DCE2_SmbSsnData*, const uint8_t*, uint32_t); void DCE2_SmbInitRdata(uint8_t*, int); void DCE2_SmbSetRdata(DCE2_SmbSsnData*, uint8_t*, uint16_t); -Packet* DCE2_SmbGetRpkt(DCE2_SmbSsnData*, const uint8_t **, +Packet* DCE2_SmbGetRpkt(DCE2_SmbSsnData*, const uint8_t**, uint32_t*, DCE2_RpktType); +DCE2_Ret DCE2_SmbHandleSegmentation(DCE2_Buffer**, + const uint8_t*, uint32_t, uint32_t); +bool DCE2_SmbIsSegBuffer(DCE2_SmbSsnData*, const uint8_t*); +void DCE2_SmbSegAlert(DCE2_SmbSsnData*, uint32_t rule_id); /******************************************************************** * Inline functions @@ -331,5 +335,12 @@ inline void DCE2_SmbReturnRpkt(DCE2_SmbSsnData* ssd) DCE2_PopPkt(&ssd->sd); } +inline DCE2_Buffer** DCE2_SmbGetSegBuffer(DCE2_SmbSsnData* ssd) +{ + if (DCE2_SsnFromServer(ssd->sd.wire_pkt)) + return &ssd->srv_seg; + return &ssd->cli_seg; +} + #endif diff --git a/src/service_inspectors/dce_rpc/dce_utils.h b/src/service_inspectors/dce_rpc/dce_utils.h index 4ff7c6532..e47d75136 100644 --- a/src/service_inspectors/dce_rpc/dce_utils.h +++ b/src/service_inspectors/dce_rpc/dce_utils.h @@ -376,6 +376,13 @@ inline uint32_t DCE2_BufferLength(DCE2_Buffer* buf) return buf->len; } +inline uint32_t DCE2_BufferSize(DCE2_Buffer* buf) +{ + if (buf == nullptr) + return 0; + return buf->size; +} + inline uint8_t* DCE2_BufferData(DCE2_Buffer* buf) { if (buf == nullptr)