📄 dce2_co.c
字号:
/**************************************************************************** * Copyright (C) 2008-2008 Sourcefire,Inc * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * **************************************************************************** * Module for handling connection-oriented DCE/RPC processing. Provides * context id, interface UUID correlation and tracking for use with the * preprocessor rule options. Provides desegmentation and defragmentation. * Sets appropriate data for use with the preprocessor rule options. * * 8/17/2008 - Initial implementation ... Todd Wease <twease@sourcefire.com> * ****************************************************************************/#include "dce2_co.h"#include "dce2_tcp.h"#include "dce2_smb.h"#include "snort_dce2.h"#include "dce2_memory.h"#include "dce2_utils.h"#include "dce2_stats.h"#include "dce2_event.h"#include "dce2_debug.h"#include "dcerpc.h"#include "sf_snort_packet.h"#include "sf_dynamic_preprocessor.h"/******************************************************************** * Macros ********************************************************************/#define DCE2_FRAG__MIN_ALLOC_SIZE 50/******************************************************************** * Extern variables ********************************************************************/extern DynamicPreprocessorData _dpd;extern DCE2_Stats dce2_stats;extern char *dce2_pdu_types[DCERPC_PDU_TYPE__MAX];/******************************************************************** * Enumerations ********************************************************************/typedef enum _DCE2_CoRpktType{ DCE2_CO_RPKT_TYPE__SEG, DCE2_CO_RPKT_TYPE__FRAG, DCE2_CO_RPKT_TYPE__ALL} DCE2_CoRpktType;typedef enum _DCE2_CoCtxState{ DCE2_CO_CTX_STATE__ACCEPTED, DCE2_CO_CTX_STATE__REJECTED, DCE2_CO_CTX_STATE__PENDING} DCE2_CoCtxState;/******************************************************************** * Structures ********************************************************************/typedef struct _DCE2_CoCtxIdNode{ uint16_t ctx_id; /* The context id */ Uuid iface; /* The presentation syntax uuid for the interface */ uint16_t iface_vers_maj; /* The major version of the interface */ uint16_t iface_vers_min; /* The minor version of the interface */ /* Whether or not the server accepted or rejected the client bind/alter context * request. Initially set to pending until server response */ DCE2_CoCtxState state;} DCE2_CoCtxIdNode;/******************************************************************** * Private function prototypes ********************************************************************/static DCE2_Ret DCE2_CoHdrChecks(DCE2_SsnData *, DCE2_CoTracker *, const DceRpcCoHdr *);static void DCE2_CoDecode(DCE2_SsnData *, DCE2_CoTracker *, const uint8_t *, uint16_t);static void DCE2_CoSegDecode(DCE2_SsnData *, DCE2_CoTracker *, DCE2_CoSeg *);static void DCE2_CoBind(DCE2_SsnData *, DCE2_CoTracker *, const DceRpcCoHdr *, const uint8_t *, uint16_t);static void DCE2_CoAlterCtx(DCE2_SsnData *, DCE2_CoTracker *, const DceRpcCoHdr *, const uint8_t *, uint16_t);static void DCE2_CoCtxReq(DCE2_SsnData *, DCE2_CoTracker *, const DceRpcCoHdr *, const uint8_t, const uint8_t *, uint16_t);static void DCE2_CoBindAck(DCE2_SsnData *, DCE2_CoTracker *, const DceRpcCoHdr *, const uint8_t *, uint16_t);static void DCE2_CoRequest(DCE2_SsnData *, DCE2_CoTracker *, const DceRpcCoHdr *, const uint8_t *, uint16_t);static void DCE2_CoResponse(DCE2_SsnData *, DCE2_CoTracker *, const DceRpcCoHdr *, const uint8_t *, uint16_t);static void DCE2_CoHandleFrag(DCE2_SsnData *, DCE2_CoTracker *, const DceRpcCoHdr *, const uint8_t *, uint16_t);static INLINE DCE2_Ret DCE2_CoHandleSegmentation(DCE2_CoSeg *, const uint8_t *, uint16_t, uint16_t, uint16_t *);static void DCE2_CoReassemble(DCE2_SsnData *, DCE2_CoTracker *, DCE2_CoRpktType);static INLINE void DCE2_CoFragReassemble(DCE2_SsnData *, DCE2_CoTracker *);static INLINE void DCE2_CoSegReassemble(DCE2_SsnData *, DCE2_CoTracker *);static DCE2_Ret DCE2_CoSetIface(DCE2_SsnData *, DCE2_CoTracker *, uint16_t);static int DCE2_CoCtxCompare(const void *, const void *);static void DCE2_CoCtxFree(void *);static INLINE void DCE2_CoSetRopts(DCE2_SsnData *, DCE2_CoTracker *, const DceRpcCoHdr *);static INLINE void DCE2_CoSetRdata(DCE2_CoTracker *, uint8_t *, uint16_t);static INLINE void DCE2_CoResetTracker(DCE2_CoTracker *);static INLINE void DCE2_CoResetForMissedPkts(DCE2_CoTracker *, const SFSnortPacket *);static INLINE DCE2_Ret DCE2_CoInitCtxStorage(DCE2_CoTracker *);static INLINE int DCE2_CoAutodetect(const uint8_t *, uint16_t);static INLINE void DCE2_CoEraseCtxIds(DCE2_CoTracker *);static INLINE int DCE2_CoMissedPkts(DCE2_CoTracker *, const SFSnortPacket *);static INLINE void DCE2_CoSegAlert(DCE2_SsnData *, DCE2_CoTracker *, DCE2_Event);static INLINE SFSnortPacket * DCE2_CoGetSegRpkt(DCE2_SsnData *, const uint8_t *, uint32_t);static INLINE DCE2_RpktType DCE2_CoGetRpktType(DCE2_SsnData *, DCE2_BufType);static SFSnortPacket * DCE2_CoGetRpkt(DCE2_SsnData *, DCE2_CoTracker *, DCE2_CoRpktType, DCE2_RpktType *);static INLINE int DCE2_CoIsSegBuf(DCE2_SsnData *, DCE2_CoTracker *, const uint8_t *);static void DCE2_CoEarlyReassemble(DCE2_SsnData *, DCE2_CoTracker *);static DCE2_Ret DCE2_CoSegEarlyRequest(DCE2_CoTracker *, const uint8_t *, uint32_t);/******************************************************************** * Function: DCE2_CoInitRdata() * * Initializes header of defragmentation reassembly packet. * Sets relevant fields in header that will not have to change * from reassembly to reassembly. The reassembly buffer used is * big enough for the header. * * Arguments: * uint8_t * * Pointer to the place in the reassembly packet to set * the header data. * * Returns: None * ********************************************************************/void DCE2_CoInitRdata(uint8_t *co_ptr){ DceRpcCoHdr *co_hdr = (DceRpcCoHdr *)co_ptr; /* Set some relevant fields. These should never get reset */ co_hdr->pversion.major = DCERPC_PROTO_MAJOR_VERS__5; co_hdr->ptype = DCERPC_PDU_TYPE__REQUEST; co_hdr->pfc_flags = (DCERPC_CO_PFC_FLAGS__FIRST_FRAG | DCERPC_CO_PFC_FLAGS__LAST_FRAG); co_hdr->packed_drep[0] = 0x10; /* Little endian */}/******************************************************************** * Function: DCE2_CoSetRdata() * * Sets relevant fields in the defragmentation reassembly packet * based on data gathered from the session and reassembly phase. * The reassembly buffer used is big enough for the headers. * * Arguments: * DCE2_CoTracker * * Pointer to the relevant connection-oriented tracker. * uint8_t * * Pointer to the place in the reassembly packet where the * header starts. * uint16_t * The length of the stub data. * * Returns: None * ********************************************************************/static INLINE void DCE2_CoSetRdata(DCE2_CoTracker *cot, uint8_t *co_ptr, uint16_t stub_len){ DceRpcCoHdr *co_hdr = (DceRpcCoHdr *)co_ptr; DceRpcCoRequest *co_req = (DceRpcCoRequest *)((uint8_t *)co_hdr + sizeof(DceRpcCoHdr)); /* If we've set the fragment tracker context id or opnum, use them. * Won't get to this point if cot ctx_id or opnum are not set */ uint16_t ctx_id = (cot->frag_tracker.ctx_id != DCE2_SENTINEL) ? (uint16_t)cot->frag_tracker.ctx_id : (uint16_t)cot->ctx_id; uint16_t opnum = (cot->frag_tracker.opnum != DCE2_SENTINEL) ? (uint16_t)cot->frag_tracker.opnum : (uint16_t)cot->opnum; uint32_t flen = sizeof(DceRpcCoHdr) + sizeof(DceRpcCoRequest) + stub_len; if (flen > UINT16_MAX) flen = UINT16_MAX; co_hdr->frag_length = DceRpcHtons((uint16_t)flen, DCERPC_BO_FLAG__LITTLE_ENDIAN); co_req->context_id = DceRpcHtons(ctx_id, DCERPC_BO_FLAG__LITTLE_ENDIAN); co_req->opnum = DceRpcHtons(opnum, DCERPC_BO_FLAG__LITTLE_ENDIAN);}/******************************************************************** * Function: DCE2_CoProcess() * * Main entry point for connection-oriented DCE/RPC processing. * It attempts to handle missed packets and overlapped bytes, * i.e. bytes we've already seen and processed. Since there can * be more than one DCE/RPC pdu in the packet, it loops through * the packet data until none is left. It handles transport layer * segmentation and buffers data until it gets the full pdu, then * hands off to pdu processing. * * Arguments: * DCE2_SsnData * * Pointer to the session data structure. * DCE2_CoTracker * * Pointer to the relevant connection-oriented tracker. * const uint8_t * * Pointer to packet data * uint16_t * Packet data length * * Returns: None * ********************************************************************/void DCE2_CoProcess(DCE2_SsnData *sd, DCE2_CoTracker *cot, const uint8_t *data_ptr, uint16_t data_len){ DCE2_CoSeg *seg; DCE2_Ret status; uint32_t num_frags = 0; dce2_stats.co_pkts++; /* Set the appropriate segmentation buffer */ if (DCE2_SsnFromServer(sd->wire_pkt)) seg = &cot->srv_seg; else seg = &cot->cli_seg; /* Check to see if we've missed packets */ if (DCE2_SsnMissedPkts(sd) || DCE2_CoMissedPkts(cot, sd->wire_pkt)) { DCE2_DEBUG_MSG(DCE2_DEBUG__CO, "CO missed pkts ...\n"); DCE2_CoResetForMissedPkts(cot, sd->wire_pkt); /* If we don't autodetect, consider this another missed packet */ if (!DCE2_CoAutodetect(data_ptr, data_len)) return; /* Reset tracker missed packets, since we've just * dealt with it */ if (cot->cli_missed_pkts) cot->cli_missed_pkts = 0; else if (cot->srv_missed_pkts) cot->srv_missed_pkts = 0; } while (data_len > 0) { num_frags++; DCE2_DEBUG_MSG(DCE2_DEBUG__CO, "DCE/RPC message number: %u\n", num_frags); /* Fast track full fragments */ if (DCE2_BufferIsEmpty(seg->buf)) { 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)) { DCE2_DEBUG_MSG(DCE2_DEBUG__CO, "Not enough data in packet for CO header.\n"); DCE2_CoHandleSegmentation(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; frag_len = DceRpcCoFragLen((DceRpcCoHdr *)data_ptr); /* Not enough data left for the pdu. */ if (data_len < frag_len) { DCE2_DEBUG_MSG(DCE2_DEBUG__CO, "Not enough data in packet for fragment length.\n"); /* Set frag length so we don't have to check it again in seg code */ seg->frag_len = frag_len; DCE2_CoHandleSegmentation(seg, data_ptr, data_len, frag_len, &data_used); break; } DCE2_MOVE(data_ptr, data_len, frag_len); /* Got a full DCE/RPC pdu */ DCE2_CoDecode(sd, cot, frag_ptr, frag_len); /* If we're configured to do defragmentation only detect on first frag * since we'll detect on reassembled */ if (!DCE2_GcDceDefrag() || (num_frags == 1)) DCE2_Detect(sd); } else /* We've already buffered data */ { uint16_t data_used; DCE2_DEBUG_MSG(DCE2_DEBUG__CO, "Segmentation buffer has %u bytes\n", DCE2_BufferLength(seg->buf)); /* Need more data to get header */ if (DCE2_BufferLength(seg->buf) < sizeof(DceRpcCoHdr)) { status = DCE2_CoHandleSegmentation(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) { DCE2_BufferEmpty(seg->buf); return; } seg->frag_len = DceRpcCoFragLen((DceRpcCoHdr *)DCE2_BufferData(seg->buf)); } /* Need more data for full pdu */ if (DCE2_BufferLength(seg->buf) < seg->frag_len) { status = DCE2_CoHandleSegmentation(seg, data_ptr, data_len, seg->frag_len, &data_used); /* Still not enough */ if (status != DCE2_RET__SUCCESS) break; DCE2_MOVE(data_ptr, data_len, data_used); } /* Got the full DCE/RPC pdu. Need to create new packet before decoding */ DCE2_CoSegDecode(sd, cot, seg); } } if (DCE2_GcReassembleEarly()) DCE2_CoEarlyReassemble(sd, cot);}/******************************************************************** * Function: DCE2_CoHandleSegmentation() * * Wrapper around DCE2_HandleSegmentation() to allocate a new * buffer object if necessary. * * Arguments: * DCE2_CoSeg * * Pointer to a connection-oriented segmentation structure. * uint8_t * * Pointer to the current data cursor in packet. * uint16_t
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -