【IT168专稿】考虑到恶意软件的扩散和越来越高级,不难看出传统的杀毒软件技术为什么不能应付僵尸网络。大多数IDS系统的重点放在检测已知的威胁方面,或者放在检测一个僵尸电脑主机启动之后产生的通讯量增加的现象方面。然而,大多数僵尸电脑是多种形态的:它们每一次安装都进行改变,使其看起来像新的一样。而且,大多数僵尸电脑仅定期向僵尸电脑主机发送少量的信息。这个通讯量是在IDS系统规定的限制之内的。
在这篇文章的里,我们介绍一下针对早期僵尸网络探测的Canary探测器。
Canary探测器的三个策略
Canary探测器包含三个有潜力的反僵尸网络策略。第一个策略是分析真正的企业网络的踪迹,暴露僵尸网络实际的工作情况。这种分析还能够显示某些用户驱动的网络通讯流量的属性与僵尸网络通讯流量的区别。第二个策略是能够根除僵尸网络指挥与控制渠道的端点主机检测算法。这种方法是以一个单个的持续值的算法为基础的。这是衡量如何定期联络远程目标的方法。这种方法的优势是它不需要对需要检测的僵尸网络有先验的知识,也不需要检测通讯流量的负载。虽然僵尸网络检测能力也许只在单个的端点主机上实施,但是,把许多系统关联起来会进一步改善这种检测能力。这种关联可以在一个网络操作中心实施或者完全以分散的方式实施,以识别多个系统持续目标的共性。这是第三个策略。
Canary探测器的设计
Canary探测器采用一种新颖的方法检测诸如僵尸网络等隐蔽的端点托管的恶意软件。我们在这里使用隐蔽这个词汇是因为它还没有产生能够引起人们注意的通讯量。我们检测方案的中心思路是跟踪目标原子(atom)的使用,目标原子是解释各种服务的目标地址的逻辑集合。特别是我们要测量这些目标原子的关联,临时为单个用户测量这种关联和为分散在多个地方的用户测量这种关联,并且审查那些变得很重要的目标原子。例如,在检测僵尸网络的时候,招募的端点主机一般都定期地呼叫家里。通过跟踪这个目标原子,我们能够在它变得非常严重的时候为它做出标记。
英特尔企业踪迹中的目标原子
我们对于研究用户行为与网络流量方式的直接关联很感兴趣。因此,我们搜集了英特尔公司网络内部的企业数据。我们搜集了5个星期的大约400个端点主机的踪迹。我们和其他人员随后进行了数据挖掘以发现有趣的现象、统计以及与一贯的设想相矛盾的地方。
在研究真正的企业踪迹的时候,我们看到,当目标的应用相互关联的时候,效率得到了显著的提高。因此,我们的Canary算法仅依靠我们称之为目标原子的抽象层。这是网络服务的逻辑代表。这种水平的摘要显著减少了跟踪的目标实体的数量,从而减少跟踪原子所需要的人员。对应一个连接的目的地的基本定义是元组(目标IP、目标端口、proto)。元组是一个用于连接的端点,由目标地址、目标端口和正在使用的proto传输协议所组成。在知名的服务中,多个物理主机经常提供同样的难以区别的应用程序服务。因此,我们能够把一组服务组合为一个单个的原子(目标IP、目标端口、proto)。在这里,这个服务就是基础地址解析的这个域名。这些原子的例子包括 (www.google.com, 80, tcp)、(akamaitech.com, 80, tcp)和(mail.cisco.com, 135, tcp)。
通过进一步研究应用程序使用端口的情况还可能进一步概括这个应用。设想一个用PASV模式连接的FTP服务器。最初的连接是通过端口21,但是,另一个服务器协商的短期使用的端口可用于数据传输。这样,一个FTP进程就有两个原子(ftp.service.com, 21, tcp)和(ftp.service.com, k, tcp)。在这里,“k”是一个1024以外的端口号码,可以看作是提供相同的服务。通过考虑FTP语义,我们能够把1024编号以上的全部端口增加到相关的原子(ftp.service. com, 21:>1024, tcp)。这意味着当我们看到端口21的连接时,我们可以预计在不远的将来使用一个短期的端口。
在真正的企业跟踪中,我们有许多机会实施这种水平的摘要,主要是针对微软135至139之间的RPC端口。然后,我们得出这个目标原子的全面定义(地址集、端口集和proto协议)。在这里,地址集是一组目标地址:这些地址与应用程序提供的地址是一样的;端口集是一组单个的端口或者端口范围;最后,proto是这个服务使用的一个传输协议。表1枚举了一些从企业踪迹中提取的一些原子。
表1:从企业踪迹中提取的原子(来源:英特尔公司,2009)
需要指出的是,一个目标主机能够提供许多独特的服务。在这种情况下,这个端口足以消除各个服务的歧义,尽管这些服务有同样的服务名称。这些服务名称可以通过反向DNS查询获得。最后,需要指出的是,在地址不能映射到名称的时候,做摘要是不可能的。常规的目标地址是最终的描述符。
持续性
反僵尸网络技术的关键是发现对网络产生严重的临时影响的因素,无论其通讯量的水平如何。也就是发现那些有规律的服务。再说一次,这个策略是使用不同的方式对各个地方的不同的用户群进行真正的企业踪迹分析验证的。我们认为,这组端点主机重要的原子是小的和稳定的。当一个主机被恶意软件感染的之后,它将定期与一台主服务器联系,于是这台主服务器就暴露了。要实施这个探测,我们首先必须给“定期”这个模糊的概念提供一个数值。我们说的定期是指一个原子的持续性。我们要跟踪这个使用的规律性,而不是这个连接的本身。考虑一下使用你的新闻阅读器下载重要新闻的情况。每一次启动这个新闻阅读器应用程序的时候,它都要进行大量的连接。要跟踪与端点主机进行的时间最长的通讯,我们将重点跟踪高水平的进程,而不是单个连接的频率。
要跟踪高水平的进程,我们使用一个小的跟踪窗口“w”为通向那个原子的连接标上二进制代码,我们给这个窗口分配一个“1”或者一个“0”。显然,这个跟踪窗口的长度应该覆盖这个进程。当我们发现大量用户的单个原子的到达时间间隔的时候,我们看到59%的通向原子的连接的间隔时间不到1分钟,87%的通向同样的原子的连接的间隔时间至少是1个小时。因此,我们选择一个小时作为跟踪时间窗口长度来计算持续性。
为持续性分配数值的另一个必要的步骤是建立一个观察窗口“W”。也就是说,我们要研究在这个原子的分类变成重要的原子之前,定期观察一个原子的时间应该有多长。根据使用这个数据的经验,我们定义这个观察窗口是:W = 10w,基本上覆盖了一个平均工作日。在定义w和W = (w1, w2 , . . . , w10) 之后,我们对一个原子“a”的持续性进行量化。正如在主机h上观察到的那样,在观察窗口W,p (a, h, W),在观察原子的地方的许多单个的窗口w1, w2 , . . . , wn ,对持续性进行量化。
如果我们把p*表示为一个原子变成重要规律的临界值,那么,如果p (a, h, W) > p*,目的地a就被认为是主机h的持续性。需要指出的是,持续性的定义有W规定的内在的时间量程。假设那个w = 1小时,W = 1天。当在这个范围进行计算的时候,持续性将捕捉一个原子的每一天的行为。然而,它没有捕捉到可能存在的长期趋势。考虑两个不同的原子:a1,每一个小时看到一次;a2,每天看到一次。我们的得到这样一个公式:p (a1) = 24/24 + p(a2) = 1/24。
然而,直观地看,这两个不同的原子都非常有规律。因此,这两个原子都应该使用持续性这个词汇。事实上,因为我们正在设法检测我们没有先验的时间量程信息的隐蔽的恶意软件,我们选择的这个时间量程也许正好漏掉了恶意软件活动的时间。因此,不要依靠一个单独的时间量程W,我们可以考虑5个不同的时间量程W1 , W2 , . . . , W5。因此,对于每一个原子来说,我们计算p (a, h, Wi) for i = 1, 2, . . . , 5,并且说如果最大p (a, h, Wi) > p*,这就是持续性。
共性
虽然持续性定义为单个最终用户的属性,但是,我们可以使用共性量化一个目标原子与一个网络上的用户有何关联。因此,如果大量的用户正在与它沟通,一个目标原子在这个范围内是很重要的。由于这些原子是因为一个网络中的许多用户创建的,我们预计这些原子在数量上是非常稳定的。这个共性标准的定义非常简单:设N (a)为那个数量中的用户数量。那些用户能够看到原子a,至少在某些观察窗口是如此。因此,原子a, c (a)的共性 = N (a)/N。在这里,N是这个网络中的主机总数。此外,我们可以要求得到向它报告连接的一些主机的原子的最低持续性。这样做可以计算激增用户群等一些临时的短暂的影响。
与持续性不同,这种共性指标不能在一个单个的端点主机上孤立地计算。持续性需要系统有一种方法搜集和关联许多端点主机的信息。一个解决方案是假设有一个集中的IT运营中心(ITOC)能够搜集从所有的端点主机观察到的原子的定期报告,并且确定在这些原子中的重要的通用原子。替代的方法是同级的系统能够与这些群体的子集定期共享持续性的信息。
与IT运营中心的方法相比,重要的通用原子是在端点主机上定义和维护的。在这两种方案中,重要的一点是一个滑动窗口是在整个观察窗口(不同时间量程中的最大时间量程)维护的。在计算这个共性指标的时候,仅考虑在这个观察窗口中的报告。再说一次,这个重要性的测试是在c (a) 值大于一个具体的门限值c的时候进行的。当c (a) > c的时候,这就是那个群体中的共性。
建立白名单
我们采取两个步骤为每一个用户建立一个白名单。首先,主机在训练期间观察其通讯,建立一组原子并且跟踪其持续性。这个训练的时间长度取决于通讯方式的稳定程度。我们希望训练时间长度由网络运营商确定。我们确定p是持续性的门限值:也就是说,如果一个特定的原子的持续性大于p,那么,这个原子就添加到白名单。在检测阶段,每一个端点主机把自己观察到的原子(全部的原子,而不仅仅是持续性的原子)发送到这个企业的中央IT运营中心或者发送到类似机构的下属机构。在IT运营中心,将计算在这个逻辑和其中的每一个原子的共同性。我们定义共同性c的一个门限值,并且收集共同性超过c的那些原子。这些原子发送到每一个端点主机。端点主机把这些原子添加到这个白名单。因此,每一个主机的白名单都有两个组件:一个单个的组件捕捉对于那个系统来说是独特的行为。另一个通用组件是群体中常见的行为。这个通用组件包含的某些原子可以不是单个主机正常行为的一部分。
检测算法
在一个高级水平上,我们的系统可以对两种类型的事件发出警报。这两类事件是:(1)p-报警,当没有列入主机白名单的一个目标原子变得具有持续性的时候发出的报警;(2)c-报警,当在同一个窗口的大量端点主机中观察到一个目标原子并且识别出这个目标原子是普通的原子时发出的报警。注意,p-报警通常是本地发出的;用户收到报警并且要求告知收到这个报警。相比之下,如果完整的白名单发送给全部用户的话,c-报警可以在中央IT运营中心或者本地发出。需要指出的是,当与一个原子相关的报警变得非常重要时,将出现下面两种情况之中的一种情况:(1)这个原子被分类为良性的(按照用户或者运营商),在这种情况下,它必须添加到适当的白名单中;(2)这个报警指出恶意的行为,要求采取补救措施。我们在这篇文章中不讨论补救措施阶段的事情。我们仅指出一些可能性,如调解通讯流,通过一个设备重新定向通讯流、封锁通讯流等等。
processPacket(pkt, t, wi)
a <-- getDestAtom(pkt)
if a in WHITELIST then
return /* ignore atoms already in the whitelist */
end if
if a is a new connection initiation then
DCT[a][currIdx] = 1 /*update persistence */
sendReport(userID, a, t) /*report sent to central console*/
end if
在这一节的其余部分,我们简单地评估一下处理输出数据包(在表1中综合说明的)所需要的具体行动。当对应于一个原子的输出数据包已经在一个单个主机的白名单中的时候,不需要进一步采取什么行动。如果输出数据包没有对应一个已经存在于主机白名单中的原子,那么,应该采取如下步骤:
•如果这个原子是以前没有见过的,用于跟踪持续性(DCT)的数据结构中应该创建一个新的记录。这是通过一个原子做索引的并且指向一个位图。每一个位图对应一个特定的跟踪窗口。
•跟踪原子(标记为DCT)观察的这个数据结构将为当前的跟踪窗口进行更新。
•这个原子如果是新的,它将被发送到IT运营中心(也许通过一个最低持续性规定过滤之后再发送)。
需要指出的是,我们的系统没有绑定任何独特的通讯功能。为了方便,我们假设每分钟的连接次数是考虑的特点。要发出p报警,我们使用一个滑动窗口在所有的时间量程跟踪持续性。图2描述了这样做的数据结构。要维护一个字典(或者一个hash表),这个字典中有一个原子的索引,这个字典的记录显示与这个原子有关的位图。当在一个跟踪窗口wi看到这个原子的时候,这个ith二进制位设置为1,像图2描绘的那样。随着滑动窗口的移动,在最后一个跟踪窗口中观察到的每一个原子的持续性都要在这最后一个窗口的末端进行计算。为多个时间量程做这个事情似乎是很昂贵的。然而,一个有趣的观察是我们不需要在不同的时间量程复制这个架构。相反,我们需要利用这个时间量程重复的性质(W3 < W4),我们能够使用一个长的位图取消这个架构。这个位图有足够的字节覆盖最长的观察窗口。
图2 用于跟踪原子持续性的数据结构(来源:英特尔公司,2009)
如果在任何时候这个原子的持续值超过门限值p,就会发出这个原子的报警。在这个时候,用户将被要求验证这个原子是否合法,是否应该把这个原子添加到白名单。如果这个值甚至在充分跟踪之后还是不大,这个位图将被删除,这个原子将不再被跟踪(如果它再次出现,将安装一个新的位图)。
要理解这个过程的开销,我们注意到字典的长度不需要太大。如果一个输出数据包已经列入白名单(特别是它的原子在白名单中),那么,就不需要新的字典记录。对于其它东西来说,我们只需要每个原子有一个记录(尽管同一个原子有许多连接或者有许多与它有关的数据包)。拥有实际上要跟踪的原子,有关的计算就是做字典索引和更新位图所需要的时间。然而,我们在通讯流中发现我们跟踪的原子并不是经常出现(最明显的持续性原子已经在白名单中,因此不需要跟踪)。因此,这个位图中的大多数记录是空的。一个简单的优化方法是使用稀疏向量(sparse vectors)替代位图。在我们的分析中,我们发现在所有的用户遇到的最糟糕的情况中,所有的观察窗口Wmax有1435个需要跟踪的原子。平均的情况是有485个需要跟踪的原子。如果考虑到计算能力和与目前移动系统有关的内存,这个情况几乎是可以忽略的。
我们简单地讨论一下“c-报警是如何通过跟踪通用性产生的”来结束这个讨论。这是一种简单的操作。IT运营中心的中央控制台不断地跟踪不同的用户在最大的观察窗口看到的原子。当收到一个主机的报告的时候,相应的原子就会更新。同时,旧的信息将被删除(也就是说比观察窗口看到的还要老的原子将被删除)。当一个原子记录被更新的时候,相关的用户(最新看到过这个原子的用户)数量超过这个门限值c,于是发出c-报警。一台主机向中央控制台发送报告的频繁程度决定能够在多么短的时间里检测到异常情况。立即发送这个报告(在第一次发现这个原子就发出报告)有助于早一些捕捉到异常情况,但是,这要付出通讯成本。批量更新可减少通讯成本,但是,增加了检测的时间。
至此,我们介绍了目前几个有潜力的防御僵尸网络的策略,主要是收集真正的踪迹以检验常态状况。