Browsertunnel 是一款利用 DNS 协议从浏览器窃取数据的工具。其实现方式是滥用 dns-prefetch 功能——该功能旨在通过后台对指定域名进行 DNS 查找来降低网站的感知延迟。DNS 流量不会出现在浏览器的调试工具中,不会受页面内容安全策略(CSP)的阻止,且通常不会被企业防火墙或代理检查,因此它成为在受限场景中隐蔽传输数据的理想媒介。
这是一项古老的技术——DNS 隧道本身可以追溯到 90 年代,而 Patrick Vananti 在 2016 年就撰文介绍了如何利用 dns-prefetch 实现它,但据我所知,browsertunnel 是首个展示其用途的、开源且可用于生产环境的客户端/服务器工具。由于 dns-prefetch 不会向客户端 JavaScript 返回任何数据,因此通过 browsertunnel 的通信只能是单向的。此外,某些浏览器默认禁用 dns-prefetch,在这些情况下,browsertunnel 将静默失败。
该项目包含两部分:
html/ 文件夹中),用于在客户端编码和发送消息。Browsertunnel 可以通过将字符串编码到子域名中,将任意字符串通过 DNS 发送出去。当浏览器尝试递归解析该域名时,该子域名会被转发到 browsertunnel 服务器。
无法放入单个域名(253 字节)的较长消息会自动拆分为多个查询,由服务器重新组装并解码。
首先,配置 DNS 记录,将一个子域名委派给你的服务器。例如,如果你的服务器 IP 为 192.0.2.123,并且你想通过子域名 t1.example.com 建立隧道,那么你的 DNS 配置应如下所示:
t1 IN NS t1ns.example.com.
t1ns IN A 192.0.2.123
在服务器上,使用 go get 安装 browsertunnel。或者,在你自己的机器上编译 browsertunnel,然后将二进制文件复制到服务器。
go get github.com/veggiedefender/browsertunnel
接下来,运行 browsertunnel,指定要建立隧道的子域名。
browsertunnel t1.example.com
完整用法可通过 browsertunnel -help 查看:
$ browsertunnel -help
Usage of browsertunnel:
-deletionInterval int
seconds in between checks for expired messages (default 5)
-expiration int
seconds an incomplete message is retained before it is deleted (default 60)
-maxMessageSize int
maximum encoded size (in bytes) of a message (default 5000)
-port int
port to run on (default 53)
关于这些参数的更详细描述和设计思路,你还可以参考 godoc。
最后,测试你的隧道!你可以使用我的演示页面 此处,或克隆此仓库并在本地加载 html/index.html。如果一切正常,你应该能看到消息被记录到标准输出中。
对于该项目的实际应用,你可以根据需要 fork 并调整代码。以下是一些思路: