该文章详细描述了Machine Payments Protocol (MPP) 流支付通道实现中close()函数的一个整数下溢漏洞(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 凭证的小额支付的严重影响:
完全耗尽通道:攻击者可以创建一个 cumulativeAmount 低于 channel.settled 的凭证,导致 delta 下溢到一个巨大的值(接近 $2^{256} - 1$)。
TIP-20 代币盗窃:在 Tempo 的 HTTP 402 Payment Required LLM 代币计费工作流程中,这允许:
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);
// 结果:攻击者通过下溢耗尽资金
delta = 1000 - 5000 中的下溢会回绕到约 $2^{256}$delta <= channel.deposit,转账可能会失败,但是payerRefund 计算 10000 - 1000 = 9000 会将 9,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 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!