基于 TLS 1.3 的域前置。 第2部分

介绍

在第一部分 文章 我们已经简要描述了加密SNI(eSNI)机制。 他们展示了如何基于此机制逃避现代 DPI 系统的检测(以 Beeline DPI 和被禁止的 RKN 根跟踪器为例),并探索了基于该机制的新版本的域前置。

在本文的第二部分中,我们将继续讨论更实际的事情,这些事情对于红队专家的艰巨工作将是有用的。 最后,我们的目标不是访问被阻止的资源(对于这些琐碎的事情,我们有很好的旧VPN)。 幸运的是,正如他们所说,VPN 提供商种类繁多,可以满足各种品味、肤色和预算。

我们将尝试将域前置机制应用于现代 RedTeam 工具,例如 Cobalt Strike、Empire 等,并赋予它们额外的功能来模仿和逃避现代内容过滤系统。

上次我们将 eSNI 机制实现到 OpenSSL 库中,并在熟悉的 curl 实用程序中成功使用它。 但是,正如他们所说,你不会只满足于一只鸡。 当然,我想用高级语言实现类似的东西。 但不幸的是,在互联网上的快速搜索让我们失望了,因为对 eSNI 机制的支持仅在 GOLANG 中完全实现。 因此,我们没有太多选择:要么使用修补后的 OpenSSL 库用纯 C 或 C++ 编写,要么使用 CloudFlare 中的单独 GOLANG 分支并尝试将我们的工具移植到那里。 原则上,还有另一种选择,更经典,但同时也很耗时 - 实现对 Python 的 eSNI 支持。 毕竟,Python 也使用 OpenSSL 来处理 https。 但我们会将这个选项留给其他人开发,我们自己也会对 Golang 中的实现感到满意,特别是因为我们心爱的 Cobalt Strike 完全能够与第三方工具构建的通信通道(外部 C2 通道)配合使用- 我们将在文章末尾讨论这个问题。

更加努力...

Go 中实现的工具之一是我们为转向网络而开发的工具 - 隧道器 鲁索克斯顿顺便说一句,它现在被 Microsoft 和 Symantec 的工具检测为旨在破坏全球稳定的恶意软件......

基于 TLS 1.3 的域前置。 第2部分

在这种情况下使用以前的开发也很棒。 但这里出现了一个小问题。 事实上,最初 rsockstun 意味着使用与服务器的同步 SSL 通信通道。 这意味着连接建立一次并在隧道运行的整个持续时间内存在。 而且,正如您所了解的,https 协议不适用于这种操作模式 - 它以请求-响应模式工作,其中每个新的 http 请求都存在于新的 TCP 连接中。

该方案的主要缺点是,在客户端发送新的http请求之前,服务器无法向客户端传输数据。 但是,幸运的是,有很多选择可以解决这个问题 - 通过 http 协议流式传输数据(毕竟,我们设法通过 https 上运行的门户观看我们喜爱的电视节目并听音乐,但传输视频和音频只不过是比流数据)。 WebSockets 技术是通过 HTTP 协议模拟成熟 TCP 连接操作的技术之一,其主要本质是在客户端和 Web 服务器之间组织成熟的网络连接。

对我们来说幸运的是(万岁!!!),该技术默认包含在所有 CloudFlare 资费计划中,并且与 eSNI 结合使用效果很好。 这正是我们将用来教我们的隧道程序使用域前置并隐藏现代 DPI 的方法。

关于 WebSocket 的一些知识

首先,我们将简要解释一下 websocket,以便每个人都了解我们将要使用的内容。

Websocket 技术允许您临时从 http 连接切换到标准网络套接字流,而无需中断已建立的 TCP 连接。 当客户端想要切换到 websocket 时,它会在其 http 请求中设置多个 http 标头。 两个必需的标头 - 连接:升级 и 升级:websocket。 他还可以强制指定websocket协议版本(Sec-Websockset-版本:13)和类似 base64 websocket 标识符的东西(Sec-WebSocket-密钥:DAGDJSiREI3+KjDfwxm1FA==)。 服务器用 http 代码 101 Switching Protocols 响应他,并设置标头 连接、升级 и Sec-WebSocket-接受。 下面的截图清楚地展示了切换过程:

基于 TLS 1.3 的域前置。 第2部分

至此,WebSocket连接的安装才算完成。 现在,来自客户端和服务器的任何数据都将不再通过 http 提供,而是通过 WebSocket 标头提供(它们以字节 0x82 开头)。 现在服务器不需要等待客户端的请求来传输数据,因为tcp 连接没有断开。

Golang 有几个用于使用 websocket 的库。 其中最受欢迎的是 大猩猩 WebSocket 和标准 WebSocket的。 我们将使用后者,因为...... 它更简单、更小,而且正如他们所说,工作速度更快一些。

在 rsockstun 客户端代码中,我们需要将 net.dial 或 tls.dial 调用替换为相应的 WebSocket 调用:

基于 TLS 1.3 的域前置。 第2部分

基于 TLS 1.3 的域前置。 第2部分

我们希望使隧道的客户端部分变得通用,并且能够通过直接 SSL 连接和 WebSockset 协议工作。 为此,我们将创建一个单独的函数 func connectForWsSocks(地址字符串,代理字符串)错误{…} 用类比来 connectForSocks() 如果启动客户端时指定的服务器地址以 ws: 或 wss: 开头(在安全 WebSocket 的情况下),我们将使用它来处理 Web 套接字。

对于隧道的服务器端,我们还将创建一个单独的函数来使用 Web 套接字。 它将创建 http 类的实例并设置 http 连接处理程序(wsHandler 函数):

基于 TLS 1.3 的域前置。 第2部分

我们将把所有连接处理逻辑(使用密码的客户端授权、设置和结束 yamux 会话)放在 WebSocket 连接处理程序中:

基于 TLS 1.3 的域前置。 第2部分

我们编译项目并启动服务器部分:

./rsockstun –listen ws:127.0.0.1:8080 –pass P@ssw0rd

然后是客户端部分:

./rsockstun -connect ws:127.0.0.1:8080 –pass P@ssw0rd

我们检查本地主机上的工作:

基于 TLS 1.3 的域前置。 第2部分

基于 TLS 1.3 的域前置。 第2部分

让我们继续讨论域名前置

我们似乎已经找到了 websocket。 现在让我们直接转向 eSNI 和域前端。 如前所述,为了与 DoH 和 eSNI 合作,我们需要从公司获取一个特殊的 golang 分支 CloudFlare的。 我们需要一个支持 eSNI 的分支 (pwu/esni)。

我们将其克隆到本地或下载并解压相应的zip:

git clone -b pwu/esni https://github.com/cloudflare/tls-tris.git

然后我们需要复制GOROOT目录,替换克隆分支中的相应文件并将其设置为master。 为了让开发人员免于这个头痛,CloudFlare 的人准备了一个特殊的脚本 - _dev/go.sh。 我们刚刚启动它。 脚本和 makefile 将自行完成所有工作。 只是为了好玩,您可以查看 makefile 来了解详细信息。

运行脚本后,在编译项目时,我们需要将脚本准备的本地目录指定为GOROOT。 在我们的例子中,它看起来像这样:

GOROOT="/opt/tls-tris/_dev/GOROOT/linux_amd64" go build ….

接下来,我们需要在隧道中实现请求和解析所需域的公共 eSNI 密钥的功能。 在我们的例子中,这些将是来自 CloudFlare 前端服务器的公共 eSNI 密钥。 为此,我们将创建三个函数:

func makeDoTQuery(dnsName string) ([]byte, error)
func parseTXTResponse(buf []byte, wantName string) (string, error)
func QueryESNIKeysForHost(hostname string) ([]byte, error)

原则上,函数的名称不言而喻。 我们将从 esni_query.go 文件中获取内容,该文件是 tls-tris 的一部分。 第一个函数使用 DoH (DNS-over-HTTPS) 协议创建一个网络数据包,向 CloudFlare DNS 服务器发出请求,第二个函数解析查询结果并获取域的公钥值,第三个函数是前两个的容器。

接下来,我们向新创建的函数添加一个 Web 套接字连接 connectForWsSocks 为域请求 eSNI 密钥的功能。 在服务器部分运行的地方,我们设置 TLS 参数,并设置假“覆盖域”的名称:

基于 TLS 1.3 的域前置。 第2部分

这里需要注意的是,最初,tls-tris 分支并不是为使用域前置而设计的。 因此,它不会注意假服务器名称(空的 serverName 字段作为 client-hello 数据包的一部分发送)。 为了解决这个问题,我们必须将相应的 FakeServerName 字段添加到 TlsConfig 结构中。 我们不能使用该结构的标准 ServerName 字段,因为它由内部 tls 机制使用,如果它与原始的不同,则 tls 握手将以错误结束。 文件中包含 TlsConfig 结构的描述 tls/common.go - 我们必须修复它:

基于 TLS 1.3 的域前置。 第2部分

基于 TLS 1.3 的域前置。 第2部分

此外,我们还必须对文件进行更改 tls/handshake_client.go在形成 TLS 握手时使用我们的 FakeServerName 字段:

基于 TLS 1.3 的域前置。 第2部分

就这样! 您可以编译项目并检查工作。 但在运行扫描之前,您需要设置一个 CloudFlare 帐户。 好吧,我该怎么说设置它 - 只需在 cloudflare 上创建一个帐户并将您的域链接到它即可。 默认情况下,与 DoH、WebSocket 和 ESNI 相关的所有功能都包含在 CloudFlare 中。 DNS记录更新后,您可以通过查询eSNI密钥来检查域的运行情况:

dig +short txt _esni.df13tester.info 

基于 TLS 1.3 的域前置。 第2部分

如果您看到与您的域类似的内容,则意味着一切正常,您可以继续进行测试。

我们启动 Ubuntu 例如,DigitalOcean 上的 VPS。附注:我们遇到的情况是,刚从服务商那里拿到的 VPS IP 地址被 Roskomnadzor 列入了黑名单。所以,如果类似情况发生在你身上,也不要感到惊讶。我不得不使用 VPN 才能访问我的 VPS。

我们将已经编译好的 rsockstun 复制到 VPS(顺便说一句,这是 Golang 的另一个优点 - 您可以自己编译该项目并在任何 Linux 上运行它,仅观察系统的位容量)并启动服务器部分:

基于 TLS 1.3 的域前置。 第2部分

然后是客户端部分:

基于 TLS 1.3 的域前置。 第2部分

我们可以看到,客户端使用 websocket 通过 CloudFlare 前端服务器成功连接到服务器。 要检查隧道是否像隧道一样工作,可以通过本地socks5发出curl请求,在服务器上打开:

基于 TLS 1.3 的域前置。 第2部分

现在让我们看看 DPI 在通信通道中看到了什么:

基于 TLS 1.3 的域前置。 第2部分

首先,隧道器使用 DoH 机制联系 Cloudflare DNS 服务器以获取目标域的 eSNI 密钥(数据包编号 1-19),然后联系前端服务器并建立 TLS 连接,隐藏在域后面 www.google.com (当客户端启动时没有指定假域名时,这是默认值)。 要指定您的假域名,您必须使用 -fronfDomain 参数:

基于 TLS 1.3 的域前置。 第2部分

基于 TLS 1.3 的域前置。 第2部分

现在还有一件事。 默认情况下,CloudFalre 帐户设置设置为灵活 SSL。 这意味着从客户端到 Cloudflare 前端服务器的 https 请求将未加密 (http) 转发到我们的服务器。 这就是为什么我们以非 ssl 模式 (-listen ws:0.0.0.0) 启动隧道的服务器部分,而不是 (-listen wss:0.0.0.0)。

基于 TLS 1.3 的域前置。 第2部分

为了切换到完全加密模式,您必须选择 完整(严格) 服务器上是否有真实的证书。 切换模式后,我们将能够使用 https 协议接受来自 CloudFlare 的连接。 不要忘记为隧道的服务器端生成自签名证书。

基于 TLS 1.3 的域前置。 第2部分

好奇的读者会问:“那么客户呢?” Windows“毕竟,隧道器的主要用途可能是从企业机器和服务器建立后端连接,而这些机器和服务器通常都是 Windows 系统。我该如何为 Windows 编译隧道器,尤其是使用特定的 TLS 协议栈?” 现在我们将介绍 Golang 的另一个特性,它能充分展现 Golang 的便捷性。我们只需在 Kali Linux 中添加 `GOOS=windows` 参数,即可直接为 Windows 编译:

GOARCH=amd64 GOROOT="/opt/tls-tris/_dev/GOROOT/linux_amd64" GOOS=windows  go build -ldflags="-s -w"

或者 32 位版本:

GOARCH=386 GOROOT="/opt/tls-tris/_dev/GOROOT/linux_amd64" GOOS=windows  go build -ldflags="-s -w"

全部! 并且不需要更多的麻烦。 真的行!

基于 TLS 1.3 的域前置。 第2部分

需要 -w 和 -s 编译器标志来从可执行文件中删除不必要的垃圾,使其小几兆字节。 此外,还可以使用 UPX 对其进行封装,以进一步减小尺寸。

取而代之的是结论

在本文中,我们使用用 Golang 编写的隧道示例,清楚地演示了新的域前置技术的使用,该技术是在 TLS 1.3 协议的一个相当有趣的功能上实现的。 以类似的方式,您可以调整用 Golang 编写的现有工具以通过 CloudFlare 服务器工作,例如 Merlin - 著名的 C2,或强制 CobaltStrike Beacon 在与 Teamserver 一起使用时使用 eSNI 域前端 外部C2通道,在 Golang 中实现,或者使用 OpenSSL 的修补版本在标准 C++ 中实现,我们在文章的最后部分讨论了这一点。 一般来说,想象力是没有限制的。

隧道器和 CloudFlare 的示例以概念的形式呈现,仍然很难说这种类型的域前端的长期前景。 目前,只有 CloudFlare 支持 eSNI,理论上,没有什么可以阻止他们禁用这种前端,例如,如果 SNI 和 eSNI 不匹配,则中断 tls 连接。 总的来说,未来会告诉我们答案。 但就目前而言,在“kremlin.ru”的掩护下工作的前景看起来相当诱人。 是不是?

更新后的隧道程序代码以及编译后的可执行 exe 文件位于该项目的单独分支中 github上。 最好在 GitHub 的项目页面上写一个有关所有可能的隧道器问题的问题。

来源: habr.com

为具有 DDoS 保护、VPS VDS 服务器的站点购买可靠的主机 🔥 购买具备 DDoS 防护的可靠网站托管服务,包括 VPS 和 VDS 服务器 | ProHoster