Beosin 解析 Uniswap v4 Hook 攻击向量与检测方法

Beosin 解析 Uniswap v4 Hook 攻击向量与检测方法

N
News Editor
2026-10-16 09:39:42
Beosin 安全团队围绕 Uniswap v4 Hook 的风险机制作出系统梳理,指出 Hook 可在池子初始化、增删流动性、Swap 和 Donate 等环节插入自定义逻辑。文章援引 0x Protocol 9 月对 6 条链上 84,163 个 Uniswap v4 Hook 的分析结果称,仅 19.4% 被判定为安全,54.2% 被归类为恶意,26.4% 存在疑似恶意行为。文中拆解了隐性交易费、地址差异化费率、重入与外部回调、瞬时价格操纵、阻止 LP 退出及 Gas 消耗攻击,并给出权限位检查、代码核验、初始化交易审查和边界场景模拟等检测思路。

Beosin 安全团队发文称,近期 Robinhood Chain 热度上升,吸引了大量用户在其链上的 Uniswap 进行交易。一种典型风险场景是,用户看到某个 Uniswap v4 池子显示 0% 手续费,报价还比市场最优价格低几个基点,于是将其选为最佳路由,但交易完成后实际收到的代币却比报价少了接近 1%。链上数据检查后可以发现,损失来自隐藏在 Hook 合约中的「暗税」,Hook 借助 afterSwapReturnsDelta 权限在交易结算前截留了一部分代币。

文章还提到,9 月流动性聚合基础设施 0x Protocol 对 6 条链上的 84,163 个 Uniswap v4 Hook 进行了静态分析、动态分析和实际成交观察,结果显示,仅 19.4% 的 Hook 被判定为安全,54.2% 被归类为恶意,另有 26.4% 存在疑似恶意行为。Beosin 表示,本文旨在拆解 Uniswap v4 Hook 的攻击向量,帮助用户和开发者理解其中可能存在的恶意行为。

Uniswap Hook 机制与主要风险点

在 Uniswap v4 中,流动性池由 PoolManager 统一管理。Hook 合约可以在池子初始化、添加流动性、移除流动性、Swap 和 Donate 等生命周期节点插入自定义逻辑,包括修改交易费、交易前后余额以及结算逻辑。

Beosin 认为,相关安全风险主要集中在以下几个位置:

  • Hook 返回异常的余额变化;
  • Hook 在回调中调用外部合约;
  • Hook 读取瞬时价格并据此决定费率;
  • Hook 保存跨池、跨用户的状态;
  • Hook 利用回调顺序和交易回滚机制制造拒绝服务。

文章称,攻击者可能先建立一个表面正常的流动性池,并在 Hook 中加入隐藏收费或黑名单逻辑,再通过前端、空投、聚合器或社交媒体吸引用户。等到用户开始交易或提供流动性后,攻击者便可借助自定义逻辑或外部调用恶意获取其他用户资产。

按 Beosin 的总结,目前常见的恶意 Hook 形式包括:

  • 每次交易抽取少量额外费用;
  • 对特定地址收取不同费率;
  • 在价格接近某个阈值时突然改变行为;
  • 让流动性提供者无法移除流动性;
  • 通过回调消耗大量 Gas,导致兑币交易失败;
  • 诱导用户调用假冒的 unlock、settle 或 token 转账函数。

恶意 Hook 示例解析

1. 隐性交易费

文中给出的第一个示例是「对指定地址收取额外费用」的 Hook 逻辑。开发者可通过 privilegedUsers 为自己、做市商或指定机器人设置免手续费,其他用户则要承担额外交易费用。

示例合约 SuspiciousFeeHook 包含 manager、feeRecipient 以及 privilegedUsers 映射。其 beforeSwap 在校验调用者为 manager 后,如果 sender 属于 privilegedUsers,则直接返回 amountIn;若不在白名单内,则计算 hiddenFee = amountIn * 30 / 10_000,并将 adjustedAmountIn 设为 amountIn - hiddenFee,随后再通过 IERC20(token()).transferFrom(sender, feeRecipient, hiddenFee) 扣走隐藏费用。

Beosin 指出,在真实的 v4 架构中,Hook 通常不能任意绕过 PoolManager 的结算规则,但仍可以借助自定义 delta、外部代币调用或池配置影响最终结算。因此,审计的重点是检查 Hook 所有余额变化路径。

2. 动态价格或费率

第二个示例 AddressBasedHook 展示了基于地址施加差异化费率的风险。合约中包含 blocked 黑名单映射和 customFee 映射。beforeSwap 在检测到 blocked[sender] 为真时会直接 revert「blocked trader」。若 customFee[sender] 不为 0,则返回该地址对应的费率;否则返回 10_000,代码注释中将其标记为默认 100%。

这类代码同时具备黑名单机制和按用户地址设定不同费率的能力。如果前端没有完整展示费率,用户看到的池子条件就可能与实际交易条件不一致。文章提醒,在审计或开发阶段,必须确认所有费率返回值都满足协议允许范围,而不能只检查常规路径。

3. 重入和外部回调

第三类风险来自重入和外部回调。示例合约 ReentrantHook 设有 callbackTarget 和 entered。其 beforeSwap 在 require(!entered, "reentered") 通过后,将 entered 置为 true,随后调用 ICallback(callbackTarget).onSwap(sender),最后再将 entered 设回 false。

Beosin 称,Hook 中的外部调用可能触发多种链上回调,包括:

  • ERC-777 或自定义 ERC-20 回调;
  • ERC-721 / ERC-1155 接收回调;
  • 借贷协议回调;
  • 聚合器回调;
  • 当前 Hook 的再次调用;
  • 其他池子的 Swap。

如果状态更新与外部调用的先后顺序处理错误,可能导致重复计算结果、绕过单次交易限制、重复领取手续费、跨池状态污染,以及价格或额度检查失效。文章特别指出,v4 核心合约虽然有自己的解锁和结算约束,但这并不意味着 Hook 可以安全地执行任意外部调用,每个 Hook 都需要单独建立安全边界。

4. 利用瞬时价格进行预言机操纵

第四个示例 FragileOracleHook 聚焦于把当前池子的瞬时价格当作可信预言机使用的风险。合约中记录 lastObservedPrice,beforeSwap 会根据 currentSqrtPriceX96 计算出 spotPrice = priceFromSqrtPrice(currentSqrtPriceX96),若 spotPrice 大于 1_100e18,则触发 triggerLiquidation(),之后再把 lastObservedPrice 更新为 spotPrice。

Beosin 表示,攻击者可以在同一笔交易中借助闪电贷获得大量资产,再对目标池进行大额 Swap,把瞬时价格推向极端,进而触发 Hook 中的清算、奖励或抵押品估值逻辑。如果 Hook 把当前池价格直接视为可信预言机,攻击者就可能在一个区块内完成操纵。

5. 阻止流动性退出

第五类风险是阻止 LP 退出。示例合约 ExitBlockingHook 维护 blockedLP 映射。beforeRemoveLiquidity(address provider) 在检测到 blockedLP[provider] 为真时会 revert「withdraw disabled」;同时,setExitLock(address user, bool locked) 可由 onlyOwner 调用,用于修改 blockedLP[user]。

这类 Hook 可以允许用户加入流动性,但在移除流动性时设置障碍。文章列举的常见触发条件包括:

  • 用户地址被加入黑名单;
  • 池子达到某个 TVL;
  • 某个时间戳之后;
  • Hook 管理员调用隐藏开关;
  • 用户曾通过聚合器交易;
  • 用户没有支付额外费用。

6. Gas 消耗攻击

第六类是 Gas Griefing。Beosin 提到,这种攻击在以往合约攻击中同样常见,攻击者通过在交易过程中消耗异常 Gas,直接导致交易失败。

示例合约 GasGriefHook 的 beforeSwap(uint256 n) 中使用 for 循环,从 i = 0 执行到 i < n,并在每轮调用 keccak256(abi.encodePacked(i, msg.sender))。

更隐蔽的形式还包括:

  • 遍历持续增长的地址数组;
  • 清理历史用户状态;
  • 对大量池子逐一查询余额;
  • 在失败前执行大量计算;
  • 调用多个恶意外部合约。

如何检测恶意 Hook

1. 检查 Hook 地址权限位

文章建议,首先确认 Hook 地址声明了哪些回调权限,并与实际字节码中的函数进行对比。如果地址声明了 beforeSwap、afterSwap、beforeAddLiquidity、beforeRemoveLiquidity,就需要逐一分析这些对应函数。

2. 获取代码并核查实现

Beosin 提到,可以借助区块浏览器或 RPC 调用 eth_getCode(hookAddress) 获取代码,并重点检查以下问题:

  • 是否为代理合约;
  • 是否存在升级入口;
  • 是否存在自毁逻辑;
  • 是否包含未知外部调用;
  • 是否与已验证源码一致。

3. 检查流动性池初始化交易

在初始化交易层面,需要重点查看 PoolKey、currency0 / currency1、fee、tick spacing、Hook 地址、初始化地址、管理员以及资金接收地址。

4. 模拟边界场景

文章建议至少覆盖以下场景:正常 Swap、极小金额的 Swap、大额 Swap、零金额 Swap、价格极端变化、重复 Swap、添加流动性后立即移除、Hook 管理员变更、代币转账失败以及外部调用回调。

在这些模拟中,应比较用户实际支付和实际收到的代币数量、Hook 余额变化、PoolManager delta、事件记录以及 Gas 消耗。

Beosin 观点与文末提示

Beosin 在结语中表示,Uniswap v4 Hook 的目标是提升 Uniswap 的可扩展性,但同时也带来了新的攻击面和被恶意利用的可能。对普通用户来说,判断 Hook 安全性的关键标准在于:该 Hook 是否经过验证、源码是否公开、权限是否受限。

对整个 DeFi 生态而言,文章称,DeFi 协议和安全公司需要采取更多措施,包括提供检测工具以及加强对流动性池的审查,以提升链上交易的安全性和可靠性。

文末还给出拓展阅读《Uniswap v4 Hook 解析:架构设计、常见漏洞与防护实践》。

免责声明部分写道,市场有风险,投资需谨慎。本文不构成投资建议,用户应考虑文中的任何意见、观点或结论是否符合其特定状况,并自行承担据此投资的责任。

本文最初由 Bit.Fan 发布。 欲了解更多加密货币新闻与市场洞察,请访问 www.bit.fan.
100

免责声明:

本平台展示的市场信息、项目资料与第三方内容仅用于行业信息分享,不构成任何形式的投资建议或收益承诺。

加密资产交易具有较高风险,用户应充分评估自身风险承受能力并独立作出决策,相关盈亏及法律责任由用户自行承担。