/********************************************************************* * Function: * * Purpose: * * Arguments: * * Returns: * *********************************************************************/ static DCE2_TransType DCE2_GetDetectTransport(SFSnortPacket *p, const DCE2_ServerConfig *sc) { DCE2_TransType trans = DCE2_TRANS_TYPE__NONE; uint16_t port; if (DCE2_SsnFromServer(p)) port = p->src_port; else port = p->dst_port; /* Check our configured ports to see if we should continue processing */ if (IsTCP(p)) { if (DCE2_ScIsDetectPortSet(sc, port, DCE2_TRANS_TYPE__SMB)) trans = DCE2_TRANS_TYPE__SMB; else if (DCE2_ScIsDetectPortSet(sc, port, DCE2_TRANS_TYPE__TCP)) trans = DCE2_TRANS_TYPE__TCP; else if (DCE2_ScIsDetectPortSet(sc, port, DCE2_TRANS_TYPE__HTTP_PROXY)) trans = DCE2_TRANS_TYPE__HTTP_PROXY; else if (DCE2_ScIsDetectPortSet(sc, port, DCE2_TRANS_TYPE__HTTP_SERVER)) trans = DCE2_TRANS_TYPE__HTTP_SERVER; } else /* it's UDP */ { if (DCE2_ScIsDetectPortSet(sc, port, DCE2_TRANS_TYPE__UDP)) trans = DCE2_TRANS_TYPE__UDP; } return trans; }
/********************************************************************* * Function: DCE2_GetAutodetectTransport() * * * Arguments: * * Returns: * *********************************************************************/ static DCE2_TransType DCE2_GetAutodetectTransport(SFSnortPacket *p, const DCE2_ServerConfig *sc) { DCE2_TransType trans = DCE2_TRANS_TYPE__NONE; uint16_t port; if (DCE2_SsnFromServer(p)) port = p->src_port; else port = p->dst_port; if (IsTCP(p)) { /* Look for raw DCE/RCP over TCP first, since it's * more likely not to have configured a port for this. */ if (DCE2_ScIsAutodetectPortSet(sc, port, DCE2_TRANS_TYPE__TCP)) { trans = DCE2_TcpAutodetect(p); if (trans != DCE2_TRANS_TYPE__NONE) return trans; } if (DCE2_ScIsAutodetectPortSet(sc, port, DCE2_TRANS_TYPE__HTTP_SERVER)) { trans = DCE2_HttpAutodetectServer(p); if (trans != DCE2_TRANS_TYPE__NONE) return trans; } if (DCE2_ScIsAutodetectPortSet(sc, port, DCE2_TRANS_TYPE__HTTP_PROXY)) { trans = DCE2_HttpAutodetectProxy(p); if (trans != DCE2_TRANS_TYPE__NONE) return trans; } if (DCE2_ScIsAutodetectPortSet(sc, port, DCE2_TRANS_TYPE__SMB)) { trans = DCE2_SmbAutodetect(p); if (trans != DCE2_TRANS_TYPE__NONE) return trans; } } else /* it's UDP */ { if (DCE2_ScIsAutodetectPortSet(sc, port, DCE2_TRANS_TYPE__UDP)) { trans = DCE2_UdpAutodetect(p); if (trans != DCE2_TRANS_TYPE__NONE) return trans; } } return DCE2_TRANS_TYPE__NONE; }
/******************************************************************** * Function: DCE2_HttpProcessServer() * * Wrapper arount main processing point for an RPC over HTTP * session. Checks and sets session setup state for a server. * * Arguments: * DCE2_HttpSsnData * * Pointer to an RPC over HTTP session data structure. * * Returns: None * ********************************************************************/ void DCE2_HttpProcessServer(DCE2_HttpSsnData *hsd) { const SFSnortPacket *p = hsd->sd.wire_pkt; DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "Processing RPC over HTTP server packet.\n")); dce2_stats.http_server_pkts++; if (hsd->state == DCE2_HTTP_STATE__NONE) { if (DCE2_SsnFromServer(p)) hsd->state = DCE2_HTTP_STATE__INIT_SERVER; } DCE2_HttpProcess(hsd); }
/********************************************************************* * Function: DCE2_Main() * * Purpose: Main entry point for DCE/RPC processing. * * Arguments: * void * - pointer to packet structure * void * - pointer to context * * Returns: None * *********************************************************************/ static void DCE2_Main(void *pkt, void *context) { SFSnortPacket *p = (SFSnortPacket *)pkt; PROFILE_VARS; DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ALL, "%s\n", DCE2_DEBUG__START_MSG)); sfPolicyUserPolicySet (dce2_config, _dpd.getRuntimePolicy()); #ifdef DEBUG_MSGS if (DCE2_SsnFromServer(p)) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "Packet from Server.\n")); } else { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "Packet from Client.\n")); } #endif /* No inspection to do */ if ((p->payload_size == 0) || (p->payload == NULL)) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "No payload - not inspecting.\n")); DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ALL, "%s\n", DCE2_DEBUG__END_MSG)); return; } else if (p->stream_session_ptr == NULL) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "No session pointer - not inspecting.\n")); DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ALL, "%s\n", DCE2_DEBUG__END_MSG)); return; } else if (!IsTCP(p) && !IsUDP(p)) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "Not UDP or TCP - not inspecting.\n")); DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ALL, "%s\n", DCE2_DEBUG__END_MSG)); return; } if (IsTCP(p)) { if (DCE2_SsnIsMidstream(p)) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "Midstream - not inspecting.\n")); DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ALL, "%s\n", DCE2_DEBUG__END_MSG)); return; } else if (!DCE2_SsnIsEstablished(p)) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "Not established - not inspecting.\n")); DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ALL, "%s\n", DCE2_DEBUG__END_MSG)); return; } } PREPROC_PROFILE_START(dce2_pstat_main); if (DCE2_Process(p) == DCE2_RET__INSPECTED) DCE2_DisableDetect(p); PREPROC_PROFILE_END(dce2_pstat_main); DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__ALL, "%s\n", DCE2_DEBUG__END_MSG)); }
/********************************************************************* * 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_SetSsnState() * * Purpose: * Checks for missing packets and overlapping data on session * * Arguments: * DCE2_SsnData * - session data pointer * SFSnortPacket * - packet structure * * Returns: * DCE2_RET__SUCCESS * DCE2_RET__ERROR * ********************************************************************/ static DCE2_Ret DCE2_SetSsnState(DCE2_SsnData *sd, SFSnortPacket *p) { uint32_t pkt_seq = ntohl(p->tcp_header->sequence); PROFILE_VARS; PREPROC_PROFILE_START(dce2_pstat_session_state); DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "Payload size: %u\n", p->payload_size)); if (DCE2_SsnFromClient(p) && !DCE2_SsnSeenClient(sd)) { uint32_t pkt_ack = ntohl(p->tcp_header->acknowledgement); if (DCE2_SsnSeenServer(sd) && SEQ_LT(sd->cli_seq, pkt_seq) && (sd->trans != DCE2_TRANS_TYPE__HTTP_SERVER)) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "Missing packets on session - aborting session inspection\n")); DCE2_SetNoInspect(sd); PREPROC_PROFILE_END(dce2_pstat_session_state); return DCE2_RET__ERROR; } DCE2_SsnSetSeenClient(sd); sd->cli_seq = pkt_seq; sd->cli_nseq = pkt_seq + p->payload_size; if (!DCE2_SsnSeenServer(sd)) sd->srv_seq = sd->srv_nseq = pkt_ack; DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "Initial client => seq: %u, " "next seq: %u\n", sd->cli_seq, sd->cli_nseq)); } else if (DCE2_SsnFromServer(p) && !DCE2_SsnSeenServer(sd)) { uint32_t pkt_ack = ntohl(p->tcp_header->acknowledgement); if ((DCE2_SsnSeenClient(sd) && SEQ_LT(sd->srv_seq, pkt_seq)) || (!DCE2_SsnSeenClient(sd) && (sd->trans != DCE2_TRANS_TYPE__HTTP_SERVER))) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "Missing packets on session - aborting session inspection\n")); PREPROC_PROFILE_END(dce2_pstat_session_state); DCE2_SetNoInspect(sd); return DCE2_RET__ERROR; } DCE2_SsnSetSeenServer(sd); sd->srv_seq = pkt_seq; sd->srv_nseq = pkt_seq + p->payload_size; if (!DCE2_SsnSeenClient(sd)) sd->cli_seq = sd->cli_nseq = pkt_ack; DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "Initial server => seq: %u, " "next seq: %u\n", sd->srv_seq, sd->srv_nseq)); } else { uint32_t *ssn_seq; uint32_t *ssn_nseq; if (DCE2_SsnFromClient(p)) { ssn_seq = &sd->cli_seq; ssn_nseq = &sd->cli_nseq; DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "Client last => seq: %u, " "next seq: %u\n", sd->cli_seq, sd->cli_nseq)); DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "This packet => seq: %u, " "next seq: %u\n", pkt_seq, pkt_seq + p->payload_size)); } else { ssn_seq = &sd->srv_seq; ssn_nseq = &sd->srv_nseq; DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "Server last => seq: %u, " "next seq: %u\n", sd->srv_seq, sd->srv_nseq)); DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "This packet => seq: %u, " "next seq: %u\n", pkt_seq, pkt_seq + p->payload_size)); } if (*ssn_nseq != pkt_seq) { if (SEQ_LT(*ssn_nseq, pkt_seq)) { DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "Next expected sequence number (%u) is less than " "this sequence number (%u).\n", *ssn_nseq, pkt_seq)); DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "Missing packets on session - aborting session inspection\n")); DCE2_SetNoInspect(sd); PREPROC_PROFILE_END(dce2_pstat_session_state); return DCE2_RET__ERROR; } else { /* Got some kind of overlap. This shouldn't happen since we're doing * reassembly on both sides and not looking at non-reassembled packets * Actually this can happen if the stream seg list is empty */ DEBUG_WRAP(DCE2_DebugMsg(DCE2_DEBUG__MAIN, "Overlap => seq: %u, " "next seq: %u - aborting session inspection\n", pkt_seq, pkt_seq + p->payload_size)); DCE2_SetNoInspect(sd); PREPROC_PROFILE_END(dce2_pstat_session_state); return DCE2_RET__ERROR; } } *ssn_seq = pkt_seq; *ssn_nseq = pkt_seq + p->payload_size; } PREPROC_PROFILE_END(dce2_pstat_session_state); return DCE2_RET__SUCCESS; }