攻击交易:
攻击交易较多选择其一(https://etherscan.io/address/0x6162759edad730152f0df8115c698a42e666157f)
https://etherscan.io/tx/0x254735c6c14e4d338b1cc5bca43aab6b0f395ae06085013b1b2527180d270a31
合约代码:
Comptroller::https://etherscan.io/address/0xe16db319d9da7ce40b666dd2e365a4b8b3c18217#code
dai池:https://etherscan.io/address/0x67db14e73c2dce786b5bbbfa4d010deab4bbfcf9#code
eth池:https://etherscan.io/address/0xd77e28a1b9a9cfe1fc2eee70e391c05d25853cbf#code
分析工具:
https://oko.palkeo.com/0x254735c6c14e4d338b1cc5bca43aab6b0f395ae06085013b1b2527180d270a31/
分析参考文章:
https://twitter.com/Hacxyk/status/1520370421773725698
在eth池中如果调用borrow会调用doTransferOut(borrower, borrowAmount);
function borrowFresh(address payable borrower, uint borrowAmount) internal returns (uint) {
......
doTransferOut(borrower, borrowAmount);
/* We write the previously calculated values into storage */
accountBorrows[borrower].principal = vars.accountBorrowsNew;
accountBorrows[borrower].interestIndex = borrowIndex;
totalBorrows = vars.totalBorrowsNew;
.......
}
function doTransferOut(address payable to, uint amount) internal {
// Send the Ether and revert on failure
(bool success, ) = to.call.value(amount)("");
require(success, "doTransferOut failed");
}
会回调到调用者的默认回调函数.之后再更新borrow的值.
如果在回调函数中调用comptroller中的exitMarket
函数,(在没更新borrow值时,删除marketToExit.accountMembership[msg.sender]),即可绕过满足borrow的提前条件(质押一定量的其他token)的提取操作的验证操作
function redeemAllowedInternal(address cToken, address redeemer, uint redeemTokens) internal view returns (uint) {
if (!markets[cToken].isListed) {
return uint(Error.MARKET_NOT_LISTED);
}
/* If the redeemer is not 'in' the market, then we can bypass the liquidity check */
if (!markets[cToken].accountMembership[redeemer]) {
return uint(Error.NO_ERROR); ///*******************在此返回
}
/* Otherwise, perform a hypothetical liquidity check to guard against shortfall */
(Error err, , uint shortfall) = getHypotheticalAccountLiquidityInternal(redeemer, CToken(cToken), redeemTokens, 0);
if (err != Error.NO_ERROR) {
return uint(err);
}
if (shortfall > 0) {
return uint(Error.INSUFFICIENT_LIQUIDITY);
}
return uint(Error.NO_ERROR);
}
攻击流程:
- dai池
mint
(质押)大量token. - eth池
borrow
Eth;
在回调函数中调用(comptroller
)exitmarket();
3.调用(dai
)redeemUnderlying取回质押的token;