使用 Azure CDN 实现域前置
为了行动的 OPSEC,红队们通过各种手段寻求隐藏他们的 C2 基础设施,否则会被防御方以及威胁猎人所追踪到。这些技术中,使用域前置技术来实现对 C2 服务器的隐藏,是卓有成效以及典型的。在这个小节,我们将学习使用 Azure CDN 实现域前置。
因为复现该小节的操作需要一定的成本,因此更多作为内容扩展,而非靶场的强制需要。
Azure 简介
Azure 是微软自家的云平台,类似于亚马逊 AWS,Google Cloud 等。Azure 有着十分广泛的服务范围,涵盖了计算,网络,存储,数据库,应用,IoT,AI 等领域。
在这些服务中,有诸多可以被红队加以利用的服务,例如 CDN,Function 应用,逻辑应用,API 管理等。并且,几乎所有企业都会使用微软的服务,因此 Azure 一跃成为了红队基础设施供应商 :D
尽管我们在此研究的是 Azure 上可为我们所用搭建安全的 C2 基础设施的服务,在其他云平台上我们也能找到对应的服务。例如 AWS 的 Lambda 与 Azure Function App 高度等同。
域前置理论
在使用 Azure CDN 实现域前置之前,我们需要了解一下域前置的理论与原理。域前置是一种规避互联网审查的技术,它在 HTTPS 连接的不同通信层中使用不同的域名来混淆互联网连接的真实目标。接下来,我们了解域前置技术所涉及的技术术语与过程:
CDN 与云服务提供商:域前置的核心是使用托管各种合法域名的大型 CDN 和云平台。 Azure,AWS,Cloudflare 等流行服务过去都曾被用于域名前置,尽管其中一些服务已经不再支持域前置了。
DNS 解析:当用户想要连接到特定网站时,例如 example.com,域名通过域名系统 DNS 解析为 IP 地址。
Host 头:随着虚拟主机的出现,与不同域名关联的多个网站可以托管在一台主机上,即来自单个 IP 地址。此功能的关键是请求 HOST 头,它指定了目标域名与端口。如下图所示,我们通过指定 HOST 头,可以访问任意被微软托管的网站。
HTTPS 和 SNI:随着 HTTPS 的出现,引入了名称为 SNI 的机制。SNI 允许客户端在 TLS 握手开始时指定要连接到哪个域名。虽然说 TLS 将 HTTP 数据包内容加密了,我们是可以看到数据包的发送终点的。
域前置过程:在域前置中,客户端将向前置域(可信,无害的域名)发出 HTTPS 请求,该域与目标域(黑名单,或被审查的域)托管在同一 CDN 上。然而,尽管 DNS 与 HTTPS 请求中引用的是前置域,但 HOST 头指定目标域。因为 HOST 头在 HTTP 数据包中,属于被加密内容,因此可以实现规避审查的目的。
举个例子,CDN终端 good.azureedge.net 为域名 www.good.com 代理与缓存,同在 Azure 上的 CDN 终端 bad.azureedge.net 为域名 www.bad.com 代理与缓存。其中 www.good.com 是可信的域名,而 www.bad.com 被阻断访问。通过域前置技术突破的过程如下:
客户端通过 DNS 查询 www.good.com,得到 www.good.com 的 CNAME 为 good.azureedge.net
主 DNS 服务器向 Azure 的 DNS 服务器请求,查询 good.azureedge.net 的 IP
客户端得到 good.azureedge.net 的 IP
客户端向 www.good.com 发起 TLS 握手请求,得到证书
通过 HOST 头指定 bad.azureedge.net 域名,访问到 www.bad.com 内容
举个实际例子的话,do.skype.com 可以是前置域,因为其在 Azure 上的 CDN 终端为 skype-do.azureedge.net。
我们可以使用工具 FindFrontableDomains(https://github.com/rvrsh3ll/FindFrontableDomains) 来寻找与验证可用于前置域的域名。
准备工作
我们的 C2 基础设施结构如下所示,受害主机连接到 Azure 云服务,在本小节是 CDN。Azure 云服务充当着转发器/代理的作用,将收到的 Beacon 通信转发至 C2 服务器对外开放的 Nginx 服务器,Nginx 再将 Beacon 通信转发至不可被外部访问的 C2 监听端口。
理解了结构后,我们先在 VPS 上安装必要的组件:
apt-get install nginx apache2 python3-certbot-apache
编辑 Apache 的配置文件,通过以下命令确认端口 80 配置了 VHOST:
apachectl -t -D DUMP_VHOSTS
这里,我已经购买了域名 azuresky.live。使用 certbot 工具申请 LetsEncrypt 证书
certbot certonly -d <域名> --apache --register-unsafely-without-email --agree-to
root@ts:/etc/apache2/sites-available# certbot certonly -d azuresky.live --apache --register-unsafely-without-email --agree-to
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator apache, Installer apache
Obtaining a new certificate
Performing the following challenges:
http-01 challenge for azuresky.live
Waiting for verification...
Cleaning up challenges
IMPORTANT NOTES:
- Congratulations! Your certificate and chain have been saved at:
/etc/letsencrypt/live/azuresky.live/fullchain.pem
Your key file has been saved at:
/etc/letsencrypt/live/azuresky.live/privkey.pem
Your cert will expire on 2023-12-31. To obtain a new or tweaked
version of this certificate in the future, simply run certbot
again. To non-interactively renew *all* of your certificates, run
"certbot renew"
- If you like Certbot, please consider supporting our work by:
Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
Donating to EFF: https://eff.org/donate-le
因为不需要用到 Apache2,可以卸载或者停止运行。编辑 Nginx 配置文件,完成设置监听端口,指定证书与密钥等操作。
使用Azure CDN 实现域前置
Azure CDN 是我们基础设施的核心。要在 Azure 上创建并启用 CDN,首先我们需要创建订阅,并注册 CDN 服务。我们可以在 Azure 页面上点击 Cloud Shell 并执行如下命令实现。
Register-AzResourceProvider -ProviderNamespace Microsoft.Cdn
从 Azure 页面进入 Marketplace,并搜索 Front Door and CDN profiles。
创建一个新的侧写:
在 Offerings 选项中,选择 Explore other offerings 以及 Azure CDN Standard from Edgio。
填写相关信息,订阅选择刚刚创建的 pay-as-you-go,以及对应的资源组。CDN 终端名称决定了我们的子域名,Origin type 选择 Custom Origin,Origin hostname 填写我们的 C2 服务器域名,Query string caching behavior 选择 Bypass caching for query strings。
检查并提交
创建好后,进入 Caching rules 设置,将 Query string caching behavior 选择 Bypass caching for query strings。
截获微软应用的请求,或使用之前提到的工具,我们可以得到以下这些(以及更多)可作为前置域的微软域名,我们可以把这些域名一并加入主机池里。通过将 Host 头设置为 CDN 终端,我们最终可以实现隐藏 C2 服务器。
ajax.microsoft.com
ajax.aspnetcdn.com
do.skype.com
msdn.microsoft.com
az416426.vo.msecnd.net
officeimg.vo.msecnd.net
编辑域名的 DNS 配置,往往在域名平台管理后台里设置。
等待一段时间的传播后,当我们查询购买的域名的 www 子域名时,我们发现返回的是 CDN 终端的 IP 了。
编辑 /etc/nginx/nginx.cnf 文件,增加侧写中的 URI,以及设置基于 UA 的请求过滤:
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name localhost;
#proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
ssl_certificate /etc/letsencrypt/live/azuresky.live/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/azuresky.live/privkey.pem;
location ~ ^/(index.html|content.php|api/azure|static/index.html|jquery-3.3.1.slim.min.js|jquery-3.3.2.slim.min.js|jquery-3.3.1.min.js|jquery-3.3.2.min.js) {
if ($http_user_agent != "dlerinfra") {
return 403;
}
proxy_pass https://localhost:10443;
}
}
}
生成 exe 载荷,执行,我们能成功执行命令并获得输出。使用工具 ProcessHacker 查看 Beacon 的网络通信,我们发现 Beacon 与 152.199.4.33,72.21.81.200,13.107.213.36,72.21.81.200 等 IP 通信。
实际上,这些 IP 都是我们之前发现的支持域前置的微软域名,即 Beacon 通信流量不会直接流向 C2 服务器。这样,我们实现了对 C2 服务器的隐藏。