如何通过 DNS 重绑定窃取你的以太坊

2019-04-04 约 2133 字 预计阅读 5 分钟

声明:本文 【如何通过 DNS 重绑定窃取你的以太坊】 由作者 Saferman 于 2019-03-05 08:38:00 首发 先知社区 曾经 浏览数 711 次

感谢 Saferman 的辛苦付出!

翻译原文:https://blog.hacker.af/how-your-ethereum-can-be-stolen-using-dns-rebinding

随着 Tavis Ormandy 发现本地主机上利用未经身份验证的 JSON-RPC 服务的讨论兴起,我想到的第一件事就是以太坊客户端(Geth,Mist 和 Parity)。

大多数以太坊客户端在 localhost 上的端口 8545 上运行 JSON-RPC 服务,但由于它位于 localhost 上,因此我们无法直接从用户的浏览器访问它。电子钱包中的这个问题利用 CORS 标头通过 localhost 上的 JSON-RPC 控制用户的电子钱包。

Geth 的 JSON-RPC 看起来非常安全,因为它没有返回任何 CORS 头部,但随后 cpacia 在电子钱包的半补丁上发表了评论,这引起了我的兴趣。这是他具体评论的内容:

Just disabling CORS is still vulnerable to a DNS rebinding attack. It needs to be authenticated. ~ cpacia

我听说过 DNS 重新绑定但从未尝试深入研究过它。由于 Geth 的 JSON-RPC 也未经过身份验证,它也可能存在 DNS 重绑定攻击。

这里是 DNS 重绑定的基本定义: https://en.wikipedia.org/wiki/DNS_rebinding

我开始研究 DNS 重绑定,但所有文章都非常古老。然后我在 Bug Bounty 论坛上询问了这个问题,Luke Young 将他在 Defcon 会议上关于现今 DNS 重绑定利用的 演讲链接 发给了我。它包括一个自动化工具,可以在大多数现代浏览器上实现 DNS 重新绑定。

但是我有一颗非常好奇的心,我不想使用任何预先制作的工具,所以我开始编写自己的 DNS 服务器。Python 有一个非常好的库,名为 dnslib,它为我处理了大部分的 DNS 底层的内容。我注册了一个域名,设置了一些指向我的服务器的记录,并将它们用作名称服务器。

我想看看不同的浏览器如何在 TTL 很小的情况下做出响应的,所以我让我的 DNS 服务器返回 TTL <5。即使 TTL 小于 5,Chrome,Firefox 和 Safari 也缓存 DNS 的响应 60 秒。

使用--rpc 标志运行 geth (当然是在测试网络中)

geth --rpc --testnet

现在是一些需要解决 javascript 问题的时间,这是最难的部分。我不是一个很好的网络开发人员,每次 Javascript 行为时都使我很难理解。我在 3 小时内一起破解了一个非常糟糕但工作正常的 javascript。初步结果是成功的。

现在为了使它与 geth 一起使用,我必须在端口 8545 上运行我的 Web 服务器和域,因为 SOP 也使用这个端口。但如果我将链接发送给任何端口 8545 的人会显得有些低级。

解决方案是 iframe。我让 apache 监听 8545 和 80 端口,并为每个端口设置一个虚拟主机。现在我编写一个 i 访问 8545 端口的 frame 并在隐藏的 iframe 中运行所有的 javascript。

另一个问题是关于多个用户,如果多个用户同时访问了我的域,该怎么办?因为我使用的是一一个基于计数的操作系统,DNS 服务器会无法区分请求来自哪个用户。最终解决我的困惑是想到了使用子域名。

每次用户访问主域我都可以生成一个指向随机子域名的 iframe,将其作为这个用户的标识。我知道我可能没有清楚地解释这种攻击方式,下面有个例子。

我们假设我的域名是 attacker.com,我的服务器的 IP 是 87.87.87.87,以下攻击方式的步骤:

  • 受害者在他的浏览器中打开 attacker.com。
  • 首先,针对 attacker.com 的 DNS 请求被发送到我的服务器并且我的 DNS 服务器使用真实的 IP 地址 87.87.87.87 响应。
  • 接下来,用户的浏览器加载 attacker.com,然后创建一个指向 randomrsub.attacker.com:8545 的 iframe,并将其添加到页面 body 部分。
  • 现在,一个获取子域 randomrsub.attacker.com 地址的 DNS 请求发送到我的服务器,DNS 服务器再次使用真实 IP 87.87.87.87 进行响应。但这次,由于它位于端口 8545 上,因此 apache 会使用不同的虚拟主机进行响应,从而开始我们的 DNS 重绑定攻击利用。
  • 在 randomrsub.attacker.com:8545 上的 javascript 会先等待 60 秒,然后发送一个请求 randomsub.attacker.com:8545/test 的 XmlHttpRequest。
  • 由于浏览器的 DNS 缓存已过期,浏览器会再次解析 DNS。这次,我的 DNS 服务器响应 IP 为 127.0.0.1。
  • 现在请求实际上发送到 127.0.0.1:8545/test 而不是我的服务器,因为它在 randomrr.attacker.com:8545 的源下,我们可以读取响应。
  • 由于我们每次都会生成一个随机子域,因此我们甚至可以处理对多个用户的攻击,因为子域可以作为其标识令牌。

我还必须优化一下 javascript,以保证 95% 的时间都能正常工作。我在真正的 DNS 查询之前添加了一些虚假的 DNS 查询,以便它在错误的时候不会响应成错误的 IP 地址。

这个漏洞也可以结合存储型 XSS 攻击。只需将资源请求指向一个 js 文件,即可添加 iframe 和 TADA !!

所以现在我们可以读取 JSON-RPC 服务的响应,这意味着我们可以读取他们的以太坊地址,他们的账目,甚至会窃取他们的以太(如果他们的账户未上锁)。 JSON-RPC API 有一个相当不错的方法,称为 eth_sendTransaction,它基本上可用于从用户的帐户发送以太坊。

我将我的 POC 放到了 http://rebinddns.ml 网站上。如果您使用 JSON-RPC 运行 Geth (或任何其他以太坊客户端)超过 60 秒,您将看到一个 alert(),其中包含您的以太坊地址及其余额。

PoC 中使用的所有文件都可以在我的 github 上找到。

  • min.js - 在端口 8545 上生成子域的隐藏 iframe 的 Js 文件
  • main.js - 执行 DNS 重新绑定的 Js 文件
  • server.py - 用 python 编写的 DNS 服务器

我已经验证了 Geth,C ++以太坊客户端以及 python 客户端都存在漏洞。 PoC 已经在 Firefox,Chrome 和 Safari 上进行了测试。

PS:这个漏洞已被报告给以太坊基金会并且已经修复。他们还给了我一笔不错的赏金。

关键词:[‘技术文章’, ‘翻译文章’]


author

旭达网络

旭达网络技术博客,曾记录各种技术问题,一贴搞定.
本文采用知识共享署名 4.0 国际许可协议进行许可。

We notice you're using an adblocker. If you like our webite please keep us running by whitelisting this site in your ad blocker. We’re serving quality, related ads only. Thank you!

I've whitelisted your website.

Not now