code4rena-2021-06-pooltogether-h02
[H-02] YearnV2YieldSource wrong subtraction in withdraw
Summary
출금할 시 계산 식이 잘못되어 underflow가 발생, 출금이 불가하다.
Keyword
bug, logic flaw, overflow/underflow
Vulnerability
redeemToken 함수는 외부 투자 풀(Yearn V2 Vaults)에서 토큰을 출금하고, 다시 그 토큰을 호출자에게 전달하는 함수이다. _withdrawFromVault 함수는 외부 투자 풀(Yearn V2 Vaults)에서 토큰을 출금한 뒤 출금된 토큰 양을 리턴해야 한다.
function redeemToken(uint256 amount) external override nonReentrant returns (uint256) {
uint256 shares = _tokenToShares(amount);
uint256 withdrawnAmount = _withdrawFromVault(amount);
_burn(msg.sender, shares);
token.safeTransfer(msg.sender, withdrawnAmount);
emit RedeemedToken(msg.sender, shares, amount);
return withdrawnAmount;
}
function _withdrawFromVault(uint amount) internal returns (uint256) {
uint256 yShares = _tokenToYShares(amount);
uint256 previousBalance = token.balanceOf(address(this));
// we accept losses to avoid being locked in the Vault (if losses happened for some reason)
if(maxLosses != 0) {
vault.withdraw(yShares, address(this), maxLosses);
} else {
vault.withdraw(yShares);
}
uint256 currentBalance = token.balanceOf(address(this));
return previousBalance.sub(currentBalance);
}하지만 _withdrawFromVault의 리턴값을 보면 return previousBalance.sub(currentBalance);로, 풀에서 출금하기 전 컨트랙트의 잔고에서 풀에서 출금 후 컨트랙트의 잔고를 빼고 있다. 외부 투자 풀(Yearn V2 Vaults)에서 토큰을 빼내어 컨트랙트로 가져온다면 currentBalance >= previousBalance 일 것이다. 따라서 언더플로우가 발생하고, SafeMath로 인해 revert 될 것이다.
애초에 계산이 반대로 되었다. currentBalance - previousBalance를 리턴하는 게 맞다.
Impact
underflow가 발생해 revert 되고, 출금이 불가하다. 프로토콜이 동작하지 않는다.
Mitigation
_withdrawFromVault 에서 currentBalance > previousBalance ? currentBalance - previousBalance : 0 를 리턴한다.
tags: bughunting, pooltogether, smart contract, solidity, logic flaw, integer overflow underflow, severity high