区块链
交易结束了 授权却留在 JaredfromSubway 的收割现场
这座反向蜜罐用真实可兑现的小额利润诱使 JaredfromSubway 主动把 WETH、USDC 与 USDT 的持久支出权交给陌生 wrapper,再用只在特定区块生效的切换跳过预期的 transferFrom() ;BlockSec 识别的一笔收割交易由此从单份运营合约转出约 750 万美元资产,暴露出自动交易系统必须补上的完整权限生命周期。

文章导航
证据分成四层:Chainalysis 与 BlockSec 的事件观察、可独立核查的链上字段、标准与固定提交源码解释的 allowance 语义,以及建立在这些记录上的防守方案。Chainalysis 的 66 个仿冒代币合约与至少 750 万美元活动损失下限、BlockSec 的约 44 个池与单笔约 750 万美元还原、以及运营方约 1500 万美元总损失说法各自描述不同对象;全文保留这些对象和证据等级,不做合并估算。
1 一座人工市场换走了一份真实权限
五类参与者和一个状态变量足以看懂全案。攻击者控制工厂和逐区块开关;仿冒 wrapper 请求真实代币授权;仿冒池提供交换路线与事件;JaredfromSubway 的运营合约充当 owner 并签署交易;WETH、USDC、USDT 合约保存 owner 到 spender 的 allowance。池子与 wrapper 负责让路线看起来值得执行,真实代币账本负责把权限一直保存到后来的收割。
Chainalysis 的 6 月 26 日复盘把活动窗口放在 2026 年 6 月 20 日至 21 日:一名身份未知的攻击者部署 66 个仿冒代币合约,模仿 WETH、USDC、USDT 等资产,并把它们配进欺诈性流动性池。机器人在多笔交易中授予支出权限;部分权限在操作中未被消耗,事后也未撤销。Chainalysis 据此给出至少 750 万美元的活动损失下限,并记录稳定币换成 ETH、资金分散与 Tornado Cash 路径。
BlockSec 的技术还原识别了运营合约 0x1f2F10D1C40777AE1Da742455c65828FF36Df387、仿冒代币工厂 0x81F248Ff583d3f8592Ea0354A7b8DBe66de40091、约 44 个 Uniswap v2 风格池和一条依赖当前区块的 getStatus() 分支。wrapper 复用真实代币名称,在展示符号前加 f,还能从攻击者储备向机器人返还少量真实代币。交易结果因此同时具备可执行路线、正常事件和可计价利润三种可信外观。
1.1 代码与处置图锁定公开可核验的控制点
1.2 一张证据账本限定每项结论能支持的动作
| 事实对象 | 来源与证据等级 | 可直接采取的动作 |
|---|---|---|
| 66 个仿冒代币合约、至少 750 万美元活动损失下限 | Chainalysis 活动观察与资金追踪 | 用作资产与合约清单种子;完整性需要逐地址、逐交易重建 |
| 约 44 个池、逐区块分支、区块 25,360,519 的积累模式锚点 | BlockSec 链上技术还原 | 按工厂、代码家族、激活调用与残留 allowance 扩展排查 |
| 区块 25,360,696 的收割交易与三种代币单位净额 | 以太坊交易、回执、日志和 BlockSec 汇总 | 复算余额变化、调用路径、资产净额和直接接收方 |
| 运营方约 1500 万美元总损失说法 | BlockSec 转述 JaredfromSubway | 用于扩大初始事件范围;总钱包与交易集合仍需独立建立 |
| ERC-20 allowance 的持久语义 | EIP-20 与 commit 固定的 OpenZeppelin 参考实现 | 设计状态不变量;具体代币行为仍以历史链上代码和状态为准 |
这张账本把活动观察、链上字段、参考标准和运营方说法放回各自的位置。后文只在证据等级会改变处置时再次说明边界,调查主线则沿权限如何创建、保留、使用和关闭推进。
2 前几笔交易先教会机器人相信这条路线
BlockSec 把区块 25,354,425 的交易 0x542d8d7ad206672bf484bbad9635ec5f92a429d527a561ae898c2da09742362b作为早期信任样本。机器人先在真实代币合约上批准 wrapper,再调用 wrapTo();wrapper 执行 transferFrom(bot, wrapper, amount),有限 allowance 随支出下降。路线穿过攻击者创建的池,unwrap() 又向机器人送回真实代币。执行、事件、权限消耗和账面利润在这笔交易里保持一致。
交易 0x085ec14424f9b2f290ea7bd2f60fc74f3dc3d8996d70ad7bf384bcae52c37e51展示了下一阶段。外部状态机制已经部署,所在区块的 getStatus() 仍返回未激活值,wrapper 继续正常拉取。仿冒池同时发出真实的 Sync 与 Swap 日志,攻击者储备提供的小额真实代币形成可兑现利润。自动系统看到的是连续成功;场所的部署者、资金来源与代码控制权则始终集中在攻击者一侧。
交易系统在这里需要分开处理五种信号:池日志证明 emitter 执行并写出日志;余额增长证明 owner 收到资产;调用追踪证明 wrapper 是否拉取真实代币;固定区块的 allowance 证明权限结果;工厂、运行时代码和控制状态证明交易对象身份。任何单一信号都只回答自身问题,策略的业务回执需要把五项放在同一个 route ID 下。
2.1 激活区块唯一改变的是必需拉取
积累阶段从 BlockSec 引用的区块 25,360,519、交易 0x85609286d68bd47065772c21fd9542c4343348ff8c7c2e6d63d0692be5781915获得公开锚点。激活交易把当前区块写进外部状态;同一区块内,wrapper 读取到激活值并跳过 transferFrom()。unwrap() 继续发送攻击者出资的真实代币,顶层交易顺利完成,机器人仍看到正利润。价值结果沿用旧形状,权限结果则从“已消耗”变成“完整保留”。
BlockSec 评估,攻击者很可能通过 builder bribe 把激活交易与机器人交易放入同一区块。事件处理可以直接依赖更窄的确定性事实:实际 trace 缺少必需拉取,交易后 allowance 高于策略后置条件,已经构成完整告警。
负执行证据需要预先定义才能稳定检测。策略在签名前记录 spender、获准金额、必需 transferFrom() 的 owner、recipient 与 amount,以及允许的交易后额度;结算器把实际调用树和固定区块状态与这份约定比较。缺少必需调用、额度计算失败或状态读取超时都让该 owner-spender 路线暂停。手续费代币、部分成交和获准复用必须在策略版本里写明公式、舍入、上限与到期时间。
4 一笔收割交易把权限换成了三路资产
2026 年 6 月 20 日 18:49:11 UTC,收割交易 0x2be870…cf3e65进入以太坊区块 25,360,696。发送方是 0x5aF38735B215b00aa7C9f93fEd7ee415CeCB36e1,顶层目标是收割合约 0xb84db016324e8F2BFdD8DD9c260338AEE0A8DF52。交易成功回执、调用树、代币日志与前后余额共同固定了单份运营合约的损失现场。
| 资产 | 从 0x1f2F…f387 转出的公开净额 | 保存方式 |
|---|---|---|
| WETH | 1,474.582523004994977792 | 18 位小数代币数量、合约地址、日志索引、调用帧与余额差 |
| USDC | 2,870,573.12768 | 6 位小数代币数量与带时间戳的独立估值 |
| USDT | 2,035,760.155871 | 6 位小数代币数量与代币特有行为记录 |
BlockSec 报告相同数量,并把这笔已识别交易估值为约 750 万美元;Chainalysis 给出至少 750 万美元的活动级损失下限;BlockSec 另行转述 JaredfromSubway 约 1500 万美元总损失说法。代币单位数量、单笔估值、活动下限与运营方总额说法分别进入四个字段,既能安排事件范围,也保留各自的证明强度。
交易还包含从收割合约到 Etherscan 标记为 Eureka Builder 地址的 0.01 ETH 内部转账,位置为区块内第零笔。BlockSec 将其解释为确保打包的 builder bribe。案件记录分别保存原始转账、浏览器标签与分析用途,后续标签变化不会改写链上数值。
4.1 换币、分散与报告日期运行在三只时钟上
Chainalysis 称,攻击者在取得稳定币后数分钟内将其换成 ETH,并评估发行方冻结风险可能推动了这一步;随后数日,资金被拆分到其他钱包,部分路径进入 Tornado Cash。换币交易、后续分散和 mixer 归因属于三个独立记录层。每条直接资金边保存来源、目的、资产、数量、交易与区块;地址聚类和服务归因另带来源与置信度。
Chainalysis 在 6 月 26 日发文时记录“尚无资金追回”。该状态绑定报告日期。后续冻结、扣押、退还或新增损失需要新的带日期来源。稳定币换成 ETH 也改变了处置窗口:经授权的响应团队可以在证据保全同时联系发行方与交易所,提交对象分为直接接收方、已追踪中间方、服务存款点和待确认集群,并分别记录请求、回执与实际动作状态。
资金路径说明第一笔资产流出以后干预选项会迅速收窄。更早的控制点位于签名器:候选合约的身份、权限请求、必需内部调用与交易后状态必须在同一份策略决定中闭合。
5 签名器同时审查合约身份与权限结果
合约身份从链 ID 与完整地址开始,并绑定候选区块的运行时代码哈希、创建交易、部署者或工厂、实现与管理员、资金来源和变更历史。Uniswap v2 风格的 Swap 与 Sync 事件只描述 emitter 的日志;策略还要确认 pair 是否来自获准工厂、两端代币是否来自版本化注册表。BlockSec 记录的 CREATE2 批量部署同样属于来源线索:EIP-1014 能预先确定地址,地址的实际信任仍来自 deployer、初始化代码、运行时代码与当前状态。
代理进一步要求按区块解析 implementation、beacon 与 admin。ERC-1967 给出了常见存储槽;代理地址与既有存储可以在实现更换后继续存在,implementation 或 beacon 则指向新的执行代码。已批准路线因此绑定实现与状态版本,代码、实现、工厂、资产、金额、目标区块或打包条件变化都会使旧决定过期。
5.1 预检、授权、执行与对账形成前半个闭环
- 预检:固定链、候选区块、完整调用对象、运行时代码、工厂与实现、分支外部读取、流动性来源和打包条件;每项记录负责人、来源与失效条件。
- 授权:为每份真实代币指定 owner、spender、精确上限、route ID、获准持续时间和允许后置额度;陌生场所使用隔离 owner 与小额资本。
- 执行:实际 trace 必须出现策略列出的真实代币调用、参与方与金额;池日志、资产回流和顶层回执作为并列事实写入业务回执。
- 对账:在交易所在规范区块读取余额与 allowance,把价值结果和权限结果分别验收;身份变化、调用缺失、额度差异或读取超时立即暂停 owner-spender 组合。
这四步把本案利用的空隙压缩到一次结算里。真实利润仍可被系统接受,攻击者出资的利润会因来源集中而进入更低信任等级;交易成功仍进入账本,缺失的必需调用和超出预期的权限会把整条策略判为失败。速度来自预计算注册表和紧凑不变量,安全决定保留所有输入与版本。
6 撤销、验证和受控重启关闭后半个生命周期
发现残留 allowance 后,值班团队先暂停相关路线与签名策略,停止新授权和新资本进入。随即保存规范链头、最终确认区块、owner 余额、allowance、待处理交易、签名队列、运行时代码、代理槽和相关 trace。这份快照为撤销前后对比、范围扩展和后续复盘提供固定起点。
撤销使用策略控制的干净路径,直接调用真实代币设置目标额度。恶意支出迫近时,可同时把资产转移到由独立签名策略控制的新 owner;目的地址预先确认 gas、nonce、私有提交、代币暂停与发行方协调条件。范围排查沿 spender、运行时代码家族、实现、工厂、部署者、资助者和收割接收方扩展,并覆盖所有流动真实代币、待处理交易与近期失败路线。
6.1 每项撤销都有状态和完成证据
- 已计划:元组、目标额度、签名者、gas 来源、nonce 策略和资产转移优先级已经批准。
- 已提交:保存撤销交易哈希、提交渠道、替换关系和待处理期间的 owner 隔离状态。
- 已打包:回执成功,交易位于规范链;重组窗口内继续保持未完成状态。
- 已验证:达到选定最终性后,在固定区块读取 allowance 得到目标值,并复核 owner 余额与实现身份。
- 已重启:由与实施者分离的审批人确认代码、配置、开放权限、签名角色和回归结果;金丝雀 owner 在单笔与累计限额下运行预定区块数。
重启方案明确人工值守窗口和自动回退条件。合约身份变化、状态核对超时、提供商分歧或新残留额度都会重新关闭资本闸门。恢复目标同时覆盖恶意合约发现、工厂与代码策略、必需调用、allowance 后置条件、例外治理和历史状态访问,避免只关闭已经暴露的几条元组。
6.2 回归测试重放这次事故的关键变化
第一组测试提交一个储备充足、事件完整、模拟盈利但来自未知工厂的 pair;系统应拒绝自动授权,并让获准工厂对照路线继续运行。第二组在模拟与执行之间改变 wrapper 的外部状态;系统应让签名决定过期,或在结算时捕获缺失拉取与超额残留。第三组让支出更新 allowance 却不发额外 Approval 事件,验证对账器依赖状态读取。
清理测试分别覆盖置零交易丢弃、替换、revert 和被重组移出规范链,仪表盘在固定区块复读前始终显示未完成。向仍有沉睡权限的 owner 再次存入资产,应立即提高暴露估值;代理地址保持不变而实现升级,应同时使候选路线与旧例外过期;索引器重启、提供商切换和短时断网不得丢失暂停状态。自动重试只用于幂等读取,创建权限或移动资产仍需新的策略批准。
这起事件留下的工程结论非常具体:自动交易的完成条件包含价值和权限两份结果。报价值得执行、交易成功、利润到账,只完成了价值侧;必需调用出现、allowance 落入获准状态、异常权限被撤销并完成最终性复读,才关闭权限侧。两侧共享同一个 route ID、证据版本和负责人。
JaredfromSubway 遇到的市场先用正确行为建立信任,再用一个区块改变内部拉取。更安全的系统会在同一个区块读懂这项变化,并在下一笔资本进入以前关闭对应能力。交易结束时,权限也带着可重放证据结束。
研究记录
7证据、对象与来源
下面保留本文实际使用的标识、时间和原始材料,便于继续调查。
7.1研究对象
报告涉及的产品、行为者、技术、受影响对象和控制点。
BlockSec 识别、Etherscan 标记为 JaredfromSubway MEV Bot 2 的合约
区块 25,360,696 中成功执行,包含公开 WETH、USDC 与 USDT 流动
已识别收割交易的顶层目标
已识别收割交易发送方
BlockSec 还原中识别的工厂地址
BlockSec 引用的早期授权消耗路线
BlockSec 引用的未激活开关路线
BlockSec 引用的区块 25,360,519 积累模式交易
获准封装 spender 持有的真实代币持久 allowance
Chainalysis 报告的后续资金目的类别
7.2事件时间
- 早期授权消耗路线
BlockSec 引用一笔早期交易,封装器拉走真实代币并消耗授权。
- 积累模式锚点
BlockSec 将交易 0x856092…1915 作为预期拉取被跳过、权限仍然存在的锚点。
- 已识别收割交易
区块 25,360,696 的成功交易,从被归因受影响合约转出三种公开真实资产净额。
- 转换与分散
Chainalysis 报告稳定币迅速换成 ETH,随后拆分到其他钱包,部分路径进入 Tornado Cash。
- 技术报告发布
BlockSec 于 6 月 25 日发布技术还原;Chainalysis 于 6 月 26 日发布活动与资金流分析。
7.3来源与材料
- Chainalysis:JaredfromSubway.eth 遭遇 750 万美元损失的三明治攻击复盘https://www.chainalysis.com/blog/sandwich-attack-jaredfromsubway-hack/
- BlockSec:jaredFromSubway、Aztec 等事件技术还原https://blocksec.com/blog/web3-security-jaredfromsubway-aztec-more
- Etherscan:已识别收割交易https://etherscan.io/tx/0x2be8704f5a59b69e0b71f64aefdb99eb0e8ae9fb3926147c581910d71bcf3e65
- Etherscan:被归因 JaredfromSubway 受影响合约https://etherscan.io/address/0x1f2F10D1C40777AE1Da742455c65828FF36Df387
- Etherscan:BlockSec 识别的仿冒代币工厂https://etherscan.io/address/0x81F248Ff583d3f8592Ea0354A7b8DBe66de40091
- Etherscan:收割合约https://etherscan.io/address/0xb84db016324e8F2BFdD8DD9c260338AEE0A8DF52
- BlockSec Phalcon:初始信任交易https://app.blocksec.com/phalcon/explorer/tx/eth/0x542d8d7ad206672bf484bbad9635ec5f92a429d527a561ae898c2da09742362b
- BlockSec Phalcon:持续信任交易https://app.blocksec.com/phalcon/explorer/tx/eth/0x085ec14424f9b2f290ea7bd2f60fc74f3dc3d8996d70ad7bf384bcae52c37e51
- BlockSec Phalcon:积累模式锚点https://app.blocksec.com/phalcon/explorer/tx/eth/0x85609286d68bd47065772c21fd9542c4343348ff8c7c2e6d63d0692be5781915
- ERC-20 代币标准https://eips.ethereum.org/EIPS/eip-20
- OpenZeppelin ERC20.sol 固定提交 60a102ahttps://github.com/OpenZeppelin/openzeppelin-contracts/blob/60a102a65b3402aa899376d0da3819e09053f961/contracts/token/ERC20/ERC20.sol
- OpenZeppelin SafeERC20.sol 固定提交 60a102ahttps://github.com/OpenZeppelin/openzeppelin-contracts/blob/60a102a65b3402aa899376d0da3819e09053f961/contracts/token/ERC20/utils/SafeERC20.sol
- Ethereum.org:JSON-RPC APIhttps://ethereum.org/developers/docs/apis/json-rpc/
- Go Ethereum:内置 EVM tracershttps://geth.ethereum.org/docs/developers/evm-tracing/built-in-tracers
- EIP-1014:CREATE2https://eips.ethereum.org/EIPS/eip-1014
- Uniswap v2 架构https://developers.uniswap.org/docs/protocols/v2/concepts/architecture
- Uniswap v2 池https://developers.uniswap.org/docs/protocols/v2/concepts/pools
- Etherscan:合约验证https://docs.etherscan.io/contract-verification/whats-contract-verification
- Solidity:合约元数据https://docs.soliditylang.org/en/latest/metadata.html
- ERC-1967 代理存储槽https://eips.ethereum.org/EIPS/eip-1967
- ERC-2612 签名授权https://eips.ethereum.org/EIPS/eip-2612
- EIP-712 类型化结构数据https://eips.ethereum.org/EIPS/eip-712