你想在 DuckDuckGo 搜索结果的最顶部看到一个加密货币窃取器吗?Would you like a drainer served at the very top of DuckDuckGo?
作者发现 DuckDuckGo 搜索引擎的置顶结果中竟然出现了一个包含加密货币窃取器(drainer)的钓鱼网站。该网站完美仿冒了 Tronscan 区块链浏览器,极具欺骗性和危险性。这暴露了 DuckDuckGo 在广告和搜索结果审核机制上的严重漏洞。搜索引擎必须立即修复此类将高危恶意链接置于顶部的推荐逻辑。
tim
大概不会,对吧?
那将非常危险,特别是当提供该链接的钓鱼网站与你正在寻找的网站一模一样时。
嗯,这就是发生在我身上的事情!
内容摘要
我在搜索结果的第一名发现了一个伪造的 Tronscan 区块链浏览器副本。该网站伪装成 AML/安全工具,提示用户连接他们的钱包。
深入挖掘后得出的一些见解:
背景故事
像往常一样,这次诈骗调查纯属意外——这很棒,因为我不用再去寻找新的主题和事物来研究了。
一个星期五的晚上,我坐在办公桌前,试图完成本周待办事项清单上的最后一项小任务:在我当时正在做的一个项目中测试与链无关的地址拼写检查器。
“Tron 时间到了”,我打开 DuckDuckGo 并输入 Tronscan。我之所以用搜索,是因为我不记得它的域名了——是 .io?还是 .org?我不知道。
无论如何,我凭着下意识的习惯,点击了第一个从标题、描述、网站图标等看起来像 Tronscan 的结果……然后来到了这里:
这正是我期望看到的——https://tronscan.org/ 看起来简直一模一样。于是我点击搜索框,但令我完全惊讶的是,弹出了这个连接钱包的提示。我仍然相信自己是在正确的网站上,所以我反复检查是不是我点错了按到了什么按钮——不,结果还是一样。
事实上,几秒钟后我就意识到,在这个页面的任何位置点击任何内容都会弹出这个窗口。
这时我开始起疑心了——为什么一个区块链浏览器会要求我连接钱包才能执行任何基本操作?然后我看了看域名,一切都真相大白了:
你算什么东西,tronscan-app[.]org?
我打开开发者工具(Dev Tools),导出该网站加载的所有脚本,快速浏览了一下以确定里面是否有某种恶意软件,然后我发现了它——web3-loader.js。
下面会有一个完整的大章节专门用来分析它。
我保存了文件内容以便日后研究,将该链接报告给了 SEAL Phishing Bot,确认在大约 15 分钟后 tronscan-app[.]org 已下线,然后继续我的周五晚间计划。
搜索引擎优化(SEO)
你能想象我有多惊讶吗?第二天下午,我换了一台不同的设备,再次回到 DuckDuckGo,想看看那个最初的 Tronscan 网站现在是否排在第一,结果却看到了这一幕:
我简直不敢相信自己的眼睛——搜索结果竟然又是第一名!排名比真正的 Tronscan 还要高,而且这甚至不是广告——这是针对我查询的“自然”最佳结果。
我点击链接,本以为会看到 404 错误之类的页面,但不到一秒钟的时间,我突然跳转到了另一个 Tronscan 的山寨网站,这次是 tr0nscan.com——就好像我刚才点的是另一个链接一样。看来这些家伙连夜更换了被屏蔽的诱饵。
“小菜一碟”,我心想。肯定是一个极其迅速的简单重定向,快到我甚至都没注意到地址栏的变化。
我在浏览器中打开开发者工具,进入网络选项卡,并从点击 DuckDuckGo 搜索结果时开始记录……结果什么也没看到。只有一些发往 DuckDuckGo 的请求,然后停顿了一下……接着就是发往 tr0nscan 主机的请求。我是怎么跳到这里来的?
经过几次尝试,我偶然发现了这个文件的存在——https://tronscan.gr.com/checking.php
它似乎完成了整个神奇的重定向过程:
302 https://tronscan.gr.com/
-> https://tronscan.gr.com/checking.php?t={smth}
200 https://tronscan.gr.com/checking.php?t={smth}
200 https://tr0nscan.com/?verified=1所以,tronscan.gr.com 在服务端带上一个看似 cookie 的 token 参数 t 重定向到了 checking.php。该页面返回 200 状态码,然后客户端再将浏览器重定向或导航至 tr0nscan.org/?verified=1,也就是那个弹窗加载的地方。
开发者工具无法向我显示 checking.php 的内容,所以我又花了大概 20 分钟使用 mitmproxy,终于获取到了它的完整内容——你能猜到我在里面发现了什么吗?
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Redirecting...</title>
<script>
// Убираем токен из адресной строки (чтобы не светился)
// -> removing the token from the search bar so it doesn’t show.
history.replaceState(null, null, location.pathname);
</script>
</head>
<body>
<!-- САМАЯ ГЛАВНАЯ ФИШКА — НАСТОЯЩИЙ POST ОТ БРАУЗЕРА ЮЗЕРА -->
<!-- -> main feature - real post made from user browser -->
<form id="verify-form" method="GET" action="https://tr0nscan.com" style="display:none;">
<input type="hidden" name="verified" value="1">
<!-- Можно добавить ещё параметры, если нужно -->
<!-- <input type="hidden" name="ip" value="162.158.122.185"> -->
<!-- this is not important so no translation -->
</form>
<script>
// Автоматический сабмит формы через 100 мс (чтобы юзер ничего не заметил)
// -> Auto-submit form in 100ms (so the user doesn’t notice)
setTimeout(function() {
document.getElementById('verify-form').submit();
}, 100);
</script>
<div style="text-align:center; padding:50px; font-family:Arial;">
<img src="https://upload.wikimedia.org/wikipedia/commons/b/b1/Loading_icon.gif" alt="loading">
</div>
</body>
</html>谁能想到——里面竟然有俄语注释!我在下面为你附上了翻译。
原来如此——那个未被察觉的秘密重定向神技,只不过是一个客户端的表单自动提交,加上地址栏里的一些伪装。我很好奇,这些攻击者(TA)到底是说俄语的人,还是仅仅在某个论坛上找到了这个简单的 .php 文件。
有趣的是(尽管这在如今并不罕见),在我进行了数十次点击、重定向、curl 请求以及其他操作之后,起始页面 tronscan.gr.com 开始将我重定向到合法的 Tronscan 网站——这意味着后端使用了那个 t={smth} token 来为特定用户选择正确的 `<form action="{url}">`。
这是一种常见的伪装技术,它通过缩短好奇者的机会窗口,并使重定向链路难以被他人或同一研究人员在其他时间重现,从而试图让任何形式的激进挖掘变得复杂。
肯定还有其他的,对吧?
在深入探究了这波神奇的重定向之后,我刚让自己稍微平静下来,就决定去寻找其他的同类网站——既然在 DuckDuckGo 搜索 "tronscan" 的结果中存在排名第一的钓鱼网站,那么也许针对其他关键词也存在类似的网站?
是的,而且还有很多。
我不想在这些其他网站上深入探讨太多细节,否则这篇已经够长的文章就有可能变得长得离谱,所以这里仅举几个我发现的例子,而我要做的仅仅是回忆了几个不同的 web3 产品/工具,并把它们的名字输入到了 DuckDuckGo 中:
solscan 的第三名搜索结果,正是我们在最初的 tronscan 网站上见过的那个 *.gr.com 域名。有趣的是,由于根级域名 gr.com 已经把我标记为一个绝不能接近钓鱼诱饵的“爱嗅探的嗅探者”,所以这个 solscan 钓鱼网站直接把我重定向到了 google.com。
然后是 Phantom 钱包,同样的 *.gr.com 网站在搜索结果中排名第二:
它其实长得挺好看的,只是用了一个更简单的助记词窃取器代替了普通的 Drainer ——不知道现在这玩意儿还能不能骗到人(估计还是能的)。
然后我在“etherscan”的第三个搜索结果中又发现了一个类似的助记词窃取器:
需要注意的是,入口网站 etherscan.github.io 滥用了 Github Pages,实质上是为了免费托管这些重定向脚本,而最终跳转到的实际钓鱼页面却是一个普通的域名,上面根本没提到 etherscan。
Github Pages 的这个问题,跟 Cloudflare Workers / Pages 以及其他类似平台一样,非常严重:这些网关网站极难被检测出来,因为只有当真实的(或者至少是经过专门配置的无头)浏览器访问该页面时,重定向才会真正发生。对于任何试图判断该网站是否会跳转到恶意内容的简单爬虫来说,根本不会触发重定向。
这使得部署的网站在服务提供商看来是无害的(或者仅仅像是网页坏了),因此,除非被受害者或像我这样的人手动举报,否则它们可以存在很长时间。
不仅如此,由于 github.io 总体上是一个非常知名且声誉良好的域名,搜索引擎会优先收录它们,而不是那些零外链的新域名——这使得攻击者利用一些神秘的 SEO 技术将排名刷到尽可能高的位置变得更加容易。
关于 SEO 部分的简短且令人困惑的结论
我还可以列举更多的例子,但我认为这已经足以说明,几乎对于每一个与热门 web3 产品相关的搜索词,都存在排名前三的钓鱼网站。
在继续对实际的 Drainer 进行分析之前,我想先分享一些我对这些窃取者和 Drainer 的自然搜索流量来源的总体观察:
好了,现在终于可以仔细看看那个来自 tronscan 仿冒诱饵的原始 Drainer 了!
标题中承诺要讲的 Drainer
让我们先来梳理一遍用户流程——到底某人是怎么一步步被引诱并损失所有钱财的。
亏钱是什么样子的
正如你所记得的,这一切都始于一个 WalletConnect 弹窗,提示你……连接你的钱包。
如果你像我一样是个勇敢的探索者,连接钱包后就会看到这个:
首先,该应用试图模仿 AMLBot——一款流行的(我猜?)AML / KYT 软件,大概是为了某种合规原因引诱用户进行连接。TronLink 实际上对此显示了一个小小的黄色警告——在我看来,当未经验证的可疑应用试图冒用合法服务名称时,警告应该是鲜红醒目的。
如果你真的相信了,接下来系统会提示你签署一笔交易。当你解码这段十六进制编码的 protobuf 交易元数据时,它看起来是这样的:
Contract call:
type: TriggerSmartContract
Owner:
my wallet address
Token contract:
TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t - USDT token contract on TRON
Function selector:
d73dd623
Decoded function:
increaseApproval(address,uint256)
Spender:
TUJHEnmHG4qJPUhk2mecZfv2edMwoweM3K - attacker-controlled receiver address
Amount:
0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
= uint256 max = unlimited allowance实际上,签署这个交易就允许攻击者钱包 TUJHEnmHG4qJPUhk2mecZfv2edMwoweM3K 获取我持有的任意数量的 USDT。
我的这个钱包里只有 USDT,所以这是我被提示签署的唯一交易(tx)。正如你很快会看到的,这个盗币器(drainer)还能够通过不同的方式盗取任何 TRC-20 代币和原生 TRX 币。
盗币器工作流程
我决定把反混淆过程的细节留到另一篇文章中(或者干脆不写了)——长话短说,这并不是一个多么复杂的盗币器,完全不像如今在 DaaS 市场被视为“主流(meta)”的 Infernos 和 Vanillas。我花了几个小时编写了一个 python 脚本,通过旋转字符串表并不断尝试解码器函数,最终得到了一个半可读的 .js 文件,然后我使用 llms 对其进行了格式美化。
我在下面的图表中描绘了完整的工作流程:
几个有趣的细节:
总的来说,这并不是一个复杂的盗币器,但从交易记录来看,它确实完成了任务:用于 TRX 中继的合约部署者在合约部署几天后就收到了至少 1.5 万美元。
AML 问题
在结束之前,我还想谈谈这些盗币器让我感到困扰的另一个问题:一些(我认为是所有)KYT/AML 工具无法检测出属于攻击者的地址的非法性质。
在过去的8个月里,我一直在研究 KYT 产品和算法,在此期间我获得了两家不同供应商的使用权限。我不打算在这里点名,以避免不必要的品牌针对,因为我认为这并不重要——任何其他供应商可能都会显示类似的结果。
在 drainer 代码中发现硬编码的地址后,我的第一步行动是检查合约代码,然后检查每个直接参与 TRX 盗币或部署上述合约的 EOA 的 KYT 风险评分。
这些合约代码未经验证,但如果你反编译字节码或直接使用区块浏览器的内置功能,你会看到一大堆没有任何实际逻辑的函数——这些全都是为了让受害者误以为他们正在签署有益的操作,比如领取奖励、更新安全设置或其他类似操作。
你可能猜到了,这是一个巨大的危险信号——而且对于一个能够双向扫描6层以上深度的交易的工具来说,检测出这一点并不难。
但是,在我能使用的两款 KYT 工具中检查这两个 EOA(硬编码的地址 + 硬编码合约的部署者)后,结果显示为低风险甚至无风险——这意味着,如果攻击者以后想利用像 Binance 这样合规的 CEX 来洗白被盗资金,将没有任何安全措施来阻止他们、冻结其资产或向有关部门报告这些可疑的交易/地址。
作为参考,以下是这些工具的风险评分结果:部署了 TNzfYto3vBeG9X5j597DCEi37813wBzrM3 合约的 TQdt2sfRz4pgkS2gcYwYoDdmju3fEzgBdT:
接收代币授权的 TUJHEnmHG4qJPUhk2mecZfv2edMwoweM3K EOA:
听着,我并不是说随时反编译字节码,并让某个基于规则的引擎来决定合约是否可疑是一件容易的事。
但是,鉴于整个加密货币领域的 AML/KYT 工具都是闭源的,不仅收费高昂,而且算法保密,当我们看到那些在风险评估时本应依赖并盲目信任的工具,竟然无法解决这个难题(与 SOTA 的 drainer 相比,这还算相对简单的),甚至无法至少将其标记为可疑以提醒客户时,这令人十分担忧。
所有 web3 钓鱼和诈骗面临的最大问题在于,在无许可的世界里它们极难被防范;在这个世界里,作为受害者的你可以做任何你想做的事,签署任何交易——这本身是件好事,也许也是加密货币总体上最棒的一点。
而对于那些想要保护潜在受害者并阻止攻击者卷走被盗资金的人来说,剩下的选项并不多。
首先可以通过标记攻击者控制的域名并将其添加到钱包黑名单中来实现(这正是我在 SEAL 帮助下所做的事),但是,想要阻止资金转移(或至少增加其难度),只能依靠中心化/合规服务的 AML 层。当这一层未能突显出上述案例时,我们(防御者)能做的就仅限于事后的封锁和报告了。
别误会,这并不是毫无用处!我做这些的原因,除了出于对调查过程的热爱,更是为了提高公众的防范意识——那些在加密货币安全操作方面知之甚少甚至一无所知的人,他们一年365天,每天都会被多次诈骗和盗取资产。
只是看到这些脚本小子(当然有时也包括一些真正的危险分子)靠着这些低劣的骗局就能逍遥法外,真让我感到悲哀。
全文完
我不想再重新总结什么了。我想补充的是,这两件事(KYT 的局限性,以及攻击者购买或搭建的、能霸占搜索榜首的高效 SEO)似乎都很有趣且足够重要,值得进行更深入的研究。顺便说一句,如果您熟悉 KYT、在公司使用 KYT,或者就职于开发 KYT 的公司——请与我联系:[email protected]。也许我很快就会带着新的故事或更新回来。
感谢您阅读到最后!
需要完整排版与评论请前往来源站点阅读。