📄 sp_respond2.c
字号:
else if (!strcasecmp(toks[i], "icmp_all")) { response_flag |= (RESP_BAD_NET | RESP_BAD_HOST | RESP_BAD_PORT); if (!make_icmp) make_icmp = 1; i++; } else FatalError("%s: %s(%d): invalid response modifier: %s\n", MODNAME, file_name, file_line, toks[i]); } if (make_tcp) PrecacheTCP(); if (make_icmp) PrecacheICMP(); mSplitFree(&toks, num_toks); return response_flag;}/* ######## CORE respond2 section ######## *//** * Respond to hostile connection attempts * * @param p pointer to a Snort packet structure * @param fp_list pointer to a response list node * * @return void function */static int Respond2(Packet *p, RspFpList *fp_list){ RespondData *rd = (RespondData *)fp_list->params; if (p->iph == NULL) return 0; /* check the dampen cache before responding */ if ((dampen_response(p)) == 1) return 0; if (rd->response_flag) { /* if reset_both was used, receiver is reset first */ if ((rd->response_flag & (RESP_RST_RCV | RESP_RST_SND)) && IsRSTCandidate(p)) { SendReset(RESP_RST_RCV, p, &config); SendReset(RESP_RST_SND, p, &config); } if ((rd->response_flag & RESP_RST_RCV) && IsRSTCandidate(p)) SendReset(RESP_RST_RCV, p, &config); if ((rd->response_flag & RESP_RST_SND) && IsRSTCandidate(p)) SendReset(RESP_RST_SND, p, &config); if (rd->response_flag & RESP_BAD_NET && IsUNRCandidate(p)) SendUnreach(ICMP_UNREACH_NET, p, &config); if (rd->response_flag & RESP_BAD_HOST && IsUNRCandidate(p)) SendUnreach(ICMP_UNREACH_HOST, p, &config); if (rd->response_flag & RESP_BAD_PORT && IsUNRCandidate(p)) SendUnreach(ICMP_UNREACH_PORT, p, &config); } return 1; /* injection functions do not return an error */}/** * TCP reset response function * * @param flag flag describing whom to respond to (sender/receiver) * @param p Pointer to a Snort packet structure * @param data pointer to a RESPOND2_CONFIG data structure * * @return void function */static void SendReset(const int mode, Packet *p, RESPOND2_CONFIG *conf){ size_t sz = IP_HDR_LEN + TCP_HDR_LEN; ssize_t n; int reversed; u_int32_t i, ack, seq; u_int16_t window, dsize; EtherHdr *eh; IPHdr *iph; TCPHdr *tcp;#if defined(DEBUG) char *source, *dest;#endif if(IS_IP6(p)) return; if (mode == RESP_RST_SND) reversed = 1; else reversed = 0; iph = (IPHdr *)(tcp_pkt + link_offset); tcp = (TCPHdr *)(tcp_pkt + IP_HDR_LEN + link_offset); if (link_offset) { if (!IsLinkCandidate(p)) { ErrorMessage("%s: link-layer response only works on Ethernet!\n" "Remove \"config flexresp2_interface\" from snort.conf.\n", MODNAME); return; } else { DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, "%s: setting up link-layer " "header on TCP packet: %p.\n.", MODNAME, p);); /* setup the Ethernet header */ eh = (EtherHdr *)tcp_pkt; if (reversed) { memcpy(eh->ether_src, p->eh->ether_dst, 6); memcpy(eh->ether_dst, p->eh->ether_src, 6); } else { memcpy(eh->ether_src, p->eh->ether_src, 6); memcpy(eh->ether_dst, p->eh->ether_dst, 6); } } } /* save p->dsize */ dsize = p->dsize; /* Reverse the source and destination IP addr for attack-response rules */ if (reversed) { iph->ip_src.s_addr = GET_SRC_IP(p); iph->ip_dst.s_addr = GET_DST_IP(p); tcp->th_sport = p->tcph->th_dport; tcp->th_dport = p->tcph->th_sport; seq = ntohl(p->tcph->th_ack); ack = ntohl(p->tcph->th_seq) + p->dsize; } else { iph->ip_src.s_addr = GET_SRC_IP(p); iph->ip_dst.s_addr = GET_DST_IP(p); tcp->th_sport = p->tcph->th_sport; tcp->th_dport = p->tcph->th_dport; seq = ntohl(p->tcph->th_seq); ack = ntohl(p->tcph->th_ack) + p->dsize; } iph->ip_ttl = CalcOriginalTTL(p); tcp->th_win = 0; /* save the window size for all calculations */ window = ntohs(p->tcph->th_win); for (i = 0; i < conf->respond_attempts; i++) { if (link_offset) iph->ip_id = RandID(&config); /* As Dug Song pointed out, if you can't determine the rate of * SEQ and ACK number consumption, do the next best thing and try to * "land" a reset within the acceptable window of sequence numbers. * * sp_respond2 uses data sent in the offending packet and the window * size of the offending packet to 'predict' an acceptable SEQ and * ACK number. * * A minimum of four responses are sent per trigger using the * following algorithm: * * (the numbers represent iterations through a loop starting at 0) * * 0: * SEQ = seq * ACK = ack + data * * 1: * SEQ += data * * 2: * SEQ += (data * 2) * ACK += (data * 2) * * 3: * SEQ += (data * 2) * ACK += (data * 2) * * 4: * SEQ += (data * 4) * ACK += (data * 4) * * n: * * SEQ += (window / 2) * ACK += (window / 2) * * * I refer to the above as "sequence strafing", whereby sp_respond2 * iteratively brute forces sequence and ack numbers into an * acceptable window */ switch (i) { case 0: break; case 1: seq += dsize; break; case 2: seq += (dsize << 1); ack += (dsize << 1); break; case 3: seq += (dsize << 1); ack += (dsize << 1); break; case 4: seq += (dsize << 2); ack += (dsize << 2); break; default: seq += (window >> 1); ack += (window >> 1); break; } tcp->th_seq = htonl(seq); tcp->th_ack = htonl(ack); iph->ip_len = htons(sz); ip_checksum(tcp_pkt + link_offset, sz); #if defined(DEBUG) DEBUG_WRAP(#ifndef SUP_IP6 source = strdup(inet_ntoa(*(struct in_addr *)&iph->ip_src.s_addr)); dest = strdup(inet_ntoa(*(struct in_addr *)&iph->ip_dst.s_addr));#else source = ""; dest = "";#endif DebugMessage(DEBUG_PLUGIN, "%s: firing TCP response packet.\n", MODNAME); DebugMessage(DEBUG_PLUGIN, "%s:%u -> %s:%d\n(seq: %#lX " "ack: %#lX win: %hu)\n\n", source, ntohs(tcp->th_sport), dest, ntohs(tcp->th_dport), ntohl(tcp->th_seq), ntohl(tcp->th_ack), ntohs(tcp->th_win)); PrintNetData(stdout, (u_char *)tcp_pkt, sz); //ClearDumpBuf(); free(source); free(dest); );#endif /* defined(DEBUG) */ if (link_offset) n = eth_send(conf->ethdev, tcp_pkt, sz + link_offset); else n = ip_send(conf->rawdev, tcp_pkt, sz); if (n < sz) ErrorMessage("%s: failed to send TCP reset (%s).\n", MODNAME, ((link_offset == 0) ? "raw socket" : "link-layer")); } return;}/** * ICMP unreachable response function * * @param code ICMP unreachable type * @param p Pointer to a Snort packet structure * @param data pointer to a RESPOND2_CONFIG data structure * * @return void function */static void SendUnreach(const int code, Packet *p, RESPOND2_CONFIG *conf){ u_int16_t payload_len; size_t sz; ssize_t n; EtherHdr *eh; IPHdr *iph; ICMPHdr *icmph;#if defined(DEBUG) char *source, *dest, *icmp_rtype;#endif if(IS_IP6(p)) return; /* only send ICMP port unreachable responses for TCP and UDP */ if (GET_IPH_PROTO(p) == IPPROTO_ICMP && code == ICMP_UNREACH_PORT) { ErrorMessage("%s: ignoring icmp_port set on ICMP packet.\n", MODNAME); return; } iph = (IPHdr *)(icmp_pkt + link_offset); icmph = (ICMPHdr *)(icmp_pkt + IP_HDR_LEN + link_offset); iph->ip_src.s_addr = GET_DST_IP(p); iph->ip_dst.s_addr = GET_SRC_IP(p); iph->ip_ttl = CalcOriginalTTL(p); icmph->code = code; if (link_offset) { if (!IsLinkCandidate(p)) { ErrorMessage("%s: link-layer response only works on Ethernet!\n" "Remove \"config flexresp2_interface\" from snort.conf.\n", MODNAME); return; } else { DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, "%s: setting up link-layer " "header on ICMP packet: %p.\n.", MODNAME, p);); /* setup the Ethernet header */ eh = (EtherHdr *)icmp_pkt; memcpy(eh->ether_src, p->eh->ether_dst, 6); memcpy(eh->ether_dst, p->eh->ether_src, 6); /* With a raw socket, the kernel automatically sets the IP ID when * it's 0. With link-layer injection, an IP ID must be specified. * A randomly generated IP ID is used here to evade fingerprinting. */ iph->ip_id = RandID(&config); } } if ((payload_len = ntohs(GET_IPH_LEN(p)) - (GET_IPH_HLEN(p) << 2)) > 8) payload_len = 8; memcpy((char *)icmph + ICMP_LEN_MIN, p->iph, (IP_HLEN(p->iph) << 2) + payload_len); sz = IP_HDR_LEN + ICMP_LEN_MIN + (IP_HLEN(p->iph) << 2) + payload_len; iph->ip_len = htons(sz); ip_checksum(icmp_pkt + link_offset, sz); sz += link_offset;#if defined(DEBUG) DEBUG_WRAP(#ifdef SUP_IP6 source = strdup(sfip_ntoa(iph->ip_src.s_addr)); dest = strdup(sfip_ntoa(iph->ip_dst.s_addr));#else source = strdup(inet_ntoa(*(struct in_addr *)&iph->ip_src.s_addr)); dest = strdup(inet_ntoa(*(struct in_addr *)&iph->ip_dst.s_addr));#endif switch (code) { case RESP_BAD_NET: icmp_rtype = "ICMP network unreachable"; break; case RESP_BAD_HOST: icmp_rtype = "ICMP host unreachable"; break; case RESP_BAD_PORT: /* FALLTHROUGH */ default: icmp_rtype = "ICMP port unreachable"; break; } DebugMessage(DEBUG_PLUGIN, "%s: firing ICMP response packet.\n", MODNAME); DebugMessage(DEBUG_PLUGIN, "%s -> %s (%s)\n\n", source, dest, icmp_rtype); PrintNetData(stdout, (u_char *)icmp_pkt, (const int)sz); //ClearDumpBuf(); free(source); free(dest); );#endif /* defined(DEBUG) */ if (link_offset) n = eth_send(conf->ethdev, icmp_pkt, sz); else n = ip_send(conf->rawdev, icmp_pkt, sz); if (n < sz) ErrorMessage("%s: failed to send ICMP unreachable (%s).\n", MODNAME, ((link_offset == 0) ? "raw socket" : "link-layer")); return;}/** * Determine whether or not a TCP RST response can be sent * * @param p pointer to a Snort packet structure * * @return 1 on success, 0 on failure */static INLINE int IsRSTCandidate(Packet *p)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -