[H-02] close() 函数中的累积金额下溢允许耗尽通道存款

  • openai
  • 发布于 2026-02-19 15:34
  • 阅读 9

该文章详细描述了Machine Payments Protocol (MPP) 流支付通道实现中close()函数的一个整数下溢漏洞(H-02)。

[H-02] close() 函数中的累积金额下溢允许耗尽通道存款

由安全研究员提交

摘要

Machine Payments Protocol (MPP) 流支付通道实现中的 close() 函数包含一个整数下溢漏洞。当 voucher.cumulativeAmount 小于 channel.settled 时,delta 计算会下溢,可能允许攻击者耗尽通道中的所有资金。

漏洞详情

close() 函数中,支付 delta 的计算没有验证凭证的累积金额是否大于或等于已结算金额:

function close(
    Voucher calldata voucher,
    bytes calldata signature,
    bytes calldata payerSignature
) external nonReentrant {
    // ... 签名验证 ...

    channel.finalized = true;

    // H-02 漏洞:未检查 cumulativeAmount >= settled
    // 如果 voucher.cumulativeAmount < channel.settled,这将导致下溢
    uint256 delta = voucher.cumulativeAmount - channel.settled;

    // 下面易受攻击的检查未捕获下溢
    if (delta > 0 && delta <= channel.deposit) {
        channel.token.safeTransfer(channel.payee, delta);
    }

    // 这个计算也会下溢
    uint256 payerRefund = channel.deposit - voucher.cumulativeAmount;
    if (payerRefund > 0 && payerRefund <= channel.deposit) {
        channel.token.safeTransfer(channel.payer, payerRefund);
    }
}

影响

对基于 MPP 凭证的小额支付的严重影响:

  1. 完全耗尽通道:攻击者可以创建一个 cumulativeAmount 低于 channel.settled 的凭证,导致 delta 下溢到一个巨大的值(接近 $2^{256} - 1$)。

  2. TIP-20 代币盗窃:在 Tempo 的 HTTP 402 Payment Required LLM 代币计费工作流程中,这允许:

    • 恶意收款人窃取所有存入的 TIP-20 代币
    • 在较新的凭证已结算后重放旧凭证
  3. AI 代理支付漏洞利用:使用流支付通道进行计量推理服务的 AI 代理的全部预付余额可能被耗尽。

概念验证

// 设置:存入 10,000 个 TIP-20 代币的通道
// 已结算:通过之前的凭证结算了 5,000 个代币
channel.settled = 5000e6;

// 攻击:创建 cumulativeAmount < settled 的凭证
Voucher memory maliciousVoucher = Voucher({
    channelId: channelId,
    cumulativeAmount: 1000e6,  // 小于已结算金额!
    nonce: 100,
    expiry: block.timestamp + 1 hours
});

// 签署凭证(攻击者需要授权的签名者访问权限)
bytes memory signature = signVoucher(maliciousVoucher, signerPrivateKey);
bytes memory payerSig = signClose(channelId, 1000e6, payerPrivateKey);

// 执行攻击
// delta = 1000e6 - 5000e6 = 下溢至巨大数值
// payerRefund = 10000e6 - 1000e6 = 9000e6(支付给付款人)
channel.close(maliciousVoucher, signature, payerSig);

// 结果:攻击者通过下溢耗尽资金

MPP 上下文中的攻击场景

  1. LLM 服务消费者(AI 代理)使用 10,000 个 TIP-20 代币开通通道
  2. 消费者使用流支付进行推理,随时间结算 5,000 个代币
  3. 攻击者(恶意收款人或被攻破的签名者)创建仅包含 1,000 个代币的关闭凭证
  4. delta = 1000 - 5000 中的下溢会回绕到约 $2^{256}$
  5. 由于边界检查 delta <= channel.deposit,转账可能会失败,但是
  6. payerRefund 计算 10000 - 1000 = 9000 会将 9,000 个代币发送给付款人
  7. 最终结果:本应支付给收款人的 5,000 个代币被重定向

代码位置

建议

在算术操作之前添加显式边界检查:

function close(
    Voucher calldata voucher,
    bytes calldata signature,
    bytes calldata payerSignature
) external nonReentrant {
    // ... 现有验证 ...

    // 修复:验证累积金额不小于已结算金额
    if (voucher.cumulativeAmount < channel.settled) {
        revert CumulativeAmountTooLow();
    }

    channel.finalized = true;

    // 现在已避免下溢
    uint256 delta = voucher.cumulativeAmount - channel.settled;

    // 还要根据可用资金进行验证
    uint256 availableFunds = channel.deposit - channel.settled;
    if (delta > availableFunds) revert InsufficientDeposit();

    if (delta > 0) {
        channel.token.safeTransfer(channel.payee, delta);
    }

    uint256 payerRefund = channel.deposit - voucher.cumulativeAmount;
    if (payerRefund > 0) {
        channel.token.safeTransfer(channel.payer, payerRefund);
    }
}

参考文献

  • 原文链接: github.com/openai/fronti...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
openai
openai
江湖只有他的大名,没有他的介绍。