/******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ void * DCE2_ReAlloc(void *old_mem, uint32_t old_size, uint32_t new_size, DCE2_MemType mtype) { void *new_mem; DCE2_Ret status; if (dce2_mem_state == DCE2_MEM_STATE__MEMCAP) return NULL; if (old_mem == NULL) { DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Old memory passed in was NULL.", __FILE__, __LINE__); return NULL; } else if (new_size < old_size) { DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) New size is less than old size.", __FILE__, __LINE__); return NULL; } else if (new_size == old_size) { return old_mem; } if (DCE2_CheckMemcap(new_size - old_size, mtype) == DCE2_MEMCAP_EXCEEDED) return NULL; new_mem = DCE2_Alloc(new_size, mtype); if (new_mem == NULL) return NULL; status = DCE2_Memcpy(new_mem, old_mem, old_size, new_mem, (void *)((uint8_t *)new_mem + new_size)); if (status != DCE2_RET__SUCCESS) { DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Failed to copy old memory into new memory.", __FILE__, __LINE__); DCE2_Free(new_mem, new_size, mtype); return NULL; } DCE2_Free(old_mem, old_size, mtype); return new_mem; }
/******************************************************************** * Function: DCE2_GetDebugLevel() * * Gets the debugging level set by the DCE2 debugging environment * variable on the first call. Subsequent calls will used the * cached value. * * Arguments: None * * Returns: * uint32_t * The debugging level set by the environment variable. * ********************************************************************/ static uint32_t DCE2_GetDebugLevel(void) { static int debug_init = 0; static uint32_t debug_level = 0; const char* value; if (debug_init) return debug_level; value = getenv(DCE2_DEBUG_VARIABLE); if (value != NULL) { char *endptr; debug_level = _dpd.SnortStrtoul(value, &endptr, 0); if ((errno == ERANGE) || (*endptr != '\0')) { DCE2_Log(DCE2_LOG_TYPE__WARN, "\"%s\" value out of range or not a number: %s. " "Debugging will not be turned on.", DCE2_DEBUG_VARIABLE, value); debug_level = 0; } } debug_init = 1; return debug_level; }
/******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ DCE2_Ret DCE2_BufferAddData( DCE2_Buffer *buf, const uint8_t *data, uint32_t data_len, uint32_t offset, DCE2_BufferMinAddFlag mflag) { DCE2_Ret status; if ((buf == NULL) || (data == NULL)) return DCE2_RET__ERROR; /* Return success for this since ultimately nothing _was_ added */ if (data_len == 0) return DCE2_RET__SUCCESS; if ( !offset ) offset = DCE2_BufferLength(buf); if (buf->data == NULL) { uint32_t size = offset + data_len; if ((size < buf->min_add_size) && (mflag == DCE2_BUFFER_MIN_ADD_FLAG__USE)) size = buf->min_add_size; buf->data = (uint8_t *)DCE2_Alloc(size, buf->mtype); if (buf->data == NULL) return DCE2_RET__ERROR; buf->size = size; } else if ((offset + data_len) > buf->size) { uint8_t *tmp; uint32_t new_size = offset + data_len; if (((new_size - buf->size) < buf->min_add_size) && (mflag == DCE2_BUFFER_MIN_ADD_FLAG__USE)) new_size += buf->min_add_size; tmp = (uint8_t *)DCE2_ReAlloc(buf->data, buf->size, new_size, buf->mtype); if (tmp == NULL) return DCE2_RET__ERROR; buf->data = tmp; buf->size = new_size; } status = DCE2_Memcpy(buf->data + offset, data, data_len, buf->data, buf->data + buf->size); if (status != DCE2_RET__SUCCESS) { DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Failed to copy data into buffer.", __FILE__, __LINE__); return DCE2_RET__ERROR; } buf->len = offset + data_len; return DCE2_RET__SUCCESS; }
/****************************************************************** * Function: DCE2_Reset() * * Purpose: Reset the preprocessor to a post configuration state. * * Arguments: * int - signal that caused the reset * void * - pointer to data * * Returns: None * ******************************************************************/ static void DCE2_Reset(int signal, void *data) { if (!DCE2_CStackIsEmpty(dce2_pkt_stack)) { DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Packet stack is not empty when it should be.", __FILE__, __LINE__); DCE2_CStackEmpty(dce2_pkt_stack); } }
/********************************************************************* * Function: * * Purpose: * * Arguments: * * Returns: * *********************************************************************/ void DCE2_Detect(DCE2_SsnData *sd) { SFSnortPacket *top_pkt = (SFSnortPacket *)DCE2_CStackTop(dce2_pkt_stack); PROFILE_VARS; if (top_pkt == NULL) { DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) No packet on top of stack.", __FILE__, __LINE__); return; } DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "Detecting ------------------------------------------------\n")); DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ROPTIONS, " Rule options:\n")); DCE2_DEBUG_CODE(DCE2_DEBUG__ROPTIONS, DCE2_PrintRoptions(&sd->ropts););
/********************************************************************* * Function: * * Purpose: * * Arguments: * * Returns: * *********************************************************************/ void DCE2_PopPkt(void) { SFSnortPacket *pop_pkt = (SFSnortPacket *)DCE2_CStackPop(dce2_pkt_stack); PROFILE_VARS; PREPROC_PROFILE_START(dce2_pstat_log); if (pop_pkt == NULL) { DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) No packet to pop off stack.", __FILE__, __LINE__); PREPROC_PROFILE_END(dce2_pstat_log); return; } _dpd.pushAlerts(); _dpd.logAlerts((void *)pop_pkt); _dpd.resetAlerts(); _dpd.popAlerts(); PREPROC_PROFILE_END(dce2_pstat_log); }
/******************************************************************** * Function: DCE2_ClFragReassemble() * * Reassembles fragments into reassembly buffer and copies to * reassembly packet. * * Arguments: * DCE2_SsnData * * Pointer to the session data structure. * DCE2_ClActTracker * * Pointer to the connectionless activity tracker. * DceRpcClHdr * * Pointer to the connectionless header in the packet. * * Returns: None * ********************************************************************/ static void DCE2_ClFragReassemble(DCE2_SsnData *sd, DCE2_ClActTracker *at, const DceRpcClHdr *cl_hdr) { DCE2_ClFragTracker *ft = &at->frag_tracker; DCE2_ClFragNode *fnode; uint8_t *rdata = dce2_cl_rbuf; uint16_t rlen = sizeof(dce2_cl_rbuf); uint32_t stub_len = 0; const uint8_t *stub_data = NULL; SFSnortPacket *rpkt = NULL; PROFILE_VARS; PREPROC_PROFILE_START(dce2_pstat_cl_reass); for (fnode = (DCE2_ClFragNode *)DCE2_ListFirst(ft->frags); fnode != NULL; fnode = (DCE2_ClFragNode *)DCE2_ListNext(ft->frags)) { if (fnode->frag_len > rlen) { DCE2_Log(DCE2_LOG_TYPE__WARN, "%s(%d) Size of fragments exceeds reassembly buffer size. " "Using as many fragments as will fit.", __FILE__, __LINE__); break; } if (DCE2_Memcpy(rdata, fnode->frag_data, fnode->frag_len, rdata, rdata + rlen) != DCE2_RET__SUCCESS) { DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Failed to copy data into fragment " "reassembly buffer.", __FILE__, __LINE__); break; } DCE2_MOVE(rdata, rlen, fnode->frag_len); stub_len += fnode->frag_len; } switch (sd->trans) { case DCE2_TRANS_TYPE__UDP: rpkt = DCE2_GetRpkt(sd->wire_pkt, DCE2_RPKT_TYPE__UDP_CL_FRAG, dce2_cl_rbuf, stub_len); if (rpkt == NULL) { DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Failed to create reassembly packet.", __FILE__, __LINE__); PREPROC_PROFILE_END(dce2_pstat_cl_reass); return; } DCE2_ClSetRdata(at, cl_hdr, (uint8_t *)rpkt->payload, (uint16_t)(rpkt->payload_size - DCE2_MOCK_HDR_LEN__CL)); stub_data = rpkt->payload + DCE2_MOCK_HDR_LEN__CL; break; default: DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Invalid transport type: %d", __FILE__, __LINE__, sd->trans); return; } PREPROC_PROFILE_END(dce2_pstat_cl_reass); if (DCE2_PushPkt(rpkt) != DCE2_RET__SUCCESS) { DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Failed to push packet onto packet stack.", __FILE__, __LINE__); return; } /* Cache relevant values for rule option processing */ sd->ropts.first_frag = 1; DCE2_CopyUuid(&sd->ropts.iface, &ft->iface, DCERPC_BO_FLAG__NONE); sd->ropts.iface_vers = ft->iface_vers; sd->ropts.hdr_byte_order = DceRpcClByteOrder(cl_hdr); if (ft->data_byte_order != DCE2_SENTINEL) sd->ropts.data_byte_order = ft->data_byte_order; else sd->ropts.data_byte_order = DceRpcClByteOrder(cl_hdr); if (ft->opnum != DCE2_SENTINEL) sd->ropts.opnum = ft->opnum; else sd->ropts.opnum = DceRpcClOpnum(cl_hdr); sd->ropts.stub_data = stub_data; DCE2_Detect(sd); DCE2_PopPkt(); dce2_stats.cl_frag_reassembled++; }
/******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ void DCE2_RegMem(uint32_t size, DCE2_MemType mtype) { switch (mtype) { case DCE2_MEM_TYPE__CONFIG: dce2_memory.config += size; if (dce2_memory.config > dce2_memory.config_max) dce2_memory.config_max = dce2_memory.config; break; case DCE2_MEM_TYPE__ROPTION: dce2_memory.roptions += size; if (dce2_memory.roptions > dce2_memory.roptions_max) dce2_memory.roptions_max = dce2_memory.roptions; break; case DCE2_MEM_TYPE__RT: dce2_memory.rt += size; if (dce2_memory.rt > dce2_memory.rt_max) dce2_memory.rt_max = dce2_memory.rt; break; case DCE2_MEM_TYPE__INIT: dce2_memory.init += size; if (dce2_memory.init > dce2_memory.init_max) dce2_memory.init_max = dce2_memory.init; break; case DCE2_MEM_TYPE__SMB_SSN: case DCE2_MEM_TYPE__SMB_SEG: case DCE2_MEM_TYPE__SMB_UID: case DCE2_MEM_TYPE__SMB_TID: case DCE2_MEM_TYPE__SMB_FID: case DCE2_MEM_TYPE__SMB_UT: case DCE2_MEM_TYPE__SMB_PM: DCE2_RegMemSmb(size, mtype); break; case DCE2_MEM_TYPE__TCP_SSN: dce2_memory.tcp_ssn += size; if (dce2_memory.tcp_ssn > dce2_memory.tcp_ssn_max) dce2_memory.tcp_ssn_max = dce2_memory.tcp_ssn; dce2_memory.tcp_total += size; if (dce2_memory.tcp_total > dce2_memory.tcp_total_max) dce2_memory.tcp_total_max = dce2_memory.tcp_total; break; case DCE2_MEM_TYPE__CO_SEG: case DCE2_MEM_TYPE__CO_FRAG: case DCE2_MEM_TYPE__CO_CTX: DCE2_RegMemCo(size, mtype); break; case DCE2_MEM_TYPE__UDP_SSN: dce2_memory.udp_ssn += size; if (dce2_memory.udp_ssn > dce2_memory.udp_ssn_max) dce2_memory.udp_ssn_max = dce2_memory.udp_ssn; dce2_memory.udp_total += size; if (dce2_memory.udp_total > dce2_memory.udp_total_max) dce2_memory.udp_total_max = dce2_memory.udp_total; break; case DCE2_MEM_TYPE__HTTP_SSN: dce2_memory.http_ssn += size; if (dce2_memory.http_ssn > dce2_memory.http_ssn_max) dce2_memory.http_ssn_max = dce2_memory.http_ssn; dce2_memory.http_total += size; if (dce2_memory.http_total > dce2_memory.http_total_max) dce2_memory.http_total_max = dce2_memory.http_total; break; case DCE2_MEM_TYPE__CL_ACT: case DCE2_MEM_TYPE__CL_FRAG: DCE2_RegMemCl(size, mtype); break; default: DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Invalid memory type: %d", __FILE__, __LINE__, mtype); break; } switch (mtype) { case DCE2_MEM_TYPE__CONFIG: case DCE2_MEM_TYPE__ROPTION: case DCE2_MEM_TYPE__RT: case DCE2_MEM_TYPE__INIT: break; default: dce2_memory.rtotal += size; if (dce2_memory.rtotal > dce2_memory.rtotal_max) dce2_memory.rtotal_max = dce2_memory.rtotal; } dce2_memory.total += size; if (dce2_memory.total > dce2_memory.total_max) dce2_memory.total_max = dce2_memory.total; }
/******************************************************************** * Function: * * Purpose: * * Arguments: * * Returns: * ********************************************************************/ void DCE2_UnRegMem(uint32_t size, DCE2_MemType mtype) { switch (mtype) { case DCE2_MEM_TYPE__CONFIG: dce2_memory.config -= size; break; case DCE2_MEM_TYPE__ROPTION: dce2_memory.roptions -= size; break; case DCE2_MEM_TYPE__RT: dce2_memory.rt -= size; break; case DCE2_MEM_TYPE__INIT: dce2_memory.init -= size; break; case DCE2_MEM_TYPE__SMB_SSN: dce2_memory.smb_total -= size; dce2_memory.smb_ssn -= size; break; case DCE2_MEM_TYPE__SMB_SEG: dce2_memory.smb_total -= size; dce2_memory.smb_seg -= size; break; case DCE2_MEM_TYPE__SMB_UID: dce2_memory.smb_total -= size; dce2_memory.smb_uid -= size; break; case DCE2_MEM_TYPE__SMB_TID: dce2_memory.smb_total -= size; dce2_memory.smb_tid -= size; break; case DCE2_MEM_TYPE__SMB_FID: dce2_memory.smb_total -= size; dce2_memory.smb_fid -= size; break; case DCE2_MEM_TYPE__SMB_UT: dce2_memory.smb_total -= size; dce2_memory.smb_ut -= size; break; case DCE2_MEM_TYPE__SMB_PM: dce2_memory.smb_total -= size; dce2_memory.smb_pm -= size; break; case DCE2_MEM_TYPE__TCP_SSN: dce2_memory.tcp_total -= size; dce2_memory.tcp_ssn -= size; break; case DCE2_MEM_TYPE__CO_SEG: dce2_memory.co_total -= size; dce2_memory.co_seg -= size; break; case DCE2_MEM_TYPE__CO_FRAG: dce2_memory.co_total -= size; dce2_memory.co_frag -= size; break; case DCE2_MEM_TYPE__CO_CTX: dce2_memory.co_total -= size; dce2_memory.co_ctx -= size; break; case DCE2_MEM_TYPE__UDP_SSN: dce2_memory.udp_total -= size; dce2_memory.udp_ssn -= size; break; case DCE2_MEM_TYPE__CL_ACT: dce2_memory.cl_total -= size; dce2_memory.cl_act -= size; break; case DCE2_MEM_TYPE__HTTP_SSN: dce2_memory.http_total -= size; dce2_memory.http_ssn -= size; break; case DCE2_MEM_TYPE__CL_FRAG: dce2_memory.cl_total -= size; dce2_memory.cl_frag -= size; break; default: DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Invalid memory type: %d", __FILE__, __LINE__, mtype); break; } switch (mtype) { case DCE2_MEM_TYPE__CONFIG: case DCE2_MEM_TYPE__ROPTION: case DCE2_MEM_TYPE__RT: case DCE2_MEM_TYPE__INIT: break; default: dce2_memory.rtotal -= size; } dce2_memory.total -= size; }
/******************************************************************** * Function: * * Must have allocated data in buffer and data_len must fit in * buffer. * * Arguments: * * Returns: * ********************************************************************/ DCE2_Ret DCE2_BufferMoveData(DCE2_Buffer *buf, uint32_t data_offset, const uint8_t *move, uint32_t move_len) { DCE2_Ret status; uint8_t *offset, *end; if ((buf == NULL) || (buf->data == NULL) || (move == NULL)) return DCE2_RET__ERROR; /* Return success for this since ultimately nothing _was_ moved */ if (move_len == 0) return DCE2_RET__SUCCESS; offset = buf->data + data_offset; end = buf->data + buf->len; /* Moved data must be within current data */ if ((move < buf->data) || ((move + move_len) > end)) return DCE2_RET__ERROR; /* No move required */ if (move == offset) return DCE2_RET__SUCCESS; /* Would have to do two moves. One for the data and one to realign data * with start of moved data. Don't want to succeed on the first and fail * on the second and leave the buffer in a bad state. Don't want to use * an offset in data buffer because want to keep the size the same. */ if (move == buf->data) { uint32_t tmp_size = buf->len; uint8_t *tmp = (uint8_t *)DCE2_Alloc(tmp_size, buf->mtype); uint8_t *tmp_offset, *tmp_end; uint32_t new_len; if (tmp == NULL) return DCE2_RET__ERROR; tmp_offset = tmp + data_offset; tmp_end = tmp + tmp_size; status = DCE2_Memcpy(tmp, buf->data, buf->len, tmp, tmp_end); if (status != DCE2_RET__SUCCESS) { DCE2_Free((void *)tmp, tmp_size, buf->mtype); DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Failed to move data in buffer.", __FILE__, __LINE__); return DCE2_RET__ERROR; } status = DCE2_Memmove(tmp_offset, tmp, move_len, tmp_offset, tmp_end); if (status != DCE2_RET__SUCCESS) { DCE2_Free((void *)tmp, tmp_size, buf->mtype); DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Failed to move data in buffer.", __FILE__, __LINE__); return DCE2_RET__ERROR; } if (tmp_offset > (tmp + move_len)) tmp_offset = tmp + move_len; new_len = tmp_end - tmp_offset; status = DCE2_Memcpy(buf->data, tmp_offset, new_len, buf->data, end); if (status != DCE2_RET__SUCCESS) { DCE2_Free((void *)tmp, tmp_size, buf->mtype); DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Failed to move data in buffer.", __FILE__, __LINE__); return DCE2_RET__ERROR; } buf->len = new_len; DCE2_Free((void *)tmp, tmp_size, buf->mtype); } else { status = DCE2_Memmove(offset, move, move_len, offset, end); if (status != DCE2_RET__SUCCESS) { DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Failed to move data in buffer", __FILE__, __LINE__); return DCE2_RET__ERROR; } /* If we have a new end of data, adjust length */ if ((move + move_len) == end) buf->len = data_offset + move_len; } return DCE2_RET__SUCCESS; }
/********************************************************************* * Function: * * Purpose: * * Arguments: * * Returns: * *********************************************************************/ DCE2_Ret DCE2_AddDataToRpkt(SFSnortPacket *rpkt, DCE2_RpktType rtype, const uint8_t *data, uint32_t data_len) { int hdr_overhead = 0; const uint8_t *pkt_data_end; const uint8_t *payload_end; DCE2_Ret status; if ((rpkt == NULL) || (data == NULL) || (data_len == 0)) return DCE2_RET__ERROR; if (rpkt->payload == NULL) return DCE2_RET__ERROR; /* This is a check to make sure we don't overwrite header data */ switch (rtype) { case DCE2_RPKT_TYPE__SMB_CO_SEG: if (DCE2_SsnFromClient(rpkt)) hdr_overhead = DCE2_MOCK_HDR_LEN__SMB_CLI; else hdr_overhead = DCE2_MOCK_HDR_LEN__SMB_SRV; break; case DCE2_RPKT_TYPE__SMB_CO_FRAG: if (DCE2_SsnFromClient(rpkt)) hdr_overhead = DCE2_MOCK_HDR_LEN__SMB_CLI + DCE2_MOCK_HDR_LEN__CO_CLI; else hdr_overhead = DCE2_MOCK_HDR_LEN__SMB_SRV + DCE2_MOCK_HDR_LEN__CO_SRV; break; case DCE2_RPKT_TYPE__TCP_CO_FRAG: if (DCE2_SsnFromClient(rpkt)) hdr_overhead = DCE2_MOCK_HDR_LEN__CO_CLI; else hdr_overhead = DCE2_MOCK_HDR_LEN__CO_SRV; break; case DCE2_RPKT_TYPE__UDP_CL_FRAG: hdr_overhead = DCE2_MOCK_HDR_LEN__CL; break; default: break; } if (rpkt->payload_size < hdr_overhead) return DCE2_RET__ERROR; pkt_data_end = rpkt->pkt_data + rpkt->max_payload; payload_end = rpkt->payload + rpkt->payload_size; if ((payload_end + data_len) > pkt_data_end) data_len = pkt_data_end - payload_end; status = DCE2_Memcpy((void *)payload_end, (void *)data, (size_t)data_len, (void *)payload_end, (void *)pkt_data_end); if (status != DCE2_RET__SUCCESS) { DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Failed to copy data into reassembly packet.", __FILE__, __LINE__); return DCE2_RET__ERROR; } rpkt->payload_size += (uint16_t)data_len; // there is room for optimization here since the update was done // earlier - that my be eliminated, but only in this case one // approach is to move the updates to push pkt - but don't want // to update non-dce2 pseudo pkts; perhaps a flag check there // will suffice. _dpd.encodeUpdate(rpkt); if (rpkt->family == AF_INET) { rpkt->ip4h->ip_len = rpkt->ip4_header->data_length; } else { IP6RawHdr* ip6h = (IP6RawHdr*)rpkt->raw_ip6_header; if ( ip6h ) rpkt->ip6h->len = ip6h->ip6_payload_len; } return DCE2_RET__SUCCESS; }
/********************************************************************* * Function: * * Purpose: * * Arguments: * * Returns: * *********************************************************************/ static DCE2_SsnData * DCE2_NewSession(SFSnortPacket *p, tSfPolicyId policy_id) { DCE2_SsnData *sd = NULL; DCE2_TransType trans; const DCE2_ServerConfig *sc = DCE2_ScGetConfig(p); int autodetected = 0; PROFILE_VARS; PREPROC_PROFILE_START(dce2_pstat_new_session); DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "Creating new session: ")); trans = DCE2_GetTransport(p, sc, &autodetected); switch (trans) { case DCE2_TRANS_TYPE__SMB: DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "SMB transport ... ")); sd = (DCE2_SsnData *)DCE2_SmbSsnInit(p); break; case DCE2_TRANS_TYPE__TCP: DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "TCP transport ... ")); sd = (DCE2_SsnData *)DCE2_TcpSsnInit(); break; case DCE2_TRANS_TYPE__UDP: DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "UDP transport ... ")); sd = (DCE2_SsnData *)DCE2_UdpSsnInit(); break; case DCE2_TRANS_TYPE__HTTP_PROXY: DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "RPC over HTTP proxy transport ... ")); sd = (DCE2_SsnData *)DCE2_HttpProxySsnInit(); break; case DCE2_TRANS_TYPE__HTTP_SERVER: DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "RPC over HTTP server transport ... ")); sd = (DCE2_SsnData *)DCE2_HttpServerSsnInit(); break; case DCE2_TRANS_TYPE__NONE: DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "Not configured to " "look at this traffic or unable to autodetect - not inspecting.\n")); PREPROC_PROFILE_END(dce2_pstat_new_session); return NULL; default: DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Invalid transport type: %d", __FILE__, __LINE__, trans); PREPROC_PROFILE_END(dce2_pstat_new_session); return NULL; } if (sd == NULL) { PREPROC_PROFILE_END(dce2_pstat_new_session); return NULL; } DCE2_SsnSetAppData(p, (void *)sd, DCE2_SsnFree); dce2_stats.sessions++; DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "Created (%p)\n", (void *)sd)); sd->trans = trans; sd->server_policy = DCE2_ScPolicy(sc); sd->client_policy = DCE2_POLICY__WINXP; // Default to Windows XP sd->sconfig = sc; sd->wire_pkt = p; sd->policy_id = policy_id; sd->config = dce2_config; ((DCE2_Config *)sfPolicyUserDataGet(sd->config, policy_id))->ref_count++; if (autodetected) { dce2_stats.sessions_autodetected++; #ifdef DEBUG if (DCE2_SsnFromServer(p)) dce2_stats.autoports[p->src_port][trans]++; else dce2_stats.autoports[p->dst_port][trans]++; #endif DCE2_SsnSetAutodetected(sd, p); } /* If we've determined a transport, make sure we're doing * reassembly on the session */ if (IsTCP(p)) { int rs_dir = DCE2_SsnGetReassembly(p); if (!_dpd.isPafEnabled() && (rs_dir != SSN_DIR_BOTH)) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "Setting client/server reassembly to FOOTPRINT for this session.\n")); DCE2_SsnSetReassembly(p); } if (!DCE2_SsnIsRebuilt(p)) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "Got non-rebuilt packet\n")); if (DCE2_SsnIsStreamInsert(p)) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "Stream inserted - not inspecting.\n")); PREPROC_PROFILE_END(dce2_pstat_new_session); return NULL; } else if ((DCE2_SsnFromClient(p) && (rs_dir == SSN_DIR_FROM_SERVER)) || (DCE2_SsnFromServer(p) && (rs_dir == SSN_DIR_FROM_CLIENT)) || (rs_dir == SSN_DIR_BOTH)) { /* Reassembly was already set for this session, but stream * decided not to use the packet so it's probably not good */ DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "Got non-stream inserted packet - not inspecting\n")); PREPROC_PROFILE_END(dce2_pstat_new_session); return NULL; } } } PREPROC_PROFILE_END(dce2_pstat_new_session); return sd; }
/********************************************************************* * Function: DCE2_GetRpkt() * * Purpose: * * Arguments: * SFSnortPacket * - pointer to packet off wire * const uint8_t * - pointer to data to attach to reassembly packet * uint16_t - length of data * * Returns: * SFSnortPacket * - pointer to reassembly packet * *********************************************************************/ SFSnortPacket * DCE2_GetRpkt(const SFSnortPacket *wire_pkt, DCE2_RpktType rpkt_type, const uint8_t *data, uint32_t data_len) { DCE2_Ret status; SFSnortPacket *rpkt; uint16_t payload_len = 0; uint16_t data_overhead = 0; rpkt = dce2_rpkt[rpkt_type]; switch (rpkt_type) { case DCE2_RPKT_TYPE__SMB_SEG: _dpd.encodeFormat(ENC_DYN_FWD, wire_pkt, rpkt, PSEUDO_PKT_SMB_SEG); break; case DCE2_RPKT_TYPE__SMB_TRANS: // TBD these memset()s could be encapsulated by the various // init functions which should also return the data_overhead. // Better still pass in rpkt and let the init function update // payload, etc. Also, some memsets could probably be avoided // by explicitly setting the unitialized header fields. _dpd.encodeFormat(ENC_DYN_FWD, wire_pkt, rpkt, PSEUDO_PKT_SMB_TRANS); if (DCE2_SsnFromClient(wire_pkt)) { data_overhead = DCE2_MOCK_HDR_LEN__SMB_CLI; memset((void*)rpkt->payload, 0, data_overhead); DCE2_SmbInitRdata((uint8_t *)rpkt->payload, FLAG_FROM_CLIENT); } else { data_overhead = DCE2_MOCK_HDR_LEN__SMB_SRV; memset((void*)rpkt->payload, 0, data_overhead); DCE2_SmbInitRdata((uint8_t *)rpkt->payload, FLAG_FROM_SERVER); } break; case DCE2_RPKT_TYPE__SMB_CO_SEG: _dpd.encodeFormat(ENC_DYN_FWD, wire_pkt, rpkt, PSEUDO_PKT_DCE_SEG); if (DCE2_SsnFromClient(wire_pkt)) { data_overhead = DCE2_MOCK_HDR_LEN__SMB_CLI; memset((void*)rpkt->payload, 0, data_overhead); DCE2_SmbInitRdata((uint8_t *)rpkt->payload, FLAG_FROM_CLIENT); } else { data_overhead = DCE2_MOCK_HDR_LEN__SMB_SRV; memset((void*)rpkt->payload, 0, data_overhead); DCE2_SmbInitRdata((uint8_t *)rpkt->payload, FLAG_FROM_SERVER); } break; case DCE2_RPKT_TYPE__SMB_CO_FRAG: _dpd.encodeFormat(ENC_DYN_FWD, wire_pkt, rpkt, PSEUDO_PKT_DCE_FRAG); if (DCE2_SsnFromClient(wire_pkt)) { data_overhead = DCE2_MOCK_HDR_LEN__SMB_CLI + DCE2_MOCK_HDR_LEN__CO_CLI; memset((void*)rpkt->payload, 0, data_overhead); DCE2_SmbInitRdata((uint8_t *)rpkt->payload, FLAG_FROM_CLIENT); DCE2_CoInitRdata((uint8_t *)rpkt->payload + DCE2_MOCK_HDR_LEN__SMB_CLI, FLAG_FROM_CLIENT); } else { data_overhead = DCE2_MOCK_HDR_LEN__SMB_SRV + DCE2_MOCK_HDR_LEN__CO_SRV; memset((void*)rpkt->payload, 0, data_overhead); DCE2_SmbInitRdata((uint8_t *)rpkt->payload, FLAG_FROM_SERVER); DCE2_CoInitRdata((uint8_t *)rpkt->payload + DCE2_MOCK_HDR_LEN__SMB_SRV, FLAG_FROM_SERVER); } break; case DCE2_RPKT_TYPE__TCP_CO_SEG: _dpd.encodeFormat(ENC_DYN_FWD, wire_pkt, rpkt, PSEUDO_PKT_DCE_SEG); break; case DCE2_RPKT_TYPE__TCP_CO_FRAG: _dpd.encodeFormat(ENC_DYN_FWD, wire_pkt, rpkt, PSEUDO_PKT_DCE_FRAG); if (DCE2_SsnFromClient(wire_pkt)) { data_overhead = DCE2_MOCK_HDR_LEN__CO_CLI; memset((void*)rpkt->payload, 0, data_overhead); DCE2_CoInitRdata((uint8_t *)rpkt->payload, FLAG_FROM_CLIENT); } else { data_overhead = DCE2_MOCK_HDR_LEN__CO_SRV; memset((void*)rpkt->payload, 0, data_overhead); DCE2_CoInitRdata((uint8_t *)rpkt->payload, FLAG_FROM_SERVER); } break; case DCE2_RPKT_TYPE__UDP_CL_FRAG: _dpd.encodeFormat(ENC_DYN_FWD, wire_pkt, rpkt, PSEUDO_PKT_DCE_FRAG); data_overhead = DCE2_MOCK_HDR_LEN__CL; memset((void*)rpkt->payload, 0, data_overhead); DCE2_ClInitRdata((uint8_t *)rpkt->payload); break; default: DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Invalid reassembly packet type: %d", __FILE__, __LINE__, rpkt_type); return NULL; } payload_len = rpkt->max_payload; if ((data_overhead + data_len) > payload_len) data_len -= (data_overhead + data_len) - payload_len; status = DCE2_Memcpy( (void *)(rpkt->payload + data_overhead), (void *)data, (size_t)data_len, (void *)rpkt->payload, (void *)((uint8_t *)rpkt->payload + payload_len)); if (status != DCE2_RET__SUCCESS) { DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Failed to copy data into reassembly packet.", __FILE__, __LINE__); return NULL; } rpkt->payload_size = (uint16_t)(data_overhead + data_len); _dpd.encodeUpdate(rpkt); if (wire_pkt->family == AF_INET) { rpkt->ip4h->ip_len = rpkt->ip4_header->data_length; } else { IP6RawHdr* ip6h = (IP6RawHdr*)rpkt->raw_ip6_header; if ( ip6h ) rpkt->ip6h->len = ip6h->ip6_payload_len; } rpkt->flags |= FLAG_STREAM_EST; if (DCE2_SsnFromClient(wire_pkt)) rpkt->flags |= FLAG_FROM_CLIENT; else rpkt->flags |= FLAG_FROM_SERVER; rpkt->stream_session = wire_pkt->stream_session; return rpkt; }
/********************************************************************* * Function: DCE2_Process() * * Purpose: Main entry point for DCE/RPC processing. * * Arguments: * SFSnortPacket * - pointer to packet structure * * Returns: * DCE2_Ret - status * *********************************************************************/ DCE2_Ret DCE2_Process(SFSnortPacket *p) { tSfPolicyId policy_id = _dpd.getNapRuntimePolicy(); DCE2_SsnData *sd = (DCE2_SsnData *)DCE2_SsnGetAppData(p); PROFILE_VARS; PREPROC_PROFILE_START(dce2_pstat_session); if ((sd != NULL) && DCE2_SsnNoInspect(sd)) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "Session set to " "not inspect. Returning\n")); PREPROC_PROFILE_END(dce2_pstat_session); return DCE2_RET__NOT_INSPECTED; } dce2_eval_config = (DCE2_Config *)sfPolicyUserDataGet(dce2_config, policy_id); if (sd != NULL) dce2_eval_config = (DCE2_Config *)sfPolicyUserDataGet(sd->config, sd->policy_id); if (dce2_eval_config == NULL) { PREPROC_PROFILE_END(dce2_pstat_session); return DCE2_RET__NOT_INSPECTED; } if (sd == NULL) { sd = DCE2_NewSession(p, policy_id); if (sd == NULL) { PREPROC_PROFILE_END(dce2_pstat_session); return DCE2_RET__NOT_INSPECTED; } } else { sd->wire_pkt = p; if (_dpd.isPafEnabled() && !DCE2_SsnIsPafActive(p)) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "PAF was aborted on " "one or both sides - aborting session inspection\n")); DCE2_SetNoInspect(sd); PREPROC_PROFILE_END(dce2_pstat_session); return DCE2_RET__NOT_INSPECTED; } if (IsTCP(p) && !DCE2_SsnIsRebuilt(p)) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "Got non-rebuilt packet " "on session (%p)\n", (void *)sd)); if (DCE2_SsnIsStreamInsert(p)) { if (!_dpd.isPafEnabled()) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "Flushing opposite direction.\n")); DCE2_SsnFlush(p); } DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "Stream inserted - not inspecting.\n")); } else { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "Got non-stream inserted packet " "- not inspecting\n")); } PREPROC_PROFILE_END(dce2_pstat_session); return DCE2_RET__NOT_INSPECTED; } else if (DCE2_SsnAutodetected(sd) && !(p->flags & sd->autodetect_dir)) { /* Try to autodetect in opposite direction */ if ((sd->trans != DCE2_TRANS_TYPE__HTTP_PROXY) && (sd->trans != DCE2_TRANS_TYPE__HTTP_SERVER) && (DCE2_GetAutodetectTransport(p, sd->sconfig) != sd->trans)) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "Bad autodetect.\n")); DCE2_SetNoInspect(sd); dce2_stats.bad_autodetects++; PREPROC_PROFILE_END(dce2_pstat_session); return DCE2_RET__NOT_INSPECTED; } DCE2_SsnClearAutodetected(sd); } } DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "Session pointer: %p\n", (void *)sd)); if (IsTCP(p) && (DCE2_SetSsnState(sd, p) != DCE2_RET__SUCCESS)) { PREPROC_PROFILE_END(dce2_pstat_session); return DCE2_RET__NOT_INSPECTED; } if (DCE2_PushPkt((void *)p) != DCE2_RET__SUCCESS) { DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Failed to push packet onto packet stack.", __FILE__, __LINE__); PREPROC_PROFILE_END(dce2_pstat_session); return DCE2_RET__NOT_INSPECTED; } p->flags |= FLAG_ALLOW_MULTIPLE_DETECT; dce2_detected = 0; PREPROC_PROFILE_END(dce2_pstat_session); switch (sd->trans) { case DCE2_TRANS_TYPE__SMB: DCE2_SmbProcess((DCE2_SmbSsnData *)sd); break; case DCE2_TRANS_TYPE__TCP: DCE2_TcpProcess((DCE2_TcpSsnData *)sd); break; case DCE2_TRANS_TYPE__UDP: DCE2_UdpProcess((DCE2_UdpSsnData *)sd); break; case DCE2_TRANS_TYPE__HTTP_PROXY: DCE2_HttpProcessProxy((DCE2_HttpSsnData *)sd); break; case DCE2_TRANS_TYPE__HTTP_SERVER: DCE2_HttpProcessServer((DCE2_HttpSsnData *)sd); break; default: DCE2_Log(DCE2_LOG_TYPE__ERROR, "%s(%d) Invalid transport type: %d", __FILE__, __LINE__, sd->trans); return DCE2_RET__NOT_INSPECTED; } if (sd->flags & DCE2_SSN_FLAG__NO_INSPECT) { DCE2_SetNoInspect(sd); DCE2_PopPkt(); PREPROC_PROFILE_END(dce2_pstat_session); return DCE2_RET__NOT_INSPECTED; } if (!dce2_detected) DCE2_Detect(sd); DCE2_ResetRopts(&sd->ropts); DCE2_PopPkt(); if (dce2_mem_state == DCE2_MEM_STATE__MEMCAP) { DCE2_SetNoInspect(sd); dce2_mem_state = DCE2_MEM_STATE__OKAY; return DCE2_RET__NOT_INSPECTED; } if (DCE2_SsnAutodetected(sd)) return DCE2_RET__NOT_INSPECTED; return DCE2_RET__INSPECTED; }