CVE-2020-1350 詳解與復現

PsgQ發表於2021-05-24

漏洞簡介


在Windows上,DNS伺服器是域控制器,其管理員是Domain Admins組的一部分。預設情況下,Domain Admins組是已加入域的所有計算機上Administrators組的成員,包括域控制器[8]。如果利用得當,攻擊者可以在易受攻擊的系統上遠端執行程式碼,並獲得Domain Admin許可權,從而有效地損害了整個公司的基礎架構。

DNS伺服器-dns.exe負責在安裝了DNS角色的Windows伺服器上回答DNS查詢。


CVE-2020-1350是DNS.exe在處理畸形DNS Sig訊息時,由於對資料包的欄位校驗不嚴格,導致了整型溢位。DNS SIG 訊息中包含對DNS記錄集合的數字簽名,DNS記錄集合就是一種名字相同,或者型別相同的DNS訊息集合。


漏洞型別:整數溢位導致基於堆的緩衝區溢位


攻擊流程


aa91b3_adb7b85135e44f38bcca549851f38d68_mv2


攻擊者可以配置一個惡意的域名evildomain.com,該域名的DNS指向的DNS伺服器作為本次攻擊的目標。


  1. 當客戶端查詢evildomain.com的DNS記錄;
  2. 目標DNS伺服器向根域名伺服器查詢evildomain.com的NS記錄;
  3. 根域名伺服器告訴目標DNS,evildomain.com的權威DNS伺服器是3.3.3.3,並該記錄快取起來;
  4. 客戶端向目標伺服器查詢evildomain.com的Sig記錄;
  5. 目標伺服器將請求轉發給權威DNS伺服器;
  6. 權威DNS伺服器返回畸形Sig查詢結果;

目標DNS伺服器處理SigQuery的畸形訊息時,將此訊息快取到自己的記錄中,觸發漏洞。


漏洞函式

簡言之就是整數溢位後導致堆溢位,將該漏洞抽象為以下模型:

void Examples(char``*` `in``)``{``  ``unsigned short len_p1 ``=` `len``(``in``.p1);``  ``unsigned short len_p2 ``=` `len``(``in``.p2);``  ``unsigned short len_p ``=` `len_p1 ``+` `len_p2;``  ``char``*` `buf ``=` `(char ``*``)malloc(len_p);``  ``memcpy(buf, ``in``.p1, len_p1); ``}

問題就出在 len_p 的計算上,假設 len_p1 = 0xFFD0,len_p2 = 0x40,相加後高位資料被丟棄,那麼 0xFFD0 + 0x40 = 0x10010 = 0x10,所以實際分配的記憶體是 0x10 而不是 0x10010,而之後往 0x10 的空間內拷貝 0xFFD0 長度的資料,自然造成了記憶體溢位。


而在dns.exe!SigWireRead函式裡面也有類似的溢位漏洞,如圖所示第11行:

aa91b3_ffb865d47c0b4f54925b8c2acb34b036_mv2

漏洞成因如下:ushort型別,為無符號16位型別。RR_AllocateEx 分配的大小隻有16個bit,大小為0~65535,所以只要構造size 大於65535,造成整數溢位,而系統就會分配一個比實際資料量小的堆塊,進而造成堆溢位,將整數溢位轉化成堆溢位漏洞。


漏洞利用:

因此,觸發此漏洞所需的全部操作就是讓受攻擊的DNS伺服器向我們查詢SIG記錄,並使用長簽名(長度&>=64KB)對其作出SIG響應。但是,UDP上的DNS的大小限制為512位元組(如果伺服器支援EDNS0,則為4096位元組)。在任何情況下,這都不足以觸發漏洞。


CheckPoint 找到一種方法可以突破上述限制:UDP 響應時將 DNS 頭部的 TC 標誌置 1,表示被截斷,之後客戶端便會嘗試用 TCP 協議和伺服器建立連線,並通過 TCP 協議傳遞資料。由於訊息的前兩個位元組表示其長度,因此TCP上的DNS中訊息的最大大小表示為16位,因此限制為64KB。TCP 協議在 53 埠上可傳輸長度最大為 65535 的 DNS 資料,這無疑給該漏洞創造了先決條件。如下圖:紅框中的表示TC置位欄位:

image-20210524201342778


但是,即使是長度為65,535的訊息也不足以觸發漏洞,因為訊息長度包括報頭和原始查詢。計算傳遞給RR_AllocateEx的大小時不考慮此開銷。那麼,該漏洞如何觸發呢?繼續往下看,首先了解一下域名編碼和域名壓縮。


域名編碼

eg:對於完整的一個域名www.baidu.com,需要14個位元組:

0 1 2 3 4 5 6 7 8 9 10 11 12 13
\3 w w w \5 b a i d u \3 c o m

img

可以看到第一個位元組 是3,表示之後會有3個位元組的字元。


域名壓縮

域名壓縮是 DNS 協議節省空間的一種方式,因為請求中的域名字元會頻繁出現在響應包的內,故採用了一種標誌+偏移的格式來壓縮域名。壓縮方式很簡單:1 + 1 + offset,即最高 2bit 位為 1 時代表了將採用域名壓縮,剩餘的組合為偏移值(基地址為 DNS 頭),如下圖:響應區域中的 Name 欄位為 0xc00c,明顯是被壓縮過的,最高 2bit 位是標誌,剩餘的 bit 位組合得到的值為 0xc,所以當前 Name 表示的字串在 DNS 頭部向後偏移 0xc 的位置,也就是圖中紅框中 0x3 開始(0x50 表示 DNS 頭起始位置)的域名 bbs.pediy.com

879291_BK62PXN5P34V87F (1)


因此,可以將域名壓縮的偏移值指向一片可控的區域,而不是指向查詢時域名,就完全有可能使得域名的長度大大增加,比如在這裡修改為c0 0d,那麼表示域名從0x62開始,說明後面有0x62個位元組的字元,然後依次。這樣就使得原始碼第11行中的 sigName.Length 的大小變大。


注意:DNS name長度最大為0XFF


所以,可以在不改變原來資料包大小的情況下,將sigLength+sigName.length+0x16 的大小,大於65535,造成整數溢位。分配一個小的空間快取,然後導致堆溢位。


POC分析和漏洞復現


部分poc程式碼,大體就是構造sig響應訊息。具體POC,在這裡:https://github.com/maxpl0it/CVE-2020-1350-DoS

image-20210524204424343


實驗環境:

Windows Server 2008 R2 sp1 和 kali linux

復現過程:

1.在windows server 2008 安裝dns伺服器,並配置靜態ip

2.在kali 中執行指令碼sudo python sigred_dos.py evil_domain_name

3.在受害者伺服器配置轉發器,轉發器ip為kali 機的ip。

4.在受害者伺服器使用nslookup命令查詢9.evil_domain_name:

nslookup -type=sig 9.ibrokethe.net 127.0.0.1

5.檢視kali,發現會發現收到了一個UDP連線,又收到了一個TCP連線。


復現結果:

抓包結果如下:

image-20210524205603806

由於本地無法解析“ibrokethe.net”,因此會以UDP協議向惡意伺服器kali傳送DNS查詢,也就是kali收到的第一個UDP連線。惡意伺服器查到了該域名,就向受害者傳送響應包,設定TC位,通知受害者採用TCP重發原來的查詢請求,並允許返回的響應報文超過512個位元組。這是第二個DNS包。然後進行三次握手,受害者再次以TCP協議傳送請求,這就是kali收到的TCP連線。之後,惡意伺服器就可以利用TCP傳輸大於64KB的響應包發給受害者,觸發漏洞,造成堆溢位。

然後,就可以進行遠端程式碼執行等操作了。


可以看到在復現的過程,產生堆溢位,dns.exe程式發生崩潰,從而產生DOS攻擊。如下圖:

879291_P2ZBQGC4C59M8U6


漏洞修復

臨時修復方案,修改登錄檔,限制tcp包的長度,TcpReceivePacketSize的值為0xFF00

 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\DNS\Parameters 
  DWORD = TcpReceivePacketSize 
  Value = 0xFF00

注意:必須重新啟動 DNS 服務才能生效。


總結:

協議方面多多少少都會有我們所疏忽的問題,對於dns.exe開發者,最開始並未考慮到最大可以超過65535,造成溢位,程式碼並沒有問題,造成該漏洞的關鍵點,主要是因為域名壓縮。往往很多個疏忽點,湊到了一起就成了攻擊者利用的漏洞。



參考連結:

CVE-2020-1350 Windows Server DNS漏洞復現

漏洞利用剖析:帶有CVE-2020-1350 SIGRed的RCE

CVE-2020-1350: Windows DNS Server蠕蟲級遠端程式碼執行漏洞分析

相關文章