还应当注意,ngrep采用的是监听网络的手段,因此,ngrep无法在交换式的环境中使用。但是经过修改 的ngrep可以不必和你的DNS在同一个网段中,但是他必须位于一个可以监听到所有DNS请求的位置。经 过修改的ngrep也不关心目标地址,您可以把它放置在DMZ网段,使它能够检查横贯该网络的tfn2k攻 击。从理论上讲,它也可以很好的检测出对外的tfn2k攻击。 运行 ngrep, 您将看到: [root@lughnasad ngrep]# ./ngrep Ngrep with TFN detection modifications by wiretrip / www.wiretrip.net Watching DNS server: 10.0.0.8 interface: eth0 (10.0.0.0/255.255.0.0) 从这里开始ngrep将监听tfn2k攻击,如果检测到攻击, ngrep将在屏幕上打印: Sun Jan 9 17:30:01 2000 A TFN2K UDP attack has been detected! Last (5000) DNS requests: 《list of IPs that made DNS requests, up to DNS_REQUEST_MAX length》 Last (1000) ICMP echo requests (pings): 《list of IPs that made ICMP echo requests, up to ICMP_REQUEST_MAX length》 Incoming realtime ICMP echo requests (pings): 《all ICMP echo requests since the attack was detected》 以上的列表并不是唯一的,可以对它进行调整让他不仅显示是谁请求,而且请求多少次,频率为多少等 等。在ICMP flood事件中,ICMP回应请求的报告中将不包括做为tfn2k flood一部分的ICMP包。Ngrep还 可以报告检测出来的除smurf之外的攻击类型(TARGA, UDP, SYN, ICMP等)。混合式的攻击在缺省情况 下表现为ICMP攻击,除非你屏蔽了向内的ICMP回应请求,这样它就表现为UDP或SYN攻击。这些攻击的结 果都是基本类似的。 附录- Ngrep.c with tfn2k detection 以下的代码在使用前应当更改一些参数。 #define DNS_REQUEST_MAX 5000 #define ICMP_REQUEST_MAX 1000 通知ngrep最大的请求跟踪数(在检测攻击之前)。传输较为繁忙的网站应当增加这一数值(网络流量 较为繁忙的网站DNS的请求数最好在10,000,而ICMP请求为2000-3000) #define FLOOD_THRESHOLD 20 用在10秒中内有多少同一类型的攻击包来确认为真正的攻击。数目设计的越大,程序报受攻击的可能性 就越小。假如您老是收到错误的警报,那么您应当增加一下这个数值。 #define DNS_SERVER_IP "10.0.0.8" Ngrep通过监视DNS服务器的53端口的UDP包来跟踪向内的DNS请求(只有UDP)。因此,ngrep需要知道您 的DNS服务器的IP地址。 我们的设备可能会有多个DNS服务器,但我们认为对一台DNS服务器的支持足以证明这项技术的能力。 #define TTL_THRESHOLD 150 tfn2k SYN flood 攻击使用的 TTL值通常在200-255的范围内。估计到攻击者与目标主机之间不止50 跳,因此我们可以只查找TTL时间高于150的包。假如您相信攻击者在50跳左右,那么您可以对TTL的限 制进行一下更改。 编译更改过的 ngrep 编译和安装都非常简单。您仅需要使用以下之一来取代ngrep.c 文件。处于方便起见,我们可以详细说 明。 这段代码只是在RedHat 6.1 和Mandrake 6.5 Linux上测试过。 首先您需要在 http://www.packetfactory.net/ngrep/ 下载ngrep,我们测试的是1.35版。 然后在 ftp://ftp.ee.lbl.gov/libpcap.tar.Z下载libpcap 我们使用的是 0.40版。 把文件放在临时文件夹里并解包, tar xvzf libpcap.tar.Z 然后进行编译 cd libpcap-0.4; ./configure; make; make install; make install-incl 假如您遇到了困难,可以参见在libpcap-0.4目录里的README或INSTALL文件。根据我们实验的经验,如 果/usr/local/include 和/usr/local/include/net目录在linux系统中不存在的话,安装会失败。加入 您在安装时遇到了pcap.h 或 bpf.h的错误时你可以运行 mkdir /usr/local/include; mkdir /usr/local/include/net然后重新运行'make install-incl'。然后我们需要编译ngrep (使用我们修改过的版本)。首先解包 tar xvzf ngrep-1.35.tar.gz 然后进行配置 cd ngrep; ./configure 然后把ngrep.c复制到ngrep目录里。你可以覆盖也可以备份原始的ngrep.c文件。在这里,您应当回顾在修改过的ngrep.c里的配置,至少您应当把DNS_SERVER_IP更改为您所使用的DNS的地址。更改完毕后 你就可以运行'make',这样就建立了ngrep应用程序。 Modified ngrep.c source code /* this code is available for download from http://www.wiretrip.net/na/ngrep.c */ /* * $Id: ngrep.c,v 1.35 1999/10/13 16:44:16 jpr5 Exp $ * */ /* TFN detection code added by Rain Forest Puppy / rfp@wiretrip.net and Night Axis / na@wiretrip.net */ /********* TFN detection defines *******************************/ /* how many DNS and ICMP requests to track */ #define DNS_REQUEST_MAX 5000 #define ICMP_REQUEST_MAX 1000 /* flood threshold is matches per 10 seconds */ #define FLOOD_THRESHOLD 20 /* IP of your DNS server */ #define DNS_SERVER_IP "10.9.100.8" /* TFN syn uses ttl between 200-255. Assuming less than 50 hops, flag stuff with ttl > TTL_THRESHOLD (other critera are used as well) */ #define TTL_THRESHOLD 150 /**************************************************************/ #include <stdlib.h> #include <string.h> #include <signal.h> #ifdef LINUX #include <getopt> #endif #if defined(BSD) || defined(SOLARIS) #include <unistd.h> #include #include <ctype.h> #include #include #include #include #endif #if defined(LINUX) && !defined(HAVE_IF_ETHER_H) h> #include <pcap.h> #include #include "regex.h" #include "ngrep.h" static char rcsver[] = "$Revision: 1.35 $"; int snaplen = 65535, promisc = 1, to = 1000; int show_empty = 0, show_hex = 0, quiet = 0; int match_after = 0, keep_matching = 0, invert_match = 0; int matches = 0, max_matches = 0; char pc_err[PCAP_ERRBUF_SIZE], *re_err; int (*match_func)(); int re_match_word = 0, re_ignore_case = 0; struct re_pattern_buffer pattern; char *regex, *filter; struct bpf_program pcapfilter; struct in_addr net, mask; char *dev = NULL; int link_offset; pcap_t *pd; /**************** TFN2K detection **********************************/ unsigned int udp_flood_count=0, syn_flood_count=0; unsigned int targa_flood_count=0, icmp_flood_count=0; unsigned long my_dns, targ1, targ2, rfp1, icmp_flood=1; time_t t; unsigned long dns_circbuff[DNS_REQUEST_MAX]; unsigned int dns_cb_ptr=0; unsigned long icmp_circbuff[ICMP_REQUEST_MAX]; unsigned int icmp_cb_ptr=0; void add_dns (unsigned long ipadd){ dns_circbuff[dns_cb_ptr++]=ipadd; if (dns_cb_ptr==DNS_REQUEST_MAX) dns_cb_ptr=0;} void add_icmp (unsigned long ipadd){ icmp_circbuff[icmp_cb_ptr++]=ipadd; if (icmp_cb_ptr==ICMP_REQUEST_MAX) dns_cb_ptr=0;} void anti_tfn_init (void) { unsigned int x; for(x=0;x<DNS_REQUEST_MAX;X++) dns_circbuff[x]=0 for(x=0;ICMP_REQUEST_MAX;x++) icmp_circbuff[x]=0; my_dns=inet_addr(DNS_SERVER_IP); printf("Ngrep with TFN detection modifications by wiretrip / www.wiretrip.net\n"); printf("Watching DNS server: %s\n",inet_ntoa(my_dns)); targ1=htons(16383); targ2=htons(8192); rfp1=htons(~(ICMP_ECHO << 8)); /* hopefull this is universal ;) */ alarm(20);} void print_circbuffs (void) { unsigned int x; printf("Last (%u) DNS requests:\n",DNS_REQUEST_MAX); for(x=0;x<DNS_REQUEST_MAX;X++) if( dns_circbuff[x]>0) printf("%s\n",inet_ntoa(dns_circbuff[x])); printf("\nLast (%u) ICMP echo requests (pings):\n",ICMP_REQUEST_MAX); for(x=0;x 0) printf("%s\n",inet_ntoa(icmp_circbuff[x]));} void reset_counters (int sig) { udp_flood_count=syn_flood_count=targa_flood_count=icmp_flood_count=0; alarm(10);} void tfn_attack_detected (char* attack_type){ if(icmp_flood==0) return; (void)time(&t); printf("\n%s",ctime(&t)); printf("A TFN2K %s attack has been detected!\n\n",attack_type); print_circbuffs(); printf("\nIncoming realtime ICMP echo requests (pings):\n"); icmp_flood=0;} /*********************************************************************/ int main(int argc, char **argv) { char c; signal(SIGINT,dealloc); signal(SIGQUIT,dealloc); signal(SIGABRT,dealloc); signal(SIGPIPE,dealloc); signal(SIGALRM,reset_counters); anti_tfn_init(); while ((c = getopt(argc, argv, "d:")) != EOF) { switch (c) { case 'd': dev = optarg; break;}} if (!dev) if (!(dev = pcap_lookupdev(pc_err))) { perror(pc_err); exit(-1);} if ((pd = pcap_open_live(dev, snaplen, promisc, to, pc_err)) == NULL) { perror(pc_err); exit(-1);} if (pcap_lookupnet(dev,&net.s_addr,&mask.s_addr, pc_err) == -1) { perror(pc_err); exit(-1);} printf("interface: %s (%s/", dev, inet_ntoa(net)); printf("%s)\n",inet_ntoa(mask)); switch(pcap_datalink(pd)) { case DLT_EN10MB: case DLT_IEEE802: link_offset = ETHHDR_SIZE; break; case DLT_SLIP: link_offset = SLIPHDR_SIZE; break; case DLT_PPP: link_offset = PPPHDR_SIZE; break; case DLT_RAW: link_offset = RAWHDR_SIZE; break; case DLT_NULL: link_offset = LOOPHDR_SIZE; break; default: fprintf(stderr,"fatal: unsupported interface type\n"); exit(-1); } while (pcap_loop(pd,0,(pcap_handler)process,0));} void process(u_char *data1, struct pcap_pkthdr* h, u_char *p) { struct ip* ip_packet = (struct ip *)(p + link_offset); switch (ip_packet->ip_p) { case IPPROTO_TCP: { struct tcphdr* tcp = (struct tcphdr *)(((char *)ip_packet) + ip_packet->ip_hl*4); if(tcp->th_flags==0x22 && ip_packet->ip_ttl > TTL_THRESHOLD){ if(++syn_flood_count > FLOOD_THRESHOLD) tfn_attack_detected("SYN");} if(ip_packet->ip_ttl==0 && (ip_packet->ip_off==targ1 || ip_packet->ip_off==targ2)){ if(++targa_flood_count > FLOOD_THRESHOLD) tfn_attack_detected("TARGA"); }} break; case IPPROTO_UDP: { struct udphdr* udp = (struct udphdr *)(((char *)ip_packet) + ip_packet->ip_hl*4); #ifdef HAVE_DUMB_UDPHDR if ((ntohs(udp->source) + ntohs(udp->dest)) == 65536) { #else if ((ntohs(udp->uh_sport) + ntohs(udp->uh_dport)) == 65536) { #endif if(++udp_flood_count > FLOOD_THRESHOLD) tfn_attack_detected("UDP");} if(ip_packet->ip_dst.s_addr==my_dns && #ifdef HAVE_DUMB_UDPHDR ntohs(udp->dest) == 53) { #else ntohs(udp->uh_dport) == 53) { #endif add_dns(ip_packet->ip_src.s_addr); }} break; icmp_cksum==rfp1 && ip_packet->ip_ttl==0){ if(++icmp_flood_count > FLOOD_THRESHOLD) tfn_attack_detected("ICMP"); } else { if(icmp_flood>0) add_icmp(ip_packet->ip_src.s_addr); else printf("%s\n",inet_ntoa(ip_packet->ip_src));}}}}} void dealloc(int sig) { if (filter) free(filter); exit(0);}
|