一、Go語言木馬增長(zhǎng)顯著
據(jù)網(wǎng)絡(luò)安全公司 Intezer 報(bào)告顯示,惡意軟件的開發(fā)者已經(jīng)從 C 和 C++ 逐漸轉(zhuǎn)向 Go 語言,自 2017 年以來,基于 Go 語言的惡意軟件數(shù)量呈現(xiàn)爆發(fā)式增長(zhǎng),增幅超過了 2000%。預(yù)計(jì)Go的使用率在未來幾年將持續(xù)上升,并與C、C++和Python一起,成為惡意軟件編碼的首選編程語言之一。
Go語言木馬的迅猛增長(zhǎng),與Go語言天然的開發(fā)優(yōu)勢(shì)有較強(qiáng)聯(lián)系。與其他開發(fā)語言相比,Go的主要優(yōu)勢(shì)表現(xiàn)在:
經(jīng)過情報(bào)搜集可以發(fā)現(xiàn),從最近兩年開始,除一般惡意軟件外,某些知名APT惡意軟件Zebrocy、SUNSHUTTLE、HabitsRAT等,也使用Go語言開發(fā)編譯,并且利用TLS協(xié)議實(shí)現(xiàn)與C&C服務(wù)器之間的加密通信。為了研究在Go語言木馬的加密通信特征并達(dá)成有效檢測(cè),我們對(duì)Go語言中TLS協(xié)議的實(shí)現(xiàn)細(xì)節(jié)進(jìn)行了研究,重點(diǎn)考察TLS協(xié)議握手協(xié)商的獨(dú)有特點(diǎn)。文末針對(duì)Go語言實(shí)現(xiàn)的惡意加密流量檢測(cè)給出了實(shí)例。
二、Go語言TLS協(xié)議實(shí)現(xiàn)分析
TLS(Transport Layer Security)是一個(gè)保證信息安全的應(yīng)用層協(xié)議,它的前身是 SSL。它是一套對(duì)由 TCP 傳輸?shù)膱?bào)文進(jìn)行加密的協(xié)議。TLS通常用于保證Web通信(HTTP)以及其他流行協(xié)議的安全,比如POP、IMAP,當(dāng)它們使用TLS保護(hù)后,分別被稱為HTTPS、POPS和IMAPS。
我們對(duì)Go語言中TLS通信的實(shí)現(xiàn)過程進(jìn)行了研究分析。在Go語言中,實(shí)現(xiàn)TLS通信主要分為以下幾步:創(chuàng)建請(qǐng)求、獲取連接、建立TCP連接、實(shí)現(xiàn)TLS握手、傳輸加密數(shù)據(jù)。
2.1外層封裝分析
在Go語言中,HTTPS協(xié)議的實(shí)現(xiàn)方法是以HTTP協(xié)議包中實(shí)現(xiàn)的,且具有相同的請(qǐng)求流程:
在Go的官方文檔中,共提供了五種實(shí)現(xiàn)方法:Get、Head、Post、PostForm和Do。其中前四種方法都調(diào)用Do方法,即使直接調(diào)用Get、Head、Post或PostForm,內(nèi)部同樣會(huì)創(chuàng)建Request對(duì)象,且最終總是通過Client.Do函數(shù)發(fā)送請(qǐng)求。下圖為實(shí)現(xiàn)Get方法的函數(shù)調(diào)用順序,可以發(fā)現(xiàn)通過Client.Do()方法調(diào)用私有的Client.do()方法來執(zhí)行請(qǐng)求,并且在最后執(zhí)行請(qǐng)求中調(diào)用 Transport的 RoundTrip方法。
2.2連接機(jī)制分析
在Go中,具有獨(dú)特的連接管理機(jī)制——連接池。發(fā)送請(qǐng)求時(shí),我們從連接池中獲取連接,請(qǐng)求完畢后再將連接還給連接池;連接池幫我們實(shí)現(xiàn)了連接的建立、復(fù)用以及回收工作。而在HTTPS中,連接池就是通過調(diào)用 Transport的 RoundTrip方法實(shí)現(xiàn)的。
連接池機(jī)制
在RoundTrip方法中,調(diào)用了私有的roundTrip方法,其中通過getConn方法來獲取連接或者建立新的連接。在getConn中,主要有兩步操作,第一步先嘗試從空閑的連接池獲取空閑連接(通過GotConn方法),如果緩存中有空閑的連接則獲取空閑的連接;如果空閑的連接池中沒有可用的連接,則調(diào)用dialConn方法來新建連接。
在dialConn方法中,新建連接的大致過程如下:
在第二步創(chuàng)建連接中,對(duì)于HTTPS請(qǐng)求,會(huì)進(jìn)行兩步操作,分別建立TCP連接,和TLS連接。其中,dial負(fù)責(zé)建立TCP連接,實(shí)現(xiàn)TCP的四次握手;addTLS負(fù)責(zé)TLS連接,實(shí)現(xiàn)TLS握手。
2.3 TCP握手建立分析
在Go中,網(wǎng)絡(luò)編程依舊是依賴socket編程實(shí)現(xiàn)的,在net包中有一個(gè)TCPConn類型,可以用來建立TCP客戶端和TCP服務(wù)端間的通信通道。TCPConn 類型里有兩個(gè)主要的方法:Write和Read,用來實(shí)現(xiàn)通信時(shí)的數(shù)據(jù)讀寫。
在上一節(jié)我們提到了dial方法,dial方法會(huì)調(diào)用DialTCP方法來建立一個(gè)TCP連接,并返回一個(gè)TCPConn類型的對(duì)象。在DialTCP方法中,Go通過syscall系統(tǒng)調(diào)用,實(shí)現(xiàn)了對(duì)socket方法的調(diào)用。
同樣的,Go使用syscall系統(tǒng)調(diào)用實(shí)現(xiàn)了bind、connect、send和recv等方法。對(duì)于socket編程的初始化方法WSAStartup,Go語言也進(jìn)行調(diào)用,不過調(diào)用的位置在執(zhí)行main函數(shù)之前的main_init函數(shù)中,該函數(shù)的主要功能是對(duì)需要使用的函數(shù)庫(kù)進(jìn)行初始化。
2.4 TLS協(xié)商發(fā)起分析
建立TCP通信通道后,在addTLS方法下通過調(diào)用Client方法封裝得到一個(gè)tls包下的Conn結(jié)構(gòu)。
在這個(gè)封裝過程中會(huì)對(duì)調(diào)用clientHandshake方法來實(shí)現(xiàn)TLS握手,其中makeClientHello方法是對(duì)TLS握手中的ClientHello進(jìn)行設(shè)置。在makeClientHello方法中,首先會(huì)判斷是否有tls.config,也就是檢查是否存在用戶自定義的ClientHello設(shè)置,如果不存在則按照默認(rèn)情況生成,并存儲(chǔ)在clientHelloMsg結(jié)構(gòu)體中。下面針對(duì)ClientHello的詳細(xì)信息進(jìn)行分析。
2.4.1密碼套件列表
如果用戶沒有設(shè)置自定義密碼套件,Go語言就會(huì)使用庫(kù)文件中默認(rèn)的密碼套件。也就是說對(duì)于Go中生成的默認(rèn)TLS通信,密碼套件是固定的,且由庫(kù)函數(shù)決定。下圖為Go1.17版本中,默認(rèn)的密碼套件。
在1.13版本Go開始提供對(duì)TLSv1.3的支持,并且增加了3個(gè)TLSv1.3獨(dú)有的密碼套件。
2.4.2默認(rèn)壓縮方式
默認(rèn)壓縮方式為無壓縮。
2.4.3隨機(jī)數(shù)和SessionID
均為隨機(jī)生成。
2.4.4擴(kuò)展項(xiàng)
從實(shí)現(xiàn)源碼分析,Go默認(rèn)提供Status_Request、Signed_Certificate_Timestamp、Supported_Groups、EC_Point_Formats等擴(kuò)展。根據(jù)調(diào)用方式的不同,可能會(huì)產(chǎn)生Server_Name_Indicator、Supported_Versions、Application_Layer_Protocol_Negotiation等擴(kuò)展。擴(kuò)展內(nèi)容可能與調(diào)用時(shí)的設(shè)置和輸入有關(guān)。
2.5實(shí)際流量驗(yàn)證
通過以上的研究,可以確定,Go語言下TLS通信依舊使用了socket網(wǎng)絡(luò)編程體系,且是通過syscall系統(tǒng)調(diào)用實(shí)現(xiàn)的。在不主動(dòng)對(duì)TLS握手特征進(jìn)行設(shè)置時(shí),TLS握手特征是由Go語言的庫(kù)文件決定的。經(jīng)過實(shí)驗(yàn)后,發(fā)現(xiàn)不同平臺(tái)下、不同版本(1.11-1.17)的Go語言中默認(rèn)的clientHello信息基本是不變的。
進(jìn)一步確定加密套件的變化情況,發(fā)現(xiàn)在1.13版本之前有16個(gè)加密套件,1.13版本之后在這16個(gè)加密套件不變的基礎(chǔ)上多了3個(gè)加密套件。這是由于在1.13版本時(shí)新增了對(duì)TLSv1.3的支持,導(dǎo)致后續(xù)版本中新增了3個(gè)TLSv1.3的密碼套件。
Go語言中TLSv1.2和TLSv1.3的密碼套件
Go語言在默認(rèn)情況下,壓縮方式會(huì)選擇無壓縮,提供Status_Request、Signed_Certificate_Timestamp、Supported_Groups、EC_Point_Formats等擴(kuò)展項(xiàng)。下圖為默認(rèn)情況下,1.17版本Go語言產(chǎn)生的TLS流量中,ClientHello的擴(kuò)展項(xiàng)情況。
Go語言TLS默認(rèn)擴(kuò)展項(xiàng)
三、Go語言和C/C++的TLS加密對(duì)比
和傳統(tǒng)編程語言C/C++相比,Go語言下TLS協(xié)議完全由自身的封裝庫(kù)實(shí)現(xiàn),而C/C++語言則需要導(dǎo)入第三方庫(kù)來實(shí)現(xiàn)。所以,默認(rèn)情況下,GO語言TLS協(xié)議的握手特征只與Go語言的版本相關(guān),而C/C++語言則是由使用的第三方庫(kù)的類型、版本及調(diào)用參數(shù)決定的。
? | Go語言 | C/C++ |
TLS會(huì)話的實(shí)現(xiàn)方式 | 通過syscall系統(tǒng)調(diào)用socket函數(shù) | 通過Openssl等第三方庫(kù)調(diào)用socket函數(shù) |
默認(rèn)密碼套件列表 | 基于Go語言封裝庫(kù),由Go語言的版本決定 | 基于第三方庫(kù),受第三方庫(kù)的類型、版本及調(diào)用參數(shù)影響 |
默認(rèn)壓縮方式 | 基于Go語言封裝庫(kù),一般為無壓縮方式 | 基于第三方庫(kù),一般為無壓縮方式 |
隨機(jī)數(shù)和SessionID | 由Go語言封裝庫(kù)隨機(jī)生成 | 由第三方庫(kù)隨機(jī)生成 |
擴(kuò)展項(xiàng) | 基于Go語言封裝庫(kù),由Go語言的版本決定 | 基于第三方庫(kù),受第三方庫(kù)的類型、版本及調(diào)用參數(shù)影響 |
四、Go語言木馬惡意加密通信檢測(cè)分析實(shí)例
以Win32.Vobfus.azpd惡意軟件為例,該惡意軟件由Go語言開發(fā)編譯。下圖為Win32.Vobfus.azpd的TLS惡意加密流量檢測(cè)情況,可以發(fā)現(xiàn)該流量中,使用了16套加密套件,與Go語言默認(rèn)使用的加密套件一致;但擴(kuò)展項(xiàng)為9項(xiàng),比默認(rèn)情況下的6項(xiàng)多了3項(xiàng),說明惡意軟件對(duì)擴(kuò)展項(xiàng)進(jìn)行了主動(dòng)設(shè)置。最終,觀成瞰云-加密威脅智能檢測(cè)系統(tǒng)(ENS)對(duì)TLS會(huì)話的握手信息評(píng)分為0.75,結(jié)合證書檢測(cè)、行為檢測(cè)等因素,綜合評(píng)分為0.66,威脅標(biāo)簽為Win32.Vobfus.azpd。