AIZPT攻击事件分析

本篇文章分析BNBSmartChain上的ERC314标准代币AIZPT的攻击事件。该攻击事件的根本原因是:AIZPT兑换BNB时,恒定乘积公式出现问题,导致可以获得更多的BNB。

0x00:背景介绍

昨天,从DeFiHackLabs的漏洞仓库中,了解到BNB Smart Chain上的ERC314标准代币AIZPT的攻击事件。

攻击Tx:https://bscscan.com/tx/0x5e694707337cca979d18f9e45f40e81d6ca341ed342f1377f563e779a746460d

目前找不到关于AIZPT代币的相关背景,猜测是一个土狗项目。

<br>

0x01:攻击流程

image-20241007100651497.png

<br>

首先,攻击者通过PancakeSwap利用闪电贷服务借了8000 WBNB,然后兑换成8000 BNB。

image-20241007094321454.png

<br>

随后,攻击者用8000 BNB调用AIZPT代币合约的buy函数去swap,攻击者得到805,227,658个AIZPT代币。(buy函数是通过receive()回调函数内部进行调用的)

image-20241007094953854.png

<br>

接着,攻击者大量调用sell函数(由transfer内部调用),每次调用将一部分的AIZPT代币swap回BNB。

image-20241007095917533.png

调用sell函数swap成的BNB数量,会逐渐减少:2431 -> 1473 -> 960 -> 660 ……

但攻击者总共得到了8039个BNB,偿还8004.1个给闪电贷后,获利34.9个BNB。

<br>

0x02:漏洞分析

在上述过程中,攻击者用8000 BNB购买成AIZPT代币,再将AIZPT代币出售回BNB,最终多了39个BNB。这其中到底发生了什么?让我们深入合约代码的buysell函数去看看

buy函数:

function buy() internal {
    require(tradingEnable, 'Trading not enable');
    // 用户发送的BNB数量
    uint256 swapValue = msg.value;
    // 根据恒定乘积公式,计算用户得到的AIZPT代币数量
    uint256 token_amount = (swapValue * _balances[address(this)]) / (address(this).balance);

    require(token_amount > 0, 'Buy amount too low');
    // 用户获得1/2的AIZPT代币
    uint256 user_amount = token_amount * 50 / 100;
    uint256 fee_amount = token_amount - user_amount;

    _transfer(address(this), msg.sender, user_amount);
    // 另外的1/2则是发送到feeReceiver, 应该是项目方的地址
    _transfer(address(this), feeReceiver, fee_amount);

    emit Swap(msg.sender, swapValue, 0, 0, user_amount);
}

代码逻辑很简单,根据恒定乘积公式进行swap,然后转移代币。1/2的代币发送到项目方地址,这应该是项目方的盈利手段。

sell函数:

function sell(uint256 sell_amount) internal {
    require(tradingEnable, 'Trading not enable');
    // 根据恒定乘积公式,计算用户得到的BNB数量
    uint256 ethAmount = (sell_amount * address(this).balance) / (_balances[address(this)] + sell_amount);

    require(ethAmount > 0, 'Sell amount too low');
    require(address(this).balance >= ethAmount, 'Insufficient ETH in reserves');
    // 将输入的AIZPT代币分成两份
    uint256 swap_amount = sell_amount * 50 / 100;
    uint256 burn_amount = sell_amount - swap_amount;
    // 一份转移回合约
    _transfer(msg.sender, address(this), swap_amount);
    // 一份进行销毁
    _transfer(msg.sender, address(0), burn_amount);
    // 发送BNB给用户
    payable(msg.sender).transfer(ethAmount);

    emit Swap(msg.sender, 0, sell_amount, ethAmount, 0);
}

在sell函数中,会把1/2的AIZPT代币销毁,但是发送给用户的BNB数量却是以所有的AIZPT代币数量进行计算的。这就是攻击发送的根本原因,AIZPT数量随着调用变少,恒定乘积公式将不再恒定。以至于后续用AIZPT兑换成的BNB将比预期更多,直至把池子掏空。

<br>

0x03:总结

该攻击事件的根本原因是:AIZPT兑换BNB时,恒定乘积公式出现问题,导致可以获得更多的BNB。在对攻击事件分析时,当站在攻击者的角度,会发现更多的攻击细节和疑惑点:

  1. 为什么是8000 BNB?是通过计算得来的吗?如何得到最优解呢?
  2. 每次调用sell,为什么是发送3000k个AIZPT代币?是否是考虑迭代次数的问题,以至于可以在一次交易中执行完成?
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
Blockchain Hunter
Blockchain Hunter
分享区块链安全、智能合约安全,偶尔也会携带点套利小知识 : )