Go语言木马加密通信分析与检测
一、Go语言木马增长显著
据网络安全公司 Intezer 报告显示,恶意软件的开发者已经从 C 和 C++ 逐渐转向 Go 语言,自 2017 年以来,基于 Go 语言的恶意软件数量呈现爆发式增长,增幅超过了 2000%。预计Go的使用率在未来几年将持续上升,并与C、C++和Python一起,成为恶意软件编码的首选编程语言之一。
Go语言木马的迅猛增长,与Go语言天然的开发优势有较强联系。与其他开发语言相比,Go的主要优势表现在:
Go支持跨平台编译,开发者只需要编写一次代码,就可以编译出多个平台的二进制文件,包括Windows、Linux和Mac系统。
Go具有很强的反逆向能力,安全人员对Go语言生成的二进制文件逆向分析难度很大,杀毒软件对Go语言生成的恶意软件检测效率比较低。由于Go使用了静态编译,导致生成的二进制文件体积比较大,在反汇编工具中打开Go语言二进制文件,往往会看到上千个函数。再加上,Go独特的调用约定、栈空间管理和多返回值机制,进一步加大了Go的逆向分析难度。
Go语言在编写网络堆栈方面具有明显优势,Go语言有一个非常好用的网络栈,因此使用 Go 语言编写需要经常发送、接收网络数据包的恶意软件会更加容易。实际上,谷歌设计创建Go语言的一个原因就是用来取代谷歌内部的C++网络服务。
经过情报搜集可以发现,从最近两年开始,除一般恶意软件外,某些知名APT恶意软件Zebrocy、SUNSHUTTLE、HabitsRAT等,也使用Go语言开发编译,并且利用TLS协议实现与C&C服务器之间的加密通信。为了研究在Go语言木马的加密通信特征并达成有效检测,我们对Go语言中TLS协议的实现细节进行了研究,重点考察TLS协议握手协商的独有特点。文末针对Go语言实现的恶意加密流量检测给出了实例。
二、Go语言TLS协议实现分析
TLS(Transport Layer Security)是一个保证信息安全的应用层协议,它的前身是 SSL。它是一套对由 TCP 传输的报文进行加密的协议。TLS通常用于保证Web通信(HTTP)以及其他流行协议的安全,比如POP、IMAP,当它们使用TLS保护后,分别被称为HTTPS、POPS和IMAPS。
我们对Go语言中TLS通信的实现过程进行了研究分析。在Go语言中,实现TLS通信主要分为以下几步:创建请求、获取连接、建立TCP连接、实现TLS握手、传输加密数据。
2.1外层封装分析
在Go语言中,HTTPS协议的实现方法是以HTTP协议包中实现的,且具有相同的请求流程:
创建http.Client对象client;
创建http.Request对象req;
发送请求client.do(req);
关闭resp.Body.Close()。
在Go的官方文档中,共提供了五种实现方法:Get、Head、Post、PostForm和Do。其中前四种方法都调用Do方法,即使直接调用Get、Head、Post或PostForm,内部同样会创建Request对象,且最终总是通过Client.Do函数发送请求。下图为实现Get方法的函数调用顺序,可以发现通过Client.Do()方法调用私有的Client.do()方法来执行请求,并且在最后执行请求中调用 Transport的 RoundTrip方法。
2.2连接机制分析
在Go中,具有独特的连接管理机制——连接池。发送请求时,我们从连接池中获取连接,请求完毕后再将连接还给连接池;连接池帮我们实现了连接的建立、复用以及回收工作。而在HTTPS中,连接池就是通过调用 Transport的 RoundTrip方法实现的。
连接池机制
在RoundTrip方法中,调用了私有的roundTrip方法,其中通过getConn方法来获取连接或者建立新的连接。在getConn中,主要有两步操作,第一步先尝试从空闲的连接池获取空闲连接(通过GotConn方法),如果缓存中有空闲的连接则获取空闲的连接;如果空闲的连接池中没有可用的连接,则调用dialConn方法来新建连接。
在dialConn方法中,新建连接的大致过程如下:
首先初始化persistConn结构体;
创建连接,创建连接时区分HTTPS和http;
连接创建成功后,会开启两个协程writeLoop和readLoop,分别用于处理输入输出流。
在第二步创建连接中,对于HTTPS请求,会进行两步操作,分别建立TCP连接,和TLS连接。其中,dial负责建立TCP连接,实现TCP的四次握手;addTLS负责TLS连接,实现TLS握手。
2.3 TCP握手建立分析
在Go中,网络编程依旧是依赖socket编程实现的,在net包中有一个TCPConn类型,可以用来建立TCP客户端和TCP服务端间的通信通道。TCPConn 类型里有两个主要的方法:Write和Read,用来实现通信时的数据读写。
在上一节我们提到了dial方法,dial方法会调用DialTCP方法来建立一个TCP连接,并返回一个TCPConn类型的对象。在DialTCP方法中,Go通过syscall系统调用,实现了对socket方法的调用。
同样的,Go使用syscall系统调用实现了bind、connect、send和recv等方法。对于socket编程的初始化方法WSAStartup,Go语言也进行调用,不过调用的位置在执行main函数之前的main_init函数中,该函数的主要功能是对需要使用的函数库进行初始化。
2.4 TLS协商发起分析
建立TCP通信通道后,在addTLS方法下通过调用Client方法封装得到一个tls包下的Conn结构。
在这个封装过程中会对调用clientHandshake方法来实现TLS握手,其中makeClientHello方法是对TLS握手中的ClientHello进行设置。在makeClientHello方法中,首先会判断是否有tls.config,也就是检查是否存在用户自定义的ClientHello设置,如果不存在则按照默认情况生成,并存储在clientHelloMsg结构体中。下面针对ClientHello的详细信息进行分析。
2.4.1密码套件列表
如果用户没有设置自定义密码套件,Go语言就会使用库文件中默认的密码套件。也就是说对于Go中生成的默认TLS通信,密码套件是固定的,且由库函数决定。下图为Go1.17版本中,默认的密码套件。
在1.13版本Go开始提供对TLSv1.3的支持,并且增加了3个TLSv1.3独有的密码套件。
2.4.2默认压缩方式
默认压缩方式为无压缩。
2.4.3随机数和SessionID
均为随机生成。
2.4.4扩展项
从实现源码分析,Go默认提供Status_Request、Signed_Certificate_Timestamp、Supported_Groups、EC_Point_Formats等扩展。根据调用方式的不同,可能会产生Server_Name_Indicator、Supported_Versions、Application_Layer_Protocol_Negotiation等扩展。扩展内容可能与调用时的设置和输入有关。
2.5实际流量验证
通过以上的研究,可以确定,Go语言下TLS通信依旧使用了socket网络编程体系,且是通过syscall系统调用实现的。在不主动对TLS握手特征进行设置时,TLS握手特征是由Go语言的库文件决定的。经过实验后,发现不同平台下、不同版本(1.11-1.17)的Go语言中默认的clientHello信息基本是不变的。
进一步确定加密套件的变化情况,发现在1.13版本之前有16个加密套件,1.13版本之后在这16个加密套件不变的基础上多了3个加密套件。这是由于在1.13版本时新增了对TLSv1.3的支持,导致后续版本中新增了3个TLSv1.3的密码套件。
Go语言中TLSv1.2和TLSv1.3的密码套件
Go语言在默认情况下,压缩方式会选择无压缩,提供Status_Request、Signed_Certificate_Timestamp、Supported_Groups、EC_Point_Formats等扩展项。下图为默认情况下,1.17版本Go语言产生的TLS流量中,ClientHello的扩展项情况。
Go语言TLS默认扩展项
三、Go语言和C/C++的TLS加密对比
和传统编程语言C/C++相比,Go语言下TLS协议完全由自身的封装库实现,而C/C++语言则需要导入第三方库来实现。所以,默认情况下,GO语言TLS协议的握手特征只与Go语言的版本相关,而C/C++语言则是由使用的第三方库的类型、版本及调用参数决定的。
Go语言 | C/C++ | |
TLS会话的实现方式 | 通过syscall系统调用socket函数 | 通过Openssl等第三方库调用socket函数 |
默认密码套件列表 | 基于Go语言封装库,由Go语言的版本决定 | 基于第三方库,受第三方库的类型、版本及调用参数影响 |
默认压缩方式 | 基于Go语言封装库,一般为无压缩方式 | 基于第三方库,一般为无压缩方式 |
随机数和SessionID | 由Go语言封装库随机生成 | 由第三方库随机生成 |
扩展项 | 基于Go语言封装库,由Go语言的版本决定 | 基于第三方库,受第三方库的类型、版本及调用参数影响 |
四、Go语言木马恶意加密通信检测分析实例
以Win32.Vobfus.azpd恶意软件为例,该恶意软件由Go语言开发编译。下图为Win32.Vobfus.azpd的TLS恶意加密流量检测情况,可以发现该流量中,使用了16套加密套件,与Go语言默认使用的加密套件一致;但扩展项为9项,比默认情况下的6项多了3项,说明恶意软件对扩展项进行了主动设置。最终,观成瞰云-加密威胁智能检测系统(ENS)对TLS会话的握手信息评分为0.75,结合证书检测、行为检测等因素,综合评分为0.66,威胁标签为Win32.Vobfus.azpd。