AMNESIA33:開源 TCPIP 協議棧系列漏洞分析與驗證

作者:啓明星辰ADLab
原文鏈接:https://mp.weixin.qq.com/s/UWeFBK3E1Zs4cTcMl4UU3A

一、前言

近期,國外安全研究人員在多個被廣泛使用的開源TCP/IP協議棧發現了多個漏洞,這一系列漏洞統稱爲AMNESIA33。這些漏洞廣泛存在於嵌入式和物聯網設備中,影響了多個行業領域(包括醫療、運輸、能源、電信、工業控制、零售和商業等),目前已知範圍內涉及了超150家供應商以及數以百萬計的設備。與URGEN11和Ripple20不同的是,AMNESIA33影響的是多個開源TCP/IP協議棧,因此這些漏洞可以悄無聲息的地影響到無數個代碼庫、開發團隊與各個公司的產品。目前已知的漏洞涉及到了智能家居、工廠PLC、SCADA設備與工控交換機,電力監控等設備。

這些漏洞存在於uIP、FNET、picoTCP和Nut/Net等開源協議棧上,影響TCP/IP協議棧的多個組件,包括DNS、IPv6、IPv4、TCP、ICMP、LLMNR和mDNS等。其中包括多個嚴重漏洞,它們的CVE編號分別爲CVE-2020-17437、CVE-2020-17443、CVE-2020-24338、CVE-2020-24336、CVE-2020-25111。

CVE-2020-17437(CVSS評分8.2)、CVE-2020-17443(CVSS評分8.2)可導致設備拒絕服務。CVE-2020-24338、CVE-2020-24336、CVE-2020-25111(這三個CVSS評分均爲9.8)都可導致遠程代碼執行(RCE)。其它28個漏洞的嚴重程度各異,CVSS評分分別從4到8.2。

由於IoT、OT、IT設備供應鏈的特性,漏洞影響的設備衆多,影響範圍廣且持續時間長,漏洞修復的實施較困難。同時,由於uIP、picoTCP開源協議棧已經不再維護,所以部分漏洞沒有補丁,很多產品只能尋找替代技術方案或者是增加防範措施。

因此,啓明星辰ADLab對相關漏洞進行了分析,併成功復現了多個漏洞,開發了AMNESIA33相關漏洞檢測技術,並提取了流量監控特徵,這些技術正在應用到我們的安全產品中。爲了緩解漏洞的影響,我們提出了下列防範建議。

二、防範建議

對於這些漏洞的防範緩解措施,我們建議採取如下幾個措施:

(1)配置內網設備的DNS服務器爲內網DNS服務器。

(2)如不必要,請關閉IPv6設置。

(3)利用漏掃產品識別出採用問題協議棧的設備資產,對組織內可能存在問題的IoT,OT和IT設備進行風險評估。

(4)防火牆及IPS產品加入AMNESIA33漏洞攻擊識別特徵,監控惡意流量。

(5)如不必要,設備不要暴露在公網。

(6)儘可能更新相關受影響協議棧到最新版本。

下表是部分已經修復的協議棧及版本

TCP/IP協議棧 修復版本
FNET 4.70及以上
uIP-Contiki-NG 4.6.0及以上
Nut/Net 5.1及以上

CISA聯盟分享了13個涉及到AMNESIA33漏洞的公司的產品修復建議,包括了Microchip、Siemens等公司的產品,詳見參考鏈接[5]。

三、相關概念介紹

1、DNS協議解析

DNS的請求和響應的基本單位是DNS報文(Message)。請求和響應的DNS報文結構是完全相同的,每個報文都由以下五段(Section)構成:

DNS Header是每個DNS報文都必須擁有的一部分,它的長度固定爲12個字節。Question部分存放的是向服務器查詢的域名數據,一般情況下它只有一條Entry。每個Entry的格式是相同的,如下所示:

QNAME是由labels序列構成的域名。QNAME的格式使用DNS標準名稱表示法。這個字段是變長的,因此有可能出現奇數個字節,但不進行補齊。DNS使用一種標準格式對域名進行編碼。它由一系列的label(和域名中用.分割的label不同)構成。每個label首字節的高兩位用於表示label的類型。RFC1035中分配了四個裏面的兩個,分別是:00表示的普通label,11(0xC0)表示的壓縮label。

Answer、Authority和Additional三個段的格式是完全相同的,都是由零至多條Resource Record(資源記錄)構成。這些資源記錄因爲不同的用途而被分開存放。Answer對應查詢請求中的Question,Question中的請求查詢結果會在Answer中給出,如果一個響應報文的Answer爲空,說明這次查詢沒有直接獲得結果。

RR(Resource Record)資源記錄是DNS系統中非常重要的一部分,它擁有一個變長的結構,具體格式如下:

NAME:它指定該條記錄對應的是哪個域名,格式使用DNS標準名稱表示法

TYPE:資源記錄的類型。

CLASS:對應Question的QCLASS,指定請求的類型,常用值爲IN,值爲0x001。

TTL(Time To Live)資源的有效期:表示你可以將該條RR緩存TLL秒,TTL爲0表示該RR不能被緩存。TTL是一個4字節有符號數,但是隻使用它大於等於0的部分。

RDLENGTH:一個兩字節非負整數,用於指定RDATA部分的長度(字節數)。

RDATA:表示一個長度和結構都可變的字段,它的具體結構取決於TYPE字段指定的資源類型。

DNS響應包如下圖所示:

從上圖中可知,該Answers區段中存在9個資源記錄,紅框中表示的是主機地址(A類型)資源記錄。

域標籤label在DNS數據包裏被編碼,每個普通標籤的第一個字節代表這個標籤的長度,剩下的字母數字字符爲標籤本身(一些特殊字符也是可以的),但是最終結尾的字符一定是以空字節結尾(即0x00),用來表示域名的結束。舉個例子,如下圖所示,域標籤第一個字符是0x03,這代表第一個標籤長度爲3(即0x77 0x77 0x77 == “www”),同理,0x62 0x61 0x69 0x64 0x75 == “baidu”,最後可以看到以0x00結尾。

2、TCP緊急模式

爲了發送重要協議數據,TCP提供了一種稱爲緊急模式(urgentmode)的機制,TCP協議在數據段中設置URG位,表示進入緊急模式。通過設置緊急模式,發送方可以在發送隊列中優先發送這部分的數據,而且不用在發送隊列中排隊,而接收方可以對緊急模式採取特殊的處理。這種方式數據不容易接受被阻塞,服務器端程序會優先接受這些緊急的數據,而不用進行排隊處理。在TCP報文中定義了兩個字段來標示緊急模式,一個URG標誌,該標誌表示報文中有緊急數據,另一個標誌是緊急指針,它標示緊急數據在傳輸數據中偏移位置。如下圖所示:

四、漏洞分析

下面我們對幾個CVSS評分較高的漏洞進行分析:

1、CVE-2020-17437

CVE-2020-17437存在於uIP協議棧的uip.c文件的uip_process函數中,該函數主要是處理ip/tcp報文,下圖是uIP協議棧對TCP報文中帶有TCP_URG緊急指針標識時的處理代碼,如果編譯時配置了UIP_URGDATA,則程序會走到下面的if分支,對緊急指針數據進行專門處理。

但是在默認情況下,UIP_URGDATA並沒有配置。代碼會進入到else分支,程序會跳過處理緊急指針數據,並修改uip_len的數值。程序在修改uip_len的時候並沒有判斷緊急指針的值,當uip_len的值特別小,而緊急指針的值urgp 特別大時,就會引起整數溢出,導致設備重啓或者是越界讀寫。

2、CVE-2020-24338

該漏洞出現在picoTCP/IP協議棧中解析域名label的pico_dns_decompress_name()函數中,該函數具體實現如下代碼所示:

第95、96行初始化iterator,name指向待解壓縮的labels,dest_iterator指向存放解壓出來的labels的緩衝區,大小爲256字節。第97行開始爲while循環,讀取到字符串結尾空字節退出。第98行,通過iterator&0xC0判斷label類型,如果爲壓縮label,則通過packet定位到普通label所在的位置,如果爲普通label直接進入else代碼塊中,第107行,調用memcpy將普通label拷貝到dest_iterator中。我們知道dest_iterator緩衝區大小隻有256字節,而while循環退出條件爲讀到字符串結尾空字節,因此當name長度超過256字節時,導致dest_iterator緩衝區溢出。

3、CVE-2020-24336

該漏洞出現在contiki協議棧中的ip64_dns64_4to6()中,該函數功能是將ipv4類型的DNS數據包轉換成ipv6類型的DNS數據包,關鍵代碼如下:

遍歷Answer區段並更新到ipv6類型的Answer區段中。從第209行開始轉換資源記錄,具體實現代碼如下所示:

首先判斷TYPE是否是DNS_TYPE_A,DNS_TYPE_A表示該資源記錄爲ipv4主機地址,然後將對應區段拷貝到acopy中。第220行,從資源記錄中直接取RDLENGTH,前文已介紹,該區段表徵RDATA的長度。第227行,判斷len長度是否等於4,這裏正常情況,len應該爲4,因爲ipv4地址長度爲4個字節。如果len不等於4,則進入else語句中,直接調用memcpy進行RDATA數據拷貝。這裏是存在問題的,Ipv4主機地址長度不等於4,並沒有驗證主機地址的合理性而且len最大爲0xFFFF,直接拷貝可能導致緩衝區溢出。

4、CVE-2020-25111

在使用Nut/Net協議棧的設備中,NutDnsGetResourceAll()是處理DNS請求的函數,其中處理DNS答覆的函數是DecodeDnsQuestion(),處理域標籤的函數是ScanName(),漏洞就出現在ScanName()函數中。如下圖所示,cp爲指向域名第一個字節的指針(即第一個域標籤的長度字節),npp爲即將被解析的域名buffer,通過strlen()將整個域名長度賦值給rc,然後基於rc分配npp buffer,之後通過一個while,循環處理每一個label。問題顯而易見,cp是攻擊者可控的,由此可以控制npp的大小。而對於標籤的長度,即len變量,直接從數據包中得到,並沒有做任何邊界檢查,然後通過while循環處理。因此可以對len設置任意的值,即攻擊者對npp buffer可控的長度。由此可以在堆中造成越界寫,這可導致遠程代碼執行(RCE)。

5、CVE-2020-17443

CVE-2020-17443存在於PicoTCP協議棧pico_icmp6.c文件中。問題代碼位於pico_icmp6_send_echoreply()函數中,該函數的主要功能是回覆ICMPv6應答數據包以響應對端的ICMPv6 Echo(ping)請求。

我們可以看到第68行,replay結構的緩衝大小基於echo的報文中transport_len變量。

在第84行,程序從echo->payload向reply->payload地址複製了長度爲echo->transport_len - 8大小的數據。

注意,如果echo->transport_len 小於 8,echo->transport_len - 8會導致整數溢出,memcpy操作會導致緩衝區溢出。

在PicoTCP協議棧攻擊者通過構造惡意的ICMPv6數據包,這個惡意的數據包ICMP報頭小於8,會導致設備重啓或拒絕服務。

五、漏洞驗證

1、CVE-2020-17437漏洞驗證視頻

2、CVE-2020-17443漏洞驗證視頻

詳見以下鏈接:

https://mp.weixin.qq.com/s?__biz=MzAwNTI1NDI3MQ==&mid=2649615617&idx=1&sn=b6df9ee2c5265ded1913b318cc241d90&chksm=83063011b471b9073ac1b159d95ed8f40617d5897442ba9157c446962a560cccc3477205cd67&token=566237918&lang=zh_CN#rd

六、參考鏈接

1、https://www.forescout.com/research-labs/amnesia33/

2、https://www.securityweek.com/amnesia33-vulnerabilities-tcpip-stacks-expose-millions-devices-attacks

3、https://www.zdnet.com/article/amnesia33-vulnerabilities-impact-millions-of-smart-and-industrial-devices/

4、https://tools.ietf.org/html/rfc1035

5、https://us-cert.cisa.gov/ics/advisories/icsa-20-343-01


Paper 本文由 Seebug Paper 發佈,如需轉載請註明來源。本文地址:https://paper.seebug.org/1428/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章