static inline int _Active_DoReset(Packet *p) { #ifdef ACTIVE_RESPONSE if ( !Active_IsEnabled() ) return 0; if ( Active_PacketWouldBeDropped() ) return 0; if ( !IPH_IS_VALID(p) ) return 0; switch ( GET_IPH_PROTO(p) ) { case IPPROTO_TCP: if ( Active_IsRSTCandidate(p) ) Active_QueueReject(); break; // FIXTHIS send unr to udp/icmp4/icmp6 only or for all non-tcp? case IPPROTO_UDP: case IPPROTO_ICMP: case IPPROTO_ICMPV6: if ( Active_IsUNRCandidate(p) ) Active_QueueReject(); break; } #endif return 0; }
/** ** This logic finds the index to the proto array based on the ** portscan configuration. We need special logic because the ** index of the protocol changes based on the configuration. */ static int ps_get_proto(PS_PKT *ps_pkt, int *proto) { Packet *p; if(!ps_pkt || !ps_pkt->pkt || !proto) return -1; p = (Packet *)ps_pkt->pkt; *proto = 0; if (portscan_eval_config->detect_scans & PS_PROTO_TCP) { if ((p->tcph != NULL) || ((p->icmph != NULL) && (p->icmph->type == ICMP_DEST_UNREACH) && ((p->icmph->code == ICMP_PORT_UNREACH) || (p->icmph->code == ICMP_PKT_FILTERED)) && (p->orig_tcph != NULL))) { *proto = PS_PROTO_TCP; return 0; } } if (portscan_eval_config->detect_scans & PS_PROTO_UDP) { if ((p->udph != NULL) || ((p->icmph != NULL) && (p->icmph->type == ICMP_DEST_UNREACH) && ((p->icmph->code == ICMP_PORT_UNREACH) || (p->icmph->code == ICMP_PKT_FILTERED)) && (p->orig_udph != NULL))) { *proto = PS_PROTO_UDP; return 0; } } if (portscan_eval_config->detect_scans & PS_PROTO_IP) { if ((IPH_IS_VALID(p) && (p->icmph == NULL)) || ((p->icmph != NULL) && (p->icmph->type == ICMP_DEST_UNREACH) && ((p->icmph->code == ICMP_PROT_UNREACH) || (p->icmph->code == ICMP_PKT_FILTERED)))) { *proto = PS_PROTO_IP; return 0; } } if (portscan_eval_config->detect_scans & PS_PROTO_ICMP) { if (p->icmph != NULL) { *proto = PS_PROTO_ICMP; return 0; } } return -1; }
/** ** This function wraps the functionality in the generic HttpInspect ** processing. We get a Packet structure and pass this into the ** HttpInspect module where the first stage in HttpInspect is the ** Session Inspection stage where most of the other Snortisms are ** taken care of. After that, the modules should be fairly generic, ** and that's what we're trying to do here. ** ** @param p a Packet structure that contains Snort info about the ** packet. ** ** @return void */ static void HttpInspect(Packet *p, void *context) { PROFILE_VARS; /* ** IMPORTANT: ** This is where we initialize any variables that can impact other ** aspects of detection/processing. ** ** First thing that we do is reset the p->uri_count to zero, so there ** is no way that we would inspect a buffer that was completely bogus. */ p->uri_count = 0; UriBufs[0].decode_flags = 0; /* ** Check for valid packet ** if neither header or data is good, then we just abort. */ if(!IPH_IS_VALID(p) || !p->tcph || !p->data || !p->dsize) { return; } PREPROC_PROFILE_START(hiPerfStats); /* ** Pass in the configuration and the packet. */ SnortHttpInspect(&GlobalConf, p); p->uri_count = 0; UriBufs[0].decode_flags = 0; /* XXX: * NOTE: this includes the HTTPInspect directly * calling the detection engine - * to get the true HTTPInspect only stats, have another * var inside SnortHttpInspect that tracks the time * spent in Detect(). * Subtract the ticks from this if iCallDetect == 0 */ PREPROC_PROFILE_END(hiPerfStats); #ifdef PERF_PROFILING if (hiDetectCalled) { hiPerfStats.ticks -= hiDetectPerfStats.ticks; /* And Reset ticks to 0 */ hiDetectPerfStats.ticks = 0; hiDetectCalled = 0; } #endif return; }
int GetSessionCount(Packet *p) { if (IPH_IS_VALID(p)) { if (GET_IPH_PROTO(p) == IPPROTO_TCP) { if (sessionHashTable) return sessionHashTable->count; else return 0; } else { if (udpSessionHashTable) return udpSessionHashTable->count; else return 0; } } return 0; }
/** ** Check the incoming packet to decide whether portscan detection cares ** about this packet. We try to ignore as many packets as possible. */ static int ps_filter_ignore(PS_PKT *ps_pkt) { Packet *p; int reverse_pkt = 0; snort_ip_p scanner, scanned; p = (Packet *)ps_pkt->pkt; if(!IPH_IS_VALID(p)) return 1; if(p->tcph) { if(!(portscan_eval_config->detect_scans & PS_PROTO_TCP)) return 1; /* ** This is where we check all of snort's flags for different ** TCP session scenarios. The checks cover: ** ** - dropping packets in established sessions, but not the ** TWH packet. ** - dropping the SYN/ACK packet from the server on a valid ** connection (we'll catch the TWH later if it happens). */ /* ** Ignore packets that are already part of an established TCP ** stream. */ if(((p->packet_flags & (PKT_STREAM_EST | PKT_STREAM_TWH)) == PKT_STREAM_EST) && !(p->tcph->th_flags & TH_RST)) { return 1; } /* ** Ignore the server's initial response, unless it's to RST ** the connection. */ /* if(!(p->tcph->th_flags & TH_RST) && !(p->packet_flags & (PKT_STREAM_EST)) && (p->packet_flags & PKT_FROM_SERVER)) { return 1; } */ } else if(p->udph) { if(!(portscan_eval_config->detect_scans & PS_PROTO_UDP)) return 1; } else if(p->icmph) { if(p->icmph->type != ICMP_DEST_UNREACH && !(portscan_eval_config->detect_scans & PS_PROTO_ICMP)) { return 1; } } else { if(!(portscan_eval_config->detect_scans & PS_PROTO_IP)) return 1; } /* ** Check if the packet is reversed */ if((p->packet_flags & PKT_FROM_SERVER)) { reverse_pkt = 1; } else if(p->icmph && p->icmph->type == ICMP_DEST_UNREACH) { reverse_pkt = 1; } else if (p->udph && p->ssnptr && stream_api && stream_api->version >= STREAM_API_VERSION5) { if (stream_api->get_packet_direction(p) & PKT_FROM_SERVER) reverse_pkt = 1; } scanner = GET_SRC_IP(p); scanned = GET_DST_IP(p); if(reverse_pkt) { if(ps_ignore_ip(scanned, p->dp, scanner, p->sp)) return 1; } else { if(ps_ignore_ip(scanner, p->sp, scanned, p->dp)) return 1; } ps_pkt->reverse_pkt = reverse_pkt; if(portscan_eval_config->watch_ip) { if(ipset_contains(portscan_eval_config->watch_ip, scanner, &(p->sp))) return 0; if(ipset_contains(portscan_eval_config->watch_ip, scanned, &(p->dp))) return 0; return 1; } return 0; }
/* * Check header option specified against packet * * Return 1 if check is true (e.g. data matches) * Return 0 if check is not true. */ ENGINE_LINKAGE int checkHdrOpt(void *p, HdrOptCheck *optData) { SFSnortPacket *pkt = (SFSnortPacket *)p; /* Header field will be extracted from its native * 1 or 2 bytes, converted to host byte order, * and placed in a 4 byte value for easy comparison */ uint32_t value = 0; if ((optData->hdrField & IP_HDR_OPTCHECK_MASK) && (!pkt->ip4_header)) return RULE_NOMATCH; if ((optData->hdrField & TCP_HDR_OPTCHECK_MASK) && (!pkt->ip4_header || !pkt->tcp_header)) return RULE_NOMATCH; if ((optData->hdrField & ICMP_HDR_OPTCHECK_MASK) && (!IPH_IS_VALID(pkt) || !pkt->icmp_header)) return RULE_NOMATCH; switch (optData->hdrField) { /* IP Header Checks */ case IP_HDR_ID: value = IS_IP6(pkt) ? ntohl(GET_IPH_ID(pkt)) : ntohs((uint16_t)GET_IPH_ID(pkt)); break; case IP_HDR_PROTO: //value = pkt->ip4_header->proto; value = GET_IPH_PROTO(pkt); break; case IP_HDR_FRAGBITS: return checkBits(optData->value, optData->op, ((ntohs(GET_IPH_OFF(pkt)) & 0xe000) & ~optData->mask_value)); break; case IP_HDR_FRAGOFFSET: value = ntohs(GET_IPH_OFF((pkt))) & 0x1FFF; break; case IP_HDR_TOS: //value = pkt->ip4_header->type_service; value = GET_IPH_TOS(pkt); break; case IP_HDR_TTL: //value = pkt->ip4_header->time_to_live; value = GET_IPH_TTL(pkt); break; case IP_HDR_OPTIONS: return checkOptions(optData->value, optData->op, pkt->ip_options, pkt->num_ip_options); break; /* TCP Header checks */ case TCP_HDR_ACK: value = ntohl(pkt->tcp_header->acknowledgement); break; case TCP_HDR_SEQ: value = ntohl(pkt->tcp_header->sequence); break; case TCP_HDR_FLAGS: return checkBits(optData->value, optData->op, (pkt->tcp_header->flags & ~optData->mask_value)); break; case TCP_HDR_WIN: value = ntohs(pkt->tcp_header->window); break; case TCP_HDR_OPTIONS: return checkOptions(optData->value, optData->op, pkt->tcp_options, pkt->num_tcp_options); break; /* ICMP Header checks */ case ICMP_HDR_CODE: value = pkt->icmp_header->code; break; case ICMP_HDR_TYPE: value = pkt->icmp_header->type; break; case ICMP_HDR_ID: if ((pkt->icmp_header->code == ICMP_ECHO_REQUEST) || (pkt->icmp_header->code == ICMP_ECHO_REPLY)) { value = ntohs(pkt->icmp_header->icmp_header_union.echo.id); } else { return RULE_NOMATCH; } break; case ICMP_HDR_SEQ: if ((pkt->icmp_header->code == ICMP_ECHO_REQUEST) || (pkt->icmp_header->code == ICMP_ECHO_REPLY)) { value = ntohs(pkt->icmp_header->icmp_header_union.echo.seq); } else { return RULE_NOMATCH; } break; default: return RULE_NOMATCH; break; } return checkField(optData->op, value, optData->value); }
/* Main runtime entry point for SSH preprocessor. * Analyzes SSH packets for anomalies/exploits. * * PARAMETERS: * * packetp: Pointer to current packet to process. * contextp: Pointer to context block, not used. * * RETURNS: Nothing. */ static void ProcessSSH( void* ipacketp, void* contextp ) { SSHData* sessp = NULL; uint8_t source = 0; uint8_t dest = 0; uint8_t known_port = 0; uint8_t direction; SFSnortPacket* packetp; #ifdef TARGET_BASED int16_t app_id = SFTARGET_UNKNOWN_PROTOCOL; #endif tSfPolicyId policy_id = _dpd.getRuntimePolicy(); PROFILE_VARS; packetp = (SFSnortPacket*) ipacketp; sfPolicyUserPolicySet (ssh_config, policy_id); /* Make sure this preprocessor should run. */ if (( !packetp ) || ( !packetp->payload ) || ( !packetp->payload_size ) || ( !IPH_IS_VALID(packetp) ) || ( !packetp->tcp_header ) || /* check if we're waiting on stream reassembly */ ( packetp->flags & FLAG_STREAM_INSERT)) { return; } PREPROC_PROFILE_START(sshPerfStats); ssh_eval_config = sfPolicyUserDataGetCurrent(ssh_config); /* Attempt to get a previously allocated SSH block. */ sessp = _dpd.streamAPI->get_application_data(packetp->stream_session_ptr, PP_SSH); if (sessp != NULL) { ssh_eval_config = sfPolicyUserDataGet(sessp->config, sessp->policy_id); known_port = 1; } if (sessp == NULL) { /* If not doing autodetection, check the ports to make sure this is * running on an SSH port, otherwise no need to examine the traffic. */ #ifdef TARGET_BASED app_id = _dpd.streamAPI->get_application_protocol_id(packetp->stream_session_ptr); if (app_id == SFTARGET_UNKNOWN_PROTOCOL) { PREPROC_PROFILE_END(sshPerfStats); return; } if (app_id && (app_id != ssh_app_id)) { PREPROC_PROFILE_END(sshPerfStats); return; } if (app_id == ssh_app_id) { known_port = 1; } if (!app_id) { #endif source = (uint8_t)CheckSSHPort( packetp->src_port ); dest = (uint8_t)CheckSSHPort( packetp->dst_port ); if ( !ssh_eval_config->AutodetectEnabled && !source && !dest ) { /* Not one of the ports we care about. */ PREPROC_PROFILE_END(sshPerfStats); return; } #ifdef TARGET_BASED } #endif /* Check the stream session. If it does not currently * have our SSH data-block attached, create one. */ sessp = SSHGetNewSession(packetp, policy_id); if ( !sessp ) { /* Could not get/create the session data for this packet. */ PREPROC_PROFILE_END(sshPerfStats); return; } /* See if a known server port is involved. */ if (!known_port) { known_port = ( source || dest ? 1 : 0 ); /* If this is a non-SSH port, but autodetect is on, we flag this session to reduce false positives later on. */ if (!known_port && ssh_eval_config->AutodetectEnabled) { sessp->state_flags |= SSH_FLG_AUTODETECTED; } } } /* Don't process if we've missed packets */ if (sessp->state_flags & SSH_FLG_MISSED_PACKETS) return; /* If we picked up mid-stream or missed any packets (midstream pick up * means we've already missed packets) set missed packets flag and make * sure we don't do any more reassembly on this session */ if ((_dpd.streamAPI->get_session_flags(packetp->stream_session_ptr) & SSNFLAG_MIDSTREAM) || _dpd.streamAPI->missed_packets(packetp->stream_session_ptr, SSN_DIR_BOTH)) { /* Don't turn off reassembly if autodetected since another preprocessor * may actually be looking at this session as well and the SSH * autodetect of this session may be wrong. */ if (!(sessp->state_flags & SSH_FLG_AUTODETECTED)) { _dpd.streamAPI->set_reassembly(packetp->stream_session_ptr, STREAM_FLPOLICY_IGNORE, SSN_DIR_BOTH, STREAM_FLPOLICY_SET_ABSOLUTE); } sessp->state_flags |= SSH_FLG_MISSED_PACKETS; return; } /* We're interested in this session. Turn on stream reassembly. */ if ( !(sessp->state_flags & SSH_FLG_REASSEMBLY_SET )) { _dpd.streamAPI->set_reassembly(packetp->stream_session_ptr, STREAM_FLPOLICY_FOOTPRINT, SSN_DIR_BOTH, STREAM_FLPOLICY_SET_APPEND); sessp->state_flags |= SSH_FLG_REASSEMBLY_SET; } /* Get the direction of the packet. */ direction = ( (packetp->flags & FLAG_FROM_SERVER ) ? SSH_DIR_FROM_SERVER : SSH_DIR_FROM_CLIENT ); if ( !(sessp->state_flags & SSH_FLG_SESS_ENCRYPTED )) { /* If server and client have not performed the protocol * version exchange yet, must look for version strings. */ if ( (sessp->state_flags & SSH_FLG_BOTH_IDSTRING_SEEN) != SSH_FLG_BOTH_IDSTRING_SEEN ) { if ( ProcessSSHProtocolVersionExchange( sessp, packetp, direction, known_port ) == SSH_FAILURE ) { /*Error processing protovers exchange msg */ } PREPROC_PROFILE_END(sshPerfStats); return; } /* Expecting to see the key init exchange at this point * (in SSH2) or the actual key exchange if SSH1 */ if ((( sessp->state_flags & SSH_FLG_V1_KEYEXCH_DONE ) != SSH_FLG_V1_KEYEXCH_DONE ) && ((sessp->state_flags & SSH_FLG_V2_KEXINIT_DONE ) != SSH_FLG_V2_KEXINIT_DONE )) { ProcessSSHKeyInitExchange( sessp, packetp, direction ); PREPROC_PROFILE_END(sshPerfStats); return; } /* If SSH2, need to process the actual key exchange msgs. * The actual key exchange type was negotiated in the * key exchange init msgs. SSH1 won't arrive here. */ ProcessSSHKeyExchange( sessp, packetp, direction ); } else { /* Traffic on this session is currently encrypted. * Two of the major SSH exploits, SSH1 CRC-32 and * the Challenge-Response Overflow attack occur within * the encrypted portion of the SSH session. Therefore, * the only way to detect these attacks is by examining * amounts of data exchanged for anomalies. */ sessp->num_enc_pkts++; if ( sessp->num_enc_pkts <= ssh_eval_config->MaxEncryptedPackets ) { if ( direction == SSH_DIR_FROM_CLIENT ) { sessp->num_client_bytes += packetp->payload_size; if ( sessp->num_client_bytes >= ssh_eval_config->MaxClientBytes ) { /* Probable exploit in progress.*/ if (sessp->version == SSH_VERSION_1) { if ( ssh_eval_config->EnabledAlerts & SSH_ALERT_CRC32 ) { ALERT(SSH_EVENT_CRC32, SSH_EVENT_CRC32_STR); _dpd.streamAPI->stop_inspection( packetp->stream_session_ptr, packetp, SSN_DIR_BOTH, -1, 0 ); } } else { if (ssh_eval_config->EnabledAlerts & SSH_ALERT_RESPOVERFLOW ) { ALERT(SSH_EVENT_RESPOVERFLOW, SSH_EVENT_RESPOVERFLOW_STR); _dpd.streamAPI->stop_inspection( packetp->stream_session_ptr, packetp, SSN_DIR_BOTH, -1, 0 ); } } } } else { /* * Have seen a server response, so * this appears to be a valid exchange. * Reset suspicious byte count to zero. */ sessp->num_client_bytes = 0; } } else { /* Have already examined more than the limit * of encrypted packets. Both the Gobbles and * the CRC32 attacks occur during authentication * and therefore cannot be used late in an * encrypted session. For performance purposes, * stop examining this session. */ _dpd.streamAPI->stop_inspection( packetp->stream_session_ptr, packetp, SSN_DIR_BOTH, -1, 0 ); } } PREPROC_PROFILE_END(sshPerfStats); }
void ppm_pkt_log(ppm_cfg_t *ppm_cfg, Packet* p) { int filterEvent = 0; if (!ppm_cfg->max_pkt_ticks) return; ppm_cfg->pkt_event_cnt++; if (ppm_cfg->pkt_log & PPM_LOG_ALERT) { OptTreeNode* potn; Event ev; /* make sure we have an otn already in our table for this event */ potn = OtnLookup(snort_conf->otn_map, GENERATOR_PPM, PPM_EVENT_PACKET_ABORTED); if (potn == NULL) { /* have to make one */ potn = GenerateSnortEventOtn(GENERATOR_PPM, /* GID */ PPM_EVENT_PACKET_ABORTED, /* SID */ 1, /* Rev */ 0, /* classification */ 3, /* priority (low) */ PPM_EVENT_PACKET_ABORTED_STR /* msg string */); if (potn == NULL) return; OtnLookupAdd(snort_conf->otn_map, potn); } SetEvent(&ev, potn->sigInfo.generator, /* GID */ potn->sigInfo.id, /* SID */ potn->sigInfo.rev, /* Rev */ potn->sigInfo.class_id, /* classification */ potn->sigInfo.priority, /* priority (low) */ #if !defined(FEAT_OPEN_APPID) 0); #else /* defined(FEAT_OPEN_APPID) */ 0, NULL); #endif /* defined(FEAT_OPEN_APPID) */ if ( IPH_IS_VALID(p) ) { filterEvent = sfthreshold_test( potn->event_data.sig_generator, potn->event_data.sig_id, GET_SRC_IP(p), GET_DST_IP(p), p->pkth->ts.tv_sec); } else { snort_ip cleared; IP_CLEAR(cleared); filterEvent = sfthreshold_test( potn->event_data.sig_generator, potn->event_data.sig_id, IP_ARG(cleared), IP_ARG(cleared), p->pkth->ts.tv_sec); } if(filterEvent < 0) filterEvent = 0; else AlertAction(p, potn, &ev); }
/* Main runtime entry point */ static void ProcessModbus(void *ipacketp, void *contextp) { SFSnortPacket *packetp = (SFSnortPacket *)ipacketp; modbus_session_data_t *sessp; PROFILE_VARS; /* Sanity checks. Should this preprocessor run? */ if (( !packetp ) || ( !packetp->payload ) || ( !packetp->payload_size ) || ( !IPH_IS_VALID(packetp) ) || ( !packetp->tcp_header )) { return; } PREPROC_PROFILE_START(modbusPerfStats); /* Fetch me a preprocessor config to use with this VLAN/subnet/etc.! */ modbus_eval_config = sfPolicyUserDataGetCurrent(modbus_context_id); /* Look for a previously-allocated session data. */ sessp = _dpd.streamAPI->get_application_data(packetp->stream_session_ptr, PP_MODBUS); if (sessp == NULL) { /* No existing session. Check those ports. */ if (ModbusPortCheck(modbus_eval_config, packetp) != MODBUS_OK) { PREPROC_PROFILE_END(modbusPerfStats); return; } } if ( !PacketHasFullPDU(packetp) ) { /* If a packet is rebuilt, but not a full PDU, then it's garbage that got flushed at the end of a stream. */ if ( packetp->flags & (FLAG_REBUILT_STREAM|FLAG_PDU_HEAD) ) { _dpd.alertAdd(GENERATOR_SPP_MODBUS, MODBUS_BAD_LENGTH, 1, 0, 3, MODBUS_BAD_LENGTH_STR, 0); } PREPROC_PROFILE_END(modbusPerfStats); return; } if (sessp == NULL) { /* Create session data and attach it to the Stream5 session */ sessp = ModbusCreateSessionData(packetp); if ( !sessp ) { PREPROC_PROFILE_END(modbusPerfStats); return; } } /* When pipelined Modbus PDUs appear in a single TCP segment, the detection engine caches the results of the rule options after evaluating on the first PDU. Setting this flag stops the caching. */ packetp->flags |= FLAG_ALLOW_MULTIPLE_DETECT; /* Do preprocessor-specific detection stuff here */ ModbusDecode(modbus_eval_config, packetp); /* That's the end! */ PREPROC_PROFILE_END(modbusPerfStats); }
static int packet_to_data(Packet *p, void *event, idmef_alert_t *alert) { int i; if ( ! p ) return 0; add_int_data(alert, "snort_rule_sid", ntohl(((Unified2EventCommon *)event)->signature_id)); add_int_data(alert, "snort_rule_rev", ntohl(((Unified2EventCommon *)event)->signature_revision)); if ( IPH_IS_VALID(p) ) { add_int_data(alert, "ip_ver", GET_IPH_VER(p)); add_int_data(alert, "ip_hlen", GET_IPH_HLEN(p)); add_int_data(alert, "ip_tos", GET_IPH_TOS(p)); add_int_data(alert, "ip_len", ntohs(GET_IPH_LEN(p))); #ifdef SUP_IP6 // XXX-IPv6 need fragmentation ID #else add_int_data(alert, "ip_id", ntohs(p->iph->ip_id)); #endif #ifdef SUP_IP6 // XXX-IPv6 need fragmentation offset #else add_int_data(alert, "ip_off", ntohs(p->iph->ip_off)); #endif add_int_data(alert, "ip_ttl", GET_IPH_TTL(p)); add_int_data(alert, "ip_proto", GET_IPH_PROTO(p)); #ifdef SUP_IP6 // XXX-IPv6 need checksum #else add_int_data(alert, "ip_sum", ntohs(p->iph->ip_csum)); #endif for ( i = 0; i < p->ip_option_count; i++ ) { add_int_data(alert, "ip_option_code", p->ip_options[i].code); add_byte_data(alert, "ip_option_data", p->ip_options[i].data, p->ip_options[i].len); } } if ( p->tcph ) { add_int_data(alert, "tcp_seq", ntohl(p->tcph->th_seq)); add_int_data(alert, "tcp_ack", ntohl(p->tcph->th_ack)); add_int_data(alert, "tcp_off", TCP_OFFSET(p->tcph)); add_int_data(alert, "tcp_res", TCP_X2(p->tcph)); add_int_data(alert, "tcp_flags", p->tcph->th_flags); add_int_data(alert, "tcp_win", ntohs(p->tcph->th_win)); add_int_data(alert, "tcp_sum", ntohs(p->tcph->th_sum)); add_int_data(alert, "tcp_urp", ntohs(p->tcph->th_urp)); for ( i = 0; i < p->tcp_option_count; i++ ) { add_int_data(alert, "tcp_option_code", p->tcp_options[i].code); add_byte_data(alert, "tcp_option_data", p->tcp_options[i].data, p->tcp_options[i].len); } } else if ( p->udph ) { add_int_data(alert, "udp_len", ntohs(p->udph->uh_len)); add_int_data(alert, "udp_sum", ntohs(p->udph->uh_chk)); } else if ( p->icmph ) { add_int_data(alert, "icmp_type", p->icmph->type); add_int_data(alert, "icmp_code", p->icmph->code); add_int_data(alert, "icmp_sum", ntohs(p->icmph->csum)); switch ( p->icmph->type ) { case ICMP_ECHO: case ICMP_ECHOREPLY: case ICMP_INFO_REQUEST: case ICMP_INFO_REPLY: case ICMP_ADDRESS: case ICMP_TIMESTAMP: add_int_data(alert, "icmp_id", ntohs(p->icmph->s_icmp_id)); add_int_data(alert, "icmp_seq", ntohs(p->icmph->s_icmp_seq)); break; case ICMP_ADDRESSREPLY: add_int_data(alert, "icmp_id", ntohs(p->icmph->s_icmp_id)); add_int_data(alert, "icmp_seq", ntohs(p->icmph->s_icmp_seq)); add_int_data(alert, "icmp_mask", (uint32_t) ntohl(p->icmph->s_icmp_mask)); break; case ICMP_REDIRECT: #ifndef SUP_IP6 add_string_data(alert, "icmp_gwaddr", inet_ntoa(p->icmph->s_icmp_gwaddr)); #else { sfip_t gwaddr; sfip_set_raw(&gwaddr, (void *)&p->icmph->s_icmp_gwaddr.s_addr, AF_INET); add_string_data(alert, "icmp_gwaddr", inet_ntoa(&gwaddr)); } #endif break; case ICMP_ROUTER_ADVERTISE: add_int_data(alert, "icmp_num_addrs", p->icmph->s_icmp_num_addrs); add_int_data(alert, "icmp_wpa", p->icmph->s_icmp_wpa); add_int_data(alert, "icmp_lifetime", ntohs(p->icmph->s_icmp_lifetime)); break; case ICMP_TIMESTAMPREPLY: add_int_data(alert, "icmp_id", ntohs(p->icmph->s_icmp_id)); add_int_data(alert, "icmp_seq", ntohs(p->icmph->s_icmp_seq)); add_int_data(alert, "icmp_otime", p->icmph->s_icmp_otime); add_int_data(alert, "icmp_rtime", p->icmph->s_icmp_rtime); add_int_data(alert, "icmp_ttime", p->icmph->s_icmp_ttime); break; } } add_byte_data(alert, "payload", p->data, p->dsize); return 0; }
static int event_to_source_target(Packet *p, idmef_alert_t *alert) { int ret; idmef_node_t *node; idmef_source_t *source; idmef_target_t *target; idmef_address_t *address; idmef_service_t *service; prelude_string_t *string; static char saddr[128], daddr[128]; if ( !p ) return 0; if ( ! IPH_IS_VALID(p) ) return 0; ret = idmef_alert_new_source(alert, &source, IDMEF_LIST_APPEND); if ( ret < 0 ) return ret; if (barnyard2_conf->interface != NULL) { ret = idmef_source_new_interface(source, &string); if ( ret < 0 ) return ret; prelude_string_set_ref(string, PRINT_INTERFACE(barnyard2_conf->interface)); } ret = idmef_source_new_service(source, &service); if ( ret < 0 ) return ret; if ( p->tcph || p->udph ) idmef_service_set_port(service, p->sp); idmef_service_set_ip_version(service, GET_IPH_VER(p)); idmef_service_set_iana_protocol_number(service, GET_IPH_PROTO(p)); ret = idmef_source_new_node(source, &node); if ( ret < 0 ) return ret; ret = idmef_node_new_address(node, &address, IDMEF_LIST_APPEND); if ( ret < 0 ) return ret; ret = idmef_address_new_address(address, &string); if ( ret < 0 ) return ret; SnortSnprintf(saddr, sizeof(saddr), "%s", inet_ntoa(GET_SRC_ADDR(p))); prelude_string_set_ref(string, saddr); ret = idmef_alert_new_target(alert, &target, IDMEF_LIST_APPEND); if ( ret < 0 ) return ret; if (barnyard2_conf->interface != NULL) { ret = idmef_target_new_interface(target, &string); if ( ret < 0 ) return ret; prelude_string_set_ref(string, barnyard2_conf->interface); } ret = idmef_target_new_service(target, &service); if ( ! ret < 0 ) return ret; if ( p->tcph || p->udph ) idmef_service_set_port(service, p->dp); idmef_service_set_ip_version(service, GET_IPH_VER(p)); idmef_service_set_iana_protocol_number(service, GET_IPH_PROTO(p)); ret = idmef_target_new_node(target, &node); if ( ret < 0 ) return ret; ret = idmef_node_new_address(node, &address, IDMEF_LIST_APPEND); if ( ret < 0 ) return ret; ret = idmef_address_new_address(address, &string); if ( ret < 0 ) return ret; SnortSnprintf(daddr, sizeof(daddr), "%s", inet_ntoa(GET_DST_ADDR(p))); prelude_string_set_ref(string, daddr); return 0; }
/* Main runtime entry point */ static void ProcessDNP3(void *ipacketp, void *contextp) { SFSnortPacket *packetp = (SFSnortPacket *)ipacketp; MemBucket *tmp_bucket = NULL; dnp3_session_data_t *sessp = NULL; PROFILE_VARS; /* Sanity checks. Should this preprocessor run? */ if (( !packetp ) || ( !packetp->payload ) || ( !packetp->payload_size ) || ( !IPH_IS_VALID(packetp) ) || ( !packetp->tcp_header && !packetp->udp_header )) { return; } /* If TCP, require that PAF flushes full PDUs first. */ if (packetp->tcp_header && !PacketHasFullPDU(packetp)) return; PREPROC_PROFILE_START(dnp3PerfStats); /* When pipelined DNP3 PDUs appear in a single TCP segment or UDP packet, the detection engine caches the results of the rule options after evaluating on the first PDU. Setting this flag stops the caching. */ packetp->flags |= FLAG_ALLOW_MULTIPLE_DETECT; /* Fetch me a preprocessor config to use with this VLAN/subnet/etc.! */ dnp3_eval_config = sfPolicyUserDataGetCurrent(dnp3_context_id); /* Look for a previously-allocated session data. */ tmp_bucket = _dpd.streamAPI->get_application_data(packetp->stream_session_ptr, PP_DNP3); if (tmp_bucket == NULL) { /* No existing session. Check those ports. */ if (DNP3PortCheck(dnp3_eval_config, packetp) != DNP3_OK) { PREPROC_PROFILE_END(dnp3PerfStats); return; } /* Create session data and attach it to the Stream5 session */ tmp_bucket = DNP3CreateSessionData(packetp); if (tmp_bucket == NULL) { /* Mempool was full, don't process this session. */ static unsigned int times_mempool_alloc_failed = 0; /* Print a message, but only every 1000 times. Don't want to flood the log if there's a lot of DNP3 traffic. */ if (times_mempool_alloc_failed % 1000) { _dpd.logMsg("WARNING: DNP3 memcap exceeded.\n"); } times_mempool_alloc_failed++; PREPROC_PROFILE_END(dnp3PerfStats); return; } } sessp = (dnp3_session_data_t *) tmp_bucket->data; /* Set reassembly direction */ if (packetp->flags & FLAG_FROM_CLIENT) sessp->direction = DNP3_CLIENT; else sessp->direction = DNP3_SERVER; /* Do preprocessor-specific detection stuff here */ if (packetp->tcp_header) { /* Single PDU. PAF already split them up into separate pseudo-packets. */ DNP3FullReassembly(dnp3_eval_config, sessp, packetp, (uint8_t *)packetp->payload, packetp->payload_size); } else if (packetp->udp_header) { DNP3ProcessUDP(dnp3_eval_config, sessp, packetp); } /* That's the end! */ PREPROC_PROFILE_END(dnp3PerfStats); }
/*-------------------------------------------------------------------- * Function: LogIPHeader(TextLog* ) * * Purpose: Dump the IP header info to the given TextLog * * Arguments: log => TextLog to print to * * Returns: void function *-------------------------------------------------------------------- */ void LogIPHeader(TextLog* log, Packet * p) { if(!IPH_IS_VALID(p)) { TextLog_Print(log, "IP header truncated\n"); return; } if(p->frag_flag) { /* just print the straight IP header */ TextLog_Puts(log, inet_ntoa(GET_SRC_ADDR(p))); TextLog_Puts(log, " -> "); TextLog_Puts(log, inet_ntoa(GET_DST_ADDR(p))); } else { if(GET_IPH_PROTO(p) != IPPROTO_TCP && GET_IPH_PROTO(p) != IPPROTO_UDP) { /* just print the straight IP header */ TextLog_Puts(log, inet_ntoa(GET_SRC_ADDR(p))); TextLog_Puts(log, " -> "); TextLog_Puts(log, inet_ntoa(GET_DST_ADDR(p))); } else { if (!BcObfuscate()) { /* print the header complete with port information */ TextLog_Puts(log, inet_ntoa(GET_SRC_ADDR(p))); TextLog_Print(log, ":%d -> ", p->sp); TextLog_Puts(log, inet_ntoa(GET_DST_ADDR(p))); TextLog_Print(log, ":%d", p->dp); } else { /* print the header complete with port information */ if(IS_IP4(p)) TextLog_Print(log, "xxx.xxx.xxx.xxx:%d -> xxx.xxx.xxx.xxx:%d", p->sp, p->dp); else if(IS_IP6(p)) TextLog_Print(log, "x:x:x:x:x:x:x:x:%d -> x:x:x:x:x:x:x:x:%d", p->sp, p->dp); } } } if(!BcOutputDataLink()) { TextLog_NewLine(log); } else { TextLog_Putc(log, ' '); } TextLog_Print(log, "%s TTL:%u TOS:0x%X ID:%u IpLen:%u DgmLen:%u", protocol_names[GET_IPH_PROTO(p)], GET_IPH_TTL(p), GET_IPH_TOS(p), IS_IP6(p) ? ntohl(GET_IPH_ID(p)) : ntohs((uint16_t)GET_IPH_ID(p)), GET_IPH_HLEN(p) << 2, GET_IP_DGMLEN(p)); /* print the reserved bit if it's set */ if((uint8_t)((ntohs(GET_IPH_OFF(p)) & 0x8000) >> 15) == 1) TextLog_Puts(log, " RB"); /* printf more frags/don't frag bits */ if((uint8_t)((ntohs(GET_IPH_OFF(p)) & 0x4000) >> 14) == 1) TextLog_Puts(log, " DF"); if((uint8_t)((ntohs(GET_IPH_OFF(p)) & 0x2000) >> 13) == 1) TextLog_Puts(log, " MF"); TextLog_NewLine(log); /* print IP options */ if(p->ip_option_count != 0) { LogIpOptions(log, p); } /* print fragment info if necessary */ if(p->frag_flag) { TextLog_Print(log, "Frag Offset: 0x%04X Frag Size: 0x%04X\n", (p->frag_offset & 0x1FFF), GET_IP_PAYLEN(p)); } }
/** * \brief Add Source and Target fields to the IDMEF alert. * These objects contains IP addresses, source and destination * ports (see sections 4.2.4.3 and 4.2.4.4 of RFC 4765). * * \return 0 if ok */ static int EventToSourceTarget(Packet *p, idmef_alert_t *alert) { int ret; idmef_node_t *node; idmef_source_t *source; idmef_target_t *target; idmef_address_t *address; idmef_service_t *service; prelude_string_t *string; static char saddr[128], daddr[128]; uint8_t ip_vers; uint8_t ip_proto; SCEnter(); if ( !p ) SCReturnInt(0); if ( ! IPH_IS_VALID(p) ) SCReturnInt(0); if (PKT_IS_IPV4(p)) { ip_vers = 4; ip_proto = IPV4_GET_RAW_IPPROTO(p->ip4h); PrintInet(AF_INET, (const void *)GET_IPV4_SRC_ADDR_PTR(p), saddr, sizeof(saddr)); PrintInet(AF_INET, (const void *)GET_IPV4_DST_ADDR_PTR(p), daddr, sizeof(daddr)); } else if (PKT_IS_IPV6(p)) { ip_vers = 6; ip_proto = IPV6_GET_L4PROTO(p); PrintInet(AF_INET6, (const void *)GET_IPV6_SRC_ADDR(p), saddr, sizeof(saddr)); PrintInet(AF_INET6, (const void *)GET_IPV6_DST_ADDR(p), daddr, sizeof(daddr)); } else SCReturnInt(0); ret = idmef_alert_new_source(alert, &source, IDMEF_LIST_APPEND); if ( ret < 0 ) SCReturnInt(ret); ret = idmef_source_new_service(source, &service); if ( ret < 0 ) SCReturnInt(ret); if ( p->tcph || p->udph ) idmef_service_set_port(service, p->sp); idmef_service_set_ip_version(service, ip_vers); idmef_service_set_iana_protocol_number(service, ip_proto); ret = idmef_source_new_node(source, &node); if ( ret < 0 ) SCReturnInt(ret); ret = idmef_node_new_address(node, &address, IDMEF_LIST_APPEND); if ( ret < 0 ) SCReturnInt(ret); ret = idmef_address_new_address(address, &string); if ( ret < 0 ) SCReturnInt(ret); prelude_string_set_ref(string, saddr); ret = idmef_alert_new_target(alert, &target, IDMEF_LIST_APPEND); if ( ret < 0 ) SCReturnInt(ret); ret = idmef_target_new_service(target, &service); if ( ret < 0 ) SCReturnInt(ret); if ( p->tcph || p->udph ) idmef_service_set_port(service, p->dp); idmef_service_set_ip_version(service, ip_vers); idmef_service_set_iana_protocol_number(service, ip_proto); ret = idmef_target_new_node(target, &node); if ( ret < 0 ) SCReturnInt(ret); ret = idmef_node_new_address(node, &address, IDMEF_LIST_APPEND); if ( ret < 0 ) SCReturnInt(ret); ret = idmef_address_new_address(address, &string); if ( ret < 0 ) SCReturnInt(ret); prelude_string_set_ref(string, daddr); SCReturnInt(0); }
void OpSyslog_Alert(Packet *p, void *event, uint32_t event_type, void *arg) { OpSyslog_Data *syslogContext = NULL; Unified2EventCommon *iEvent = NULL; SigNode *sn = NULL; ClassType *cn = NULL; char sip[16] = {0}; char dip[16] = {0}; if( (p == NULL) || (event == NULL) || (arg == NULL)) { LogMessage("OpSyslog_Alert(): Invoked with Packet[0x%x] Event[0x%x] Event Type [%u] Context pointer[0x%x]\n", p, event, event_type, arg); return; } if(event_type != UNIFIED2_IDS_EVENT) { LogMessage("OpSyslog_Alert(): Is currently unable to handle Event Type [%u] \n", event_type); return; } syslogContext = (OpSyslog_Data *)arg; iEvent = event; memset(syslogContext->payload,'\0',(SYSLOG_MAX_QUERY_SIZE)); memset(syslogContext->formatBuffer,'\0',(SYSLOG_MAX_QUERY_SIZE)); syslogContext->payload_current_pos = 0; syslogContext->format_current_pos = 0; switch(syslogContext->operation_mode) { case 0: /* Ze Classic (Requested) */ if(IPH_IS_VALID(p)) { if (strlcpy(sip, inet_ntoa(GET_SRC_ADDR(p)), sizeof(sip)) >= sizeof(sip)) { FatalError("[%s()], strlcpy() error , bailing \n", __FUNCTION__); return; } if (strlcpy(dip, inet_ntoa(GET_DST_ADDR(p)), sizeof(dip)) >= sizeof(dip)) { FatalError("[%s()], strlcpy() error , bailing \n", __FUNCTION__); return; } } sn = GetSigByGidSid(ntohl(iEvent->generator_id), ntohl(iEvent->signature_id)); cn = ClassTypeLookupById(barnyard2_conf, ntohl(iEvent->classification_id)); if( (syslogContext->format_current_pos += snprintf(syslogContext->formatBuffer,SYSLOG_MAX_QUERY_SIZE, "[%u:%u:%u] ", ntohl(iEvent->generator_id), ntohl(iEvent->signature_id), ntohl(iEvent->signature_revision))) >= SYSLOG_MAX_QUERY_SIZE) { /* XXX */ FatalError("[%s()], failed call to snprintf \n", __FUNCTION__); } if( OpSyslog_Concat(syslogContext)) { /* XXX */ FatalError("OpSyslog_Concat(): Failed \n"); } if(sn != NULL) { if( (syslogContext->format_current_pos += snprintf(syslogContext->formatBuffer,SYSLOG_MAX_QUERY_SIZE, "%s ", sn->msg)) >= SYSLOG_MAX_QUERY_SIZE) { /* XXX */ FatalError("[%s()], failed call to snprintf \n", __FUNCTION__); } } else { if( (syslogContext->format_current_pos += snprintf(syslogContext->formatBuffer,SYSLOG_MAX_QUERY_SIZE, "ALERT ")) >= SYSLOG_MAX_QUERY_SIZE) { /* XXX */ FatalError("[%s()], failed call to snprintf \n", __FUNCTION__); } } if( OpSyslog_Concat(syslogContext)) { /* XXX */ FatalError("OpSyslog_Concat(): Failed \n"); } if(cn != NULL) { if( cn->name ) { if( (syslogContext->format_current_pos += snprintf(syslogContext->formatBuffer,SYSLOG_MAX_QUERY_SIZE, "[Classification: %s] [Priority: %d]:", cn->name, ntohl(((Unified2EventCommon *)event)->priority_id))) >= SYSLOG_MAX_QUERY_SIZE) { /* XXX */ FatalError("[%s()], failed call to snprintf \n", __FUNCTION__); } } } else if( ntohl(((Unified2EventCommon *)event)->priority_id) != 0 ) { if( (syslogContext->format_current_pos += snprintf(syslogContext->formatBuffer,SYSLOG_MAX_QUERY_SIZE, "[Priority: %d]:", ntohl(((Unified2EventCommon *)event)->priority_id))) >= SYSLOG_MAX_QUERY_SIZE) { /* XXX */ FatalError("[%s()], failed call to snprintf \n", __FUNCTION__); } } if( OpSyslog_Concat(syslogContext)) { /* XXX */ FatalError("OpSyslog_Concat(): Failed \n"); } if( (IPH_IS_VALID(p)) && (((GET_IPH_PROTO(p) != IPPROTO_TCP && GET_IPH_PROTO(p) != IPPROTO_UDP && GET_IPH_PROTO(p) != IPPROTO_ICMP) || p->frag_flag))) { if(!BcAlertInterface()) { if(protocol_names[GET_IPH_PROTO(p)]) { if( (syslogContext->format_current_pos += snprintf(syslogContext->formatBuffer,SYSLOG_MAX_QUERY_SIZE, " {%s} %s -> %s", protocol_names[GET_IPH_PROTO(p)], sip, dip)) >= SYSLOG_MAX_QUERY_SIZE) { /* XXX */ FatalError("[%s()], failed call to snprintf \n", __FUNCTION__); } } } else { if(protocol_names[GET_IPH_PROTO(p)]) { if( (syslogContext->format_current_pos += snprintf(syslogContext->formatBuffer,SYSLOG_MAX_QUERY_SIZE, " <%s> {%s} %s -> %s", barnyard2_conf->interface, protocol_names[GET_IPH_PROTO(p)], sip, dip)) >= SYSLOG_MAX_QUERY_SIZE) { /* XXX */ FatalError("[%s()], failed call to snprintf \n", __FUNCTION__); } } } } else { if(BcAlertInterface()) { if(protocol_names[GET_IPH_PROTO(p)]) { if( (syslogContext->format_current_pos += snprintf(syslogContext->formatBuffer,SYSLOG_MAX_QUERY_SIZE, " <%s> {%s} %s:%i -> %s:%i", barnyard2_conf->interface, protocol_names[GET_IPH_PROTO(p)], sip, p->sp, dip, p->dp)) >= SYSLOG_MAX_QUERY_SIZE) { /* XXX */ FatalError("[%s()], failed call to snprintf \n", __FUNCTION__); } } } else { if(protocol_names[GET_IPH_PROTO(p)]) { if( (syslogContext->format_current_pos += snprintf(syslogContext->formatBuffer,SYSLOG_MAX_QUERY_SIZE, " {%s} %s:%i -> %s:%i", protocol_names[GET_IPH_PROTO(p)], sip, p->sp, dip, p->dp)) >= SYSLOG_MAX_QUERY_SIZE) { /* XXX */ FatalError("[%s()], failed call to snprintf \n", __FUNCTION__); } } } } if( OpSyslog_Concat(syslogContext)) { /* XXX */ FatalError("OpSyslog_Concat(): Failed \n"); } break; case 1: /* Ze verbose */ if(Syslog_FormatTrigger(syslogContext, iEvent,0) ) { LogMessage("WARNING: Unable to append Trigger header.\n"); return; } /* Support for portscan ip */ if(p->iph) { if(Syslog_FormatIPHeaderAlert(syslogContext, p) ) { LogMessage("WARNING: Unable to append Trigger header.\n"); return; } } if(p->iph) { /* build the protocol specific header information */ switch(p->iph->ip_proto) { case IPPROTO_TCP: Syslog_FormatTCPHeaderAlert(syslogContext, p); break; case IPPROTO_UDP: Syslog_FormatUDPHeaderAlert(syslogContext, p); break; case IPPROTO_ICMP: Syslog_FormatICMPHeaderAlert(syslogContext, p); break; } } /* CHECKME: -elz will update formating later on .. */ if( (syslogContext->format_current_pos += snprintf(syslogContext->formatBuffer,SYSLOG_MAX_QUERY_SIZE, "\n")) >= SYSLOG_MAX_QUERY_SIZE) { /* XXX */ FatalError("Couldn't finalize payload string ....\n"); } if( OpSyslog_Concat(syslogContext)) { /* XXX */ FatalError("OpSyslog_Concat(): Failed \n"); } break; default: FatalError("[%s()]: Unknown operation_mode ... bailing \n", __FUNCTION__); break; } if(NetSend(syslogContext)) { NetClose(syslogContext); if(syslogContext->local_logging != 1) { FatalError("NetSend(): call failed for host:port '%s:%u' bailing...\n", syslogContext->server, syslogContext->port); } } return; }