笔记本电脑就是入口
Binance 表示,有记录以来最大的加密货币盗窃案,约 63 亿美元,可能始于一名 DevOps 工程师被入侵的笔记本电脑。被指为幕后黑手的组织有个惯用手法:让开发者运行一个项目,再利用那台笔记本电脑能触及的一切。如今编码代理整天都在运行项目。在 Bromure Agentic Coding 中,这些代码在只持有替身凭据的 VM 里运行,每一次使用生产环境的密钥都要经过 Mac。
攻击者不需要 Binance 的私钥。他们需要的是一名工程师的笔记本电脑,以及它能触及的系统。开发者的电脑是通往生产环境的路径,而编码代理如今会运行落到电脑上的任何代码。
10 月 30 日,Binance 披露了一起“安全事件”,涉及约 63 亿美元的资产。The Hacker News 报道,Chainalysis 在事发时估计被盗金额为 59.12 亿美元,几乎是此前有记录的最大加密货币盗窃案的四倍。已有近 30 亿美元在链上被冻结,大部分是 Tether 和 Circle 冻结的稳定币。Binance 表示将赔付所有损失。
Binance 对事件起点的说明只有一句话:“初步调查表明,此次安全事件可能涉及一名 DevOps 工程师被入侵的笔记本电脑”,攻击者借此进入一个服务容器,并提交了未经授权的提现。Binance 表示,没有发现任何钱包私钥泄露的证据。它没有说明那台笔记本电脑是如何被入侵的。
五十个签名与三分钟
链上记录显示了这份访问权限的价值。UTC 时间 20:20,攻击者提交了一笔交易,其中带有 50 个授权,每个都由 Binance 的热钱包签名,分别对应 50 个连续的交易序号,好让其中一个恰好对上钱包的下一个序号。每个授权都指向一个只听命于攻击者的归集合约。其中一个对上了。大约三分 24 秒后,热钱包把全部余额转给了攻击者:167,464 ETH 和 63 种代币,其中包括 16.15 亿 USDT。
Blockaid 首席执行官 Ido Ben-Natan 告诉 Cointelegraph,初步证据指向“密钥滥用”:签名系统被诱导去签署攻击者的交易,根本不需要窃取任何密钥。密钥一直留在原处。只是有人拿着那名工程师的访问权限,让系统使用了它们。
TRM Labs“以高置信度”将此次攻击归于 TraderTraitor,即 FBI 认定为 2025 年 2 月 Bybit 15 亿美元盗窃案元凶的朝鲜组织。Chainalysis 同样指向朝鲜。Binance 则没有点名任何人。
这个组织如何进入笔记本电脑
TraderTraitor 记录最完整的一次入侵展示了它的手法。在 Bybit 一案中,Safe 自己的初步报告和 Mandiant 的调查结果 按顺序描述了经过:
- 2025 年 2 月 4 日,一名 Safe 开发者在自己的 Mac 上运行了一个名为
MC-Based-Stock-Invest-Simulator-main的 Docker 项目。Mandiant 认为这名开发者是被说服去运行的。 - 该项目连接到
getstockprice[.]com,一个两天前才注册的域名,开发者的 macOS 工作站随即被入侵。 - 攻击者拿走了开发者的 AWS 会话令牌,从而能够绕过多因素认证,使用开发者的 AWS 访问权限。
- 他们凭借这份访问权限,篡改了 Bybit 签名人使用的 Safe 界面,签名人随后批准了一笔清空冷钱包的交易。
Mandiant 指出,该组织在此前的盗窃案中也用过类似的、以股票为主题的 Docker 项目。手法从未改变:给开发者一个项目,让它以开发者的身份运行,再拿走那台电脑能触及的东西。一台 DevOps 笔记本电脑能触及的东西很多。上面通常有存着有效会话令牌的 ~/.aws、指向生产集群的 ~/.kube/config、堡垒机的 SSH 密钥,以及 gh 的登录状态,工程师启动的任何进程都能读取这些。
现在运行项目的是代理
过去的诱饵需要一位能被说服去运行某样东西的开发者。这一步正变得越来越容易跳过。就在 Binance 披露入侵的同一天,BleepingComputer 报道了 Air Security 对一个名为 SolanaUpdateTools/solana-starter-kit 的 GitHub 仓库的分析。它有 286 颗星,而且据 Air 称,AI 编码代理搜索 Solana 入门套件时,它排在第一位。仓库里唯一的文件就是 README。它承诺提供完整的应用模板,只给出一个安装步骤:粘贴一条命令,这条命令会用片段拼出一个位于 developer-update[.]app 的 URL,下载一个脚本,并在内存中执行。
Air 获取的载荷会安装 NetSupport Manager,一款合法的远程访问工具,并设置为每次登录时都连接攻击者。接着它会显示一条假错误:开发者功能“因负载过高暂停”,请 72 小时后再试。照着 README 操作的代理会运行这条命令,然后报告服务器繁忙。开发者看不到任何值得多看一眼的东西。
把这个代理放到一位 DevOps 工程师的笔记本电脑上,工程师的 kubeconfig 和 AWS 会话就在同一个主目录里,这个入门套件就成了 Bybit 案中的那个 Docker 项目,只是省去了社会工程。
同一个项目,放进 Bromure Agentic Coding
Bromure Agentic Coding 在你的 Mac 上以 Ubuntu VM 运行 Claude Code、Codex、Grok、Kimi 和 omp。每台机器都是独立的 VM,代理接触的一切都在里面:克隆下来的仓库、软件包缓存、Docker 容器,以及 README 建议的每一条命令。你的 Mac 持有真正的凭据、VM 流量必经的代理服务器,以及事情经过的记录。
项目在 VM 里运行,而不是以你的身份
在 Bromure 机器里运行那个股票模拟器的 Docker 项目,或者让代理粘贴入门套件的命令。容器在 VM 里启动,载荷也是。它拿到的是 Ubuntu 客户机里的一个 shell,身份是机器的用户。它拿不到你的 macOS 账号,也拿不到你的钥匙串。你 Mac 上的 ~/.aws、~/.kube 和 ~/.ssh 也不在那里:Bromure 在你导入时于主机上读取这些文件,从不把它们挂载进 VM。
它找到的密钥都是替身
接下来,载荷会去找凭据,而 VM 里有很多看起来都对的。没有一个能在别处使用。
- AWS.
~/.aws/config指向一个辅助程序,它交出真正的访问密钥 ID,搭配一个假的秘密访问密钥,而且完全没有会话令牌。VM 用假的秘密密钥签署每个请求,Mac 则在请求发往*.amazonaws.com的途中,用真的密钥重新签名。把 VM 的 AWS 凭据复制到另一台机器,每次调用都会以InvalidSignatureException失败。Bybit 攻击者拿走的那种会话令牌,在 VM 里根本不以任何形式存在。 - Kubernetes. VM 的
~/.kube/config是合成的。kubectl与 Bromure 的代理服务器通信,从不直接连接 API 服务器。Bearer token 是brm-k8s-…替身,客户端证书是一次性的,而像aws eks get-token这样的 exec 插件在 Mac 上运行,而不是在 VM 里。 - SSH. VM 的
SSH_AUTH_SOCK是通往 Mac 的桥接。客户机可以请求签名,私钥永远不会离开主机。ls ~/.ssh/id_*找不到任何可以复制的东西。你 Mac 自己的 ssh-agent 也从不暴露给任何 VM。 - Git.
gh和~/.git-credentials里的 GitHub 令牌是替身,代理服务器只在发往 github.com 的请求上,才把它换成真的。
替身同时也是绊线。如果载荷把替身发送到自己的服务器,代理服务器会在任何一个字节离开你的 Mac 之前,以 HTTP 451 拦下请求,暂停 VM,并显示 This environment may have been compromised,指出是哪个凭据、原本要发往哪台主机。在磁盘和主目录被清除之前,这台机器不会再启动。你的设置和密钥都会保留。
生产环境的密钥听你的
替身解决了窃取的问题。Binance 一案带出了第二种风险:攻击者根本不偷访问权限,而是直接在它本来就能用的地方使用它。VM 里的载荷可以像代理一样,通过代理服务器发出请求。这些请求能做什么,由 Bromure 的 Guardrails 决定,而且在 Mac 上强制执行,VM 里的任何东西都改不了。
- Require approval to use,按凭据设置:Kubernetes context、AWS 密钥或 SSH 密钥在一个会话中第一次被使用时,代理服务器会扣下请求,在你的 Mac 上询问你。你可以选择 5 分钟、一小时或整个会话,或者 Don't allow。对 AWS 而言,这项检查覆盖每一次签名调用。在你批准之前就伸手去碰生产集群的载荷,只会在你屏幕上弹出一个对话框,在有人回应之前什么都拿不到。
- 写入策略,按服务设置。新机器对 Kubernetes、AWS、镜像仓库、git 托管平台和数据库,一开始都是 Prompt before write:读取直接放行,每一次写入都会停在一个显示具体操作的对话框上。Block destructive 拒绝删除和终止,Read-only 则拒绝一切更改。只需要读取生产环境日志的机器可以设为只读,在其中运行的任何东西都无法更改生产环境。
- Outbound connections,每台机器各自的防火墙。把 Unmatched traffic 设为 Deny,只允许项目需要的主机。入门套件从
developer-update[.]app的下载、Bybit 项目对getstockprice[.]com的调用,以及 NetSupport 回连攻击者的连接,全都落入默认规则而被拒绝。
每一次凭据使用、签名、拦截和放行,都会记录在机器的 Security Timeline 中,AWS 签名调用和 SSH 签名逐条记录。Binance 现在正通过一台“被入侵的电脑”重建攻击路径。在 Bromure 中,VM 拿你的凭据做了什么的记录保存在 Mac 上,在攻击者控制的那台 VM 之外。
让入门套件远离生产环境
创建 Bromure 机器很省事,所以访问权限可以分散到不同机器上。凭据是按机器配置的。用来试用新入门套件、带回家做的编程测试或陌生人仓库的机器,完全不给生产环境凭据,并配上默认拒绝的防火墙。kubeconfig 和 AWS 角色则留在负责部署工作的机器上,两者都要求批准。对于不想保留的东西,bromure-cli vm run --rm 会创建一台停止时即删除的机器。
这样一来,载荷即使占领了入门套件的 VM,也找不到任何值得拿的东西:没有真正的密钥,没有集群,也没有通往你未允许的主机的路径。部署用的机器从未运行过它的代码。
项目在 VM 里运行
Docker 项目、README 命令和代理的安装操作,都在机器的 Ubuntu VM 里运行,远离你的 macOS 账号和钥匙串。
是替身,不是会话令牌
AWS 秘密密钥是假的,会话令牌根本不存在,kubeconfig 是合成的,SSH 密钥留在 Mac 上。副本到了其他地方都会失效。
生产环境先问过你
按凭据的批准和按服务的写入策略,都在你 Mac 上的代理服务器里运行。VM 里的任何东西都关不掉它们。
拒绝未知的主机
把 Unmatched traffic 设为 Deny,载荷的下载和它回连攻击者的连接都会被拒绝,而且这次尝试会被记录下来。
看它上演两遍
我们的教程系列 A Tale of Two Agents 以这起攻击为灵感。Theo 是虚构交易所 Coinvance 的 DevOps 工程师,他让编码代理替他完成招聘方发来的笔试题,而 README 要代理先运行一个安装脚本。同一个错误在分屏上演两遍:左边,代理在他的笔记本电脑上运行;右边,在 Bromure 里运行。
- 笔试题(1:24)。在笔记本电脑上,脚本把他真实的云密钥、kubeconfig 和部署令牌当作“遥测数据”发了出去。在 Bromure 里,它只找到替身凭据;当替身凭据被发往错误的主机,Bromure 会暂停 VM 并征求他的意见。
- 横向移动(1:18)。有人用 Theo 的 Kubernetes 访问权限篡改了提现服务。右边,Security Timeline 把被阻止的请求一路追溯到代理的推理,工作区一键即可清除。
- 二十分钟(1:02)。左边,热钱包被掏空。右边,没有任何密钥需要轮换。
Theo 和 Coinvance 都是虚构的,这几集并不描述 Binance 实际发生的经过。每一集都有八种语言的旁白。
开发者的电脑是生产环境的一部分
Binance 的提现服务正因“安全改造”而暂停,预计 48 小时内恢复,而它的完整分析会进一步说明那台笔记本电脑是如何被触及的。Bybit 早已让所有人看清这个模式。想要一家公司生产系统的攻击者,会去找运维这些系统的工程师的电脑,而在大多数这样的电脑上,生产环境的访问权限就放在主目录里的几个文件中。
你的编码代理让这个缺口变得更大。它在一个又一个任务中克隆、安装并运行陌生人的代码,粘贴 README 命令的速度比你还快。在 Bromure Agentic Coding 中,代码在只有替身的 VM 里运行,而生产环境的访问权限留在 Mac 上,挡在一个你必须回应的对话框后面。
关于一场完全不需要攻击者服务器的令牌窃取行动,请阅读被盗的令牌不需要服务器。关于一个从下载文件接受命令的代理,请阅读下达命令的是那个下载文件。
