3.5 C&C服务器

随着恶意木马产业的发展,后门也摆脱了过去“单打独斗”的作战方式,进化为通过指挥大量受到感染的计算机共同行动的模式,形成了规模效应,本节将带领读者了解C&C的原理、如何用Go语言开发一个C&C服务器,以及如何防御。
3.5.1 什么是C&C服务器
C&C服务器的全称是Command and Control Server,即命令与控制服务器,被控制的服务器可以接收控制端的命令,常被用于僵尸网络中,控制端统一对被控制端下发命令。
C&C的实现非常灵活,只要能实现被控制端可以获取控制端命令的功能即可,可以使用任何协议实现,常见的实现方式如下。
● HTTP/HTTPS实现的C&C。
● 社交平台,如将命令写在微博、论坛中,被控制端通过访问特定的URL获取黑客的命令。
本节将以HTTP/HTTPS来讲述如何实现一个C&C服务器。
3.5.2 HTTP/HTTPS的C&C服务器的架构
HTTP/HTTPS的C&C服务器分为控制端Server与被控制端Client。
● Server为一个Web服务,可以接收被控制端的机器信息、向被控制端发送命令,以及接收被控制端发回的命令执行结果。Server端的项目的代码结构如图3-11所示。

●图3-11 C&C服务器控制端代码结构
● Agent为一个HTTP Client,功能为向控制端发送Agent的状态,获取Server下发的命令及提交命令执行结果。被控制端的代码结构如图3-12所示。

●图3-12 C&C服务器被控制端代码结构
3.5.3 C&C服务器被控制端
C&C服务器的被控制端又称为C&C Agent,功能如下。
● 定时向控制端上报状态。
● 定时从控制端获取命令。
● 命令执行结果返回给控制端。
在正式开发Agent前,需要先定义Agent的数据结构,用来描述客户端对象的属性,如http.client对象、协议、UUID、客户端平台、用户名与组名,以及控制端的URL等字段,详细的struct的定义如下:


被控制端与控制端之间的通信数据为JSON,也需要定义一个结构用来进行JSON的序列化与反序列化,详细的定义如下所示:

1.C&C Agent初始化
前面已经定义了Agent的数据结构,需要再定义一个NewAgent函数在被控制端启动时初始化Agent对象的属性,并返回一个Agent对象,代码如下所示:



2.C&C Agent与Server端通信的实现
需要给Agent对象再加一个ParseInfo方法,用来从Agent对象中解析出需要向控制端上报的数据,代码如下所示:

Agent需要定时向控制端上报状态,这里定义了一个Ping函数,用来实现Agent向控制端上报信息的功能,将Agent的数据struct转化为JSON,然后用HTTP Client对象以POST方式提交到控制端的/ping接口中即可,代码如下所示:


for range time.Tick是Go语言的一个机制,表示以固定时间间隔执行其中的代码,代码中的for range beat的作用是每10s执行一次被控制端信息上报操作。
3.获取控制端的命令
与信息上报功能类似,被控制端也会以固定的时间间隔从控制端获取命令,如果检测到控制端下发了命令,就会调用exec/command库执行命令,并将命令的执行结果再提交给控制端,获取命令并返回命令执行结果的代码如下所示:

执行命令的功能与前面的Webshell中的类似,都是用标准库的exec包来执行命令,代码片断如下所示:

命令命令结果是以post form的方式返回给控制端的,urlCmd为控制端接收命令执行结果的接口,完整代码如下所示:

最后在main函数加入定时上报被控制端信息、定时接收命令并返回的功能的函数就完成了一个简单的C&C服务器被控制端的开发,main函数的代码如下所示:

3.5.4 C&C服务器控制端
C&C服务器控制端的作用是向被控制端下发命令及接收被控制端命令的执行结果。这里提供了两个版本的被控制端,为了方便演示,第一个版本采用的是HTTP,第二个版本是一个HTTP2服务器,采用HTTPS通信,防止被NIDS检测到通信的内容。
控制端会启动一个Web服务器并提供以下3个接口。
● /ping,接收被控制端发送的本地服务器信息并存入数据库(被控制端上线列表)。
● /cmd/:uuid,被控制端会定时从这个接口获取需要执行的命令。
● /send_result/:id,被控制端执行下发的命令后会将执行结果提交到这个接口中。
控制端除了与被控制端通信外,还需要提供控制者下发命令的功能。这里给出了两种下发命令的方式。
● 命令行方式。
● 交互式shell方式。
1.控制端的接口开发
控制端的接口是用Go语言的一个名为gin的Web框架开发的,也可以选择其他Web框架,如Echo、Beego,或直接用Go标准库的net/http包进行开发。
以下代码的作用是创建一个默认的∗gin.Engine对象,并为其设置了3个接口的路由。

(1)被控制端信息上报接口的实现
routers.Ping是/ping接口的处理函数,作用是将被控制端上报的JSON数据解析为struct,然后根据被控制端的UUID判断是否存入数据库,如果是新的被控制端则存入数据库,如果是已经存在的被控制端,则更新最后的上线时间等信息。以下为Ping处理器的具体实现代码:


控制端的数据库操作使用的是xorm包,这个ORM框架还支持MySQL等其他常用的数据库,为了减少控制端对部署环境的依赖,这里使用了轻量级的数据库SQLite3,以下为建库、建表的详细代码:

关于xorm的详细使用方法可以参考其手册https://xorm.io/。
(2)下发命令接口的实现
routers.GetCommand是控制端下发命令的接口/cmd/:uuid的具体实现,它的作用是通过Agent的UUID查询该Agent需要执行的命令列表,然后以JSON的形式返回给Agent。为了防止被人恶意利用,这里提供的演示程序只支持对指定的Agent下发命令。

models.ListCommandByAgentId的作用是通过Agent的UUID查询命令列表,代码如下所示:

status=0表示尚未执行的命令,Agent执行完命令将结果上报回来后,控制端会将其status置为1,表示已经执行完毕。
(3)命令执行结果接收接口的实现
routers.send_result是被控制端向控制端上报命令执行结果的接口/send_result/:id的具体实现,command的数据结构定义如下:

命令执行完毕后,只要将command记录中的result字段更新为命令执行结果即可,详细的代码如下所示:

2.控制端交互模块的开发
控制端与被控制端的交互功能完成之后,还需要开发操作者与控制端的交互功能,操作者通过控制端来给被控制端下发一系列的命令,被控制端执行命令后再将结果返回给控制端。控制端与操作者的交互操作如下。
● 查看Agent上线列表。
● 下发命令。
● 实时返回命令的执行者。
操作者与控制端的交互是通过数据库进行的,详情如下。
● 被控制端上报的Agent信息供操作者查看,list命令可以列出所有上线的Agent列表。
● 操作者使用run agent_ id cmd命令下发的命令会保存到数据库中,然后供被控制端通过HTTP接口拉取。
● 操作者用cmd命令可以查看所有下发的命令。
假设交互式shell的样例如下所示:

以上的list、run与cmd命令的底层为相应的数据库操作,这3个命令的数据库操作的实现如下:

3.交互式控制台的实现
交互式shell的实现使用了一个Go语言的第三方包gopkg.in/abiosoft/ishell.v2,使用此包可以很方便地实现交互式控制台程序的开发。
官方提供了一个示例,作用是提供一个交互控制台,输入greet xxx命令后会在控制台中显示hello xxx,示例代码如下:


shell对象的AddCmd方法表示新增一个交互式命令,传入的参数为一个Cmd结构体,可以指定命令的名称、help说明、执行函数、命令参数自动完成的函数及子命令,Cmd结构体的定义如下所示:

以下为cmd agent_id的命令的实现,其他命令的实现大同小异,为了节约篇幅,这里不一一列出了。参数自动补全功能只需把可选的参数以[]string返回即可,代码如下所示:


4.实时展示命令执行结果
控制端下发的命令执行成功后,被控制端会提交回来并存入数据库,需要实时地向操作者展示命令的执行结果。以下代码的作用是每隔两秒检测一次是否有执行结果返回,然后展示在操作者的控制台上。

ListCmdResult需要与交互式shell并行运行,前面加go以协程的方式启动即可。

DisplayCmdResult的作用是以table的格式向操作者的控制台展示结果,这里使用了Go的第三方包github.com/olekukonko/tablewriter,详细的代码如下:

● table.SetHeader的作用是设置表头。
● table.SetAlignment的作用是设置内容的对齐方向。
● table.AppendBulk(data)用来填充具体的数据,传入的参数为一个[][]string。
table对象的格式及内容填充完成后,用table.Render()就可以渲染并输出到命令行了。
3.5.5 C&C服务器测试与防御
C&C服务器开发完后,接下来测试C&C服务器的接口服务、被控制端与控制端的实际效果。
最终的服务器端的命令行参数如下:

● remove_agent表示根据UUID移除一个Agent。
● list_agent表示列出所有Agent。
● list_cmd表示根据UUID查询某个Agent执行过的历史命令。
● run command用来对命令的UUID的Agent下发命令。
● serv表示启动C&C服务器的接口服务。
● shell表示启动交互式控制台。
C&C服务器的测试步骤如下。
1)首先用serv命令启动C&C服务器的接口服务,如图3-13所示。

●图3-13 C&C服务器接口服务启动效果
2)接下来启动C&C服务器的被控制端,也就是Agent,直接启动即可,如图3-14所示。

●图3-14 C&C服务器被控制端启动效果
3)进入控制端的交互式shell就可以以交互的方式操作Agent了,如用run可以下发命令,用cmd可以查看历史命令,list可以列出Agent列表,用remove可以删除一个Agent,如图3-15所示。

●图3-15 C&C服务器交互式控制端测试效果
C&C服务器的种类繁多,这里只讲解本节实现的C&C服务器示例的防御方法。
● 平时加强基础设施的安全建设与安全运营,尽量让攻击者无可趁之机。
● 部署HIDS、NIDS、WAF等安全产品,以便第一时间发现被植入C&C服务器并进行快速的应急响应。
3.5.6 用HTTP2加密C&C的通信
前面已经实现了一个简单的C&C服务器的控制端与被控制端,但通信协议使用的是HTTP,容易被NIDS等流量分析的安全产品识别出来,攻击者为了躲避安全产品的检测可能会将协议改为HTTP2实现HTTPS加密传输。修改方法为分别对控制端与被控制端的协议进行修改。将之前的gin的HTTP启动方式改为以HTTP2启动,代码如下所示:

r.RunTLS的第一个参数为HTTP2服务启动的地址,后两个参数分别为HTTPS证书的公钥与私钥,生成步骤如下。
1)确保安装了OpenSSL。
2)生成私钥。

3)生成公钥。
