暗度陈仓:基于国内某云的 Domain Fronting 技术实践

 

一、简介

Domain Fronting,中文译名 “域前置” 或 “域名前置”,是一种用于隐藏真实C2服务器IP且同时能伪装为与高信誉域名通信的技术,多用于木马受控端和控制端之间的隐蔽通信。

简言之,利用该技术,可以让受控端以为程序是在和一个高信誉域名通信,但实际上却是在和我们的C2服务器进行通信,效果如下:

全球著名的俄罗斯军方黑客组织 APT29 也曾被披露使用这项技术来逃避IDS的审查。

Domain Fronting 的技术原理图如下,在下面的 “原理” 一节中我们会详细解释该技术。

在这篇文章中,我们将基于国内某云来实践该技术,为什么说某云,而不指名道姓说出来?因为该厂商云的 CDN 有一个非常有意思的特性(下面会讲解),可很好的辅助我们进行红队测试,但知道这点的人不多,所以,到底是哪个云厂商,就交由各位凭借自身的信息检索和情报提取能力来判断了,在文章中会出现相关线索。但需要注意的是,除去这一特性后,本篇文章依然在所有云上通用。

二、原理

Domain Fronting 的核心技术是 CDN,所以我们先来了解下 CDN 的工作机制。

一般情况下,1台 CDN 会同时负责多个网站的加速服务,那问题来了:如果我访问的两个网站(a.com 和 b.com)都是由同1台 CDN 服务器(1.1.1.1)进行加速服务,那么当我使用浏览器访问这两个域名时,浏览器实际上访问的都是 1.1.1.1 这台 CDN 服务器,但我在浏览器访问的域名有可能是 a.com 也可能是 b.com,所以 1.1.1.1 这台 CDN 服务器必须清楚地知道我访问的是哪个域名,然后才能给我返回对应域名的内容,那 CDN 是如何知道我访问的是哪个域名呢?

答案就是在和 CDN 服务器通信时,在 HTTP 请求包的 Host 头中填入我们要访问的域名。

下面以1个真实例子进行讲解。

这里对两个网站执行 nslookup,可以发现它们使用的都是同样的一批 CDN 服务器。

对 klst.96jm.com 进行请求,返回的状态码为 301,

对 www.shhorse.com.cn 进行请求,返回的状态码为 302,

然后对它们其中共同的一台 CDN 服务器进行请求,并且设置 Host 头为 www.shhorse.com.cn,

可以发现,返回的结果和我们请求 www.shhorse.com.cn 时返回的结果一模一样,这说明我们依然成功请求到了 www.shhorse.com.cn,虽然我们请求的主机是 CDN 服务器。

由此可见,即使直接请求 CDN,只要 Host 头中带有想要访问的域名,CDN 就能知道你想和哪个域名通信,进而就能让你和指定的域名互相传送内容。

又由于我们访问 klst.96jm.com 时实际上访问的也是 125.94.49.222 这台CDN服务器,所以下面这样也是可行的,

可以看到,效果和上面直接请求 CDN 服务器一样,依然成功访问到了 www.shhorse.com.cn 这个域名下,而非表面上访问的 klst.96jm.com。

以上就是技术原理,只不过在 Domain Fronting 实战中,Host 头一般被设置为高信誉的域名(或者我们自己申请的 “形似” 高信誉域名的域名)。

另外,我们也可以知道,因为 CDN 的存在,我们访问网站时访问的实际上只是 CDN,而不是直接和网站的真实服务器进行通信,所以利用 CDN 的同时也可以隐藏我们真实C2服务器的 IP。

 

三、实践

了解原理后,我们通过 Cobalt Strike 来实践 Domain Fronting,这里笔者使用的 Cobalt Strike 版本为 3.14,服务器系统为 Ubuntu 16.04 x64。

正常情况下,第一步我们要做的是先申请一个域名(这个域名的作用是用来配合 CDN 来隐藏我们的C2服务器),然后再申请一个CDN对我们的所申请的域名进行加速,在这个过程中CDN会要求我们在域名的解析配置中设置相应的 CNAME。

但由于某云有一个有趣的特点:当 CDN 配置中的源 IP 为自己云的服务器时,加速时会跳过对域名的检验,直接与配置中的域名绑定的源服务器IP进行通信。利用该特性,我们不需要真正去申请 CDN 时所填写的域名中配置解析相应的 CNAME 了。换言之,只要我们的C2服务器属于该云的服务器,那么我们就无需申请域名,只需要在申请 CDN 时随便填一个没有人绑定过的域名就好了,而且这个域名我们可以填成任何高信誉的域名,例如 test.microsoft.com、oops.microsoft.com…

接下来我们直接去申请 CDN 即可,这里笔者把域名填为 fuck.microsoft.com。

(红色涂抹处填成你在该云C2服务器的公网IP)

点击下一步申请完成,一开始申请状态为这样:

等几分钟,就可以了,

CDN 申请完成后,就可以开始编辑 Cobalt Strike 要用到的 C2 Profile 文件了,我们直接使用开源项目 Malleable-C2-Profiles 中的 amazon.profile,但需要把其中的 Host 头改成我们自己在 CDN 中绑定的域名,如图:

(文件链接:amazon.profile

修改成自己的域名后,在服务器上启动 teamserver,别忘记加上配置文件的选项,

(注意:这里在命令前加了个 nohup 指令,这是为了在关闭这个 Shell 后,teamserver 依然能继续运行,如果没加上 nohup 的话,在关闭这个 ssh shell 后,本次会话中启动的所有程序都将随着 shell 的关闭一起终止)

然后关闭系统自带的防火墙,让外部能访问进来。笔者使用的是 Ubuntu 16.04,所以执行 ufw disable 就把防火墙关掉了,读者可根据自己的系统来执行相应操作关闭防火墙。

需要注意的是,除了系统自带的防火墙外,部分云服务器的实例中仍带有额外的防火墙规则,如果系统防火墙都关掉了还是访问不到相关端口,那么十有八九就是这玩意在作怪。这里笔者的云服务器就有这功能,我直接添加了本次实践要配置的入站规则(即允许了 50050 和 80 端口),

然后我们打开 Cobalt Strike 的 web日志 视图,在 cmd 中用 curl 执行以下操作(域名换成你自己的,原理在第一节已经讲过):

然后如果在 Cobalt Strike 的 web日志 中能看到对应请求信息,则说明配置成功:

上面都搞好后,就可以在 Cobalt Strike 中开搞了,首先创建一个 Listener,

申请 CDN 时绑定的是 80 端口,所以此处的端口也填 80,主机则填申请 CDN 时所绑定的域名,点击 Save 后会让弹出一个框,让我们填一个 beacon 通信的地址,我们直接填上该云任意一个CDN服务器的地址即可,

创建完成后如图所示:

Listener创建完成后,就可以开始创建 Agent 了,但由于使用了 Domain Fronting 技术,Cobalt Strike 默认生成的 Agent 会崩溃,因此我们需要一个针对 Domain Fronting 技术进行定制化的 Agent Generator,这个已经有人写好了:CACTUSTORCH

把整个项目下载下来,解压到任意目录,然后在 Cobalt Strike 中打开脚本管理器,点击Load,找到刚刚下载的项目中的 cna 文件,点击OK,整个项目的脚本就成功加载到 Cobalt Strike 中了,

加载成功后,我们找到 “攻击” 菜单,可以发现最后多出了1个选项,这就是我们需要的 Agent Generator,

点击该选项,即可生成 Agent,

这里我生成 HTA 类型的 Agent,红色涂抹处填写你的C2服务器公网IP,Listener 选择之前创建的 HTTP-DF-C2,点击开始即可得到 payload的 下载地址,

然后我们在目标主机上执行该 Payload,同时打开 Wireshark 进行抓包,

可以发现,已经成功伪装成我们的高信誉域名。同时,Cobalt Strike 中也可以看到目标主机已经成功上线,

另外,我们在目标主机使用 Wireshark 过滤与真实C2服务器的通信,可以发现没有任何与真实主机的通信,至此,说明我们成功实现了 Domain Fronting 技术。

 

四、总结

总结下来,实施 Domain Fronting 大致分为以下几步:

1. 申请域名

2. 申请CDN,加速上一步申请的域名

3. 使用 curl 加上 Host 头访问CDN,测试是否成功

4. 编辑好 C2 Profile 文件,作为 teamserver 中的一个选项运行之

5. 使用特制的 Agent Generator 生成 Payload

6. 在目标主机中运行 Payload

可以发现,利用 Domain Fronting 技术,在目标主机上只能看到系统是在和一个高信誉域名通信,并且不会产生任何与我们真实C2服务器的直接通信流量,伪装的同时还极佳地隐藏了我们的C2服务器,利用此技术,我们可以有效地躲避各种IDS,实施红队测试。

(完)