code4rena-2023-09-ondo-m04
[M-04] Admin can’t burn tokens from blocklisted addresses because of a check in _beforeTokenTransfer
Summary
악성 유저는 허용 리스트에 없고, 차단/제재 리스트에 있을 것이다. 허용/블락/제재 리스트 확인에서 걸려서 관리자 함수로 악성 유저의 토큰을 소각할 수 없다.
Keyword
bug, logic flaw, erc20
Vulnerability
burn 함수는 관리자가 악성 유저의 rUSDY를 소각하는 함수이다. 이들 악성 유저는 허용 리스트에 없고, 차단/제재 리스트에 있을 것이다.
function burn(
address _account,
uint256 _amount
) external onlyRole(BURNER_ROLE) {
uint256 sharesAmount = getSharesByRUSDY(_amount);
@> _burnShares(_account, sharesAmount);
usdy.transfer(msg.sender, sharesAmount / BPS_DENOMINATOR);
emit TokensBurnt(_account, _amount);
}
function _burnShares(
address _account,
uint256 _sharesAmount
) internal whenNotPaused returns (uint256) {
require(_account != address(0), "BURN_FROM_THE_ZERO_ADDRESS");
@> _beforeTokenTransfer(_account, address(0), _sharesAmount);
uint256 accountShares = shares[_account];
require(_sharesAmount <= accountShares, "BURN_AMOUNT_EXCEEDS_BALANCE");
uint256 preRebaseTokenAmount = getRUSDYByShares(_sharesAmount);
totalShares -= _sharesAmount;
shares[_account] = accountShares - _sharesAmount;
uint256 postRebaseTokenAmount = getRUSDYByShares(_sharesAmount);
return totalShares;
}토큰을 소각할 시 _beforeTokenTransfer(_account, address(0), _sharesAmount)를 호출한다. _account는 토큰을 빼앗길 악성 유저이다. 이 _account는 블락/제재 리스트에 있거나 허용 리스트에 없으므로 _beforeTokenTransfer의 리스트 확인에 걸려 소각할 수 없다.
function _beforeTokenTransfer(
address from,
address to,
uint256
) internal view {
// Check constraints when `transferFrom` is called to facliitate
// a transfer between two parties that are not `from` or `to`.
if (from != msg.sender && to != msg.sender) {
require(!_isBlocked(msg.sender), "rUSDY: 'sender' address blocked");
require(!_isSanctioned(msg.sender), "rUSDY: 'sender' address sanctioned");
require(
_isAllowed(msg.sender),
"rUSDY: 'sender' address not on allowlist"
);
}
@> if (from != address(0)) {
// If not minting
@> require(!_isBlocked(from), "rUSDY: 'from' address blocked");
@> require(!_isSanctioned(from), "rUSDY: 'from' address sanctioned");
@> require(_isAllowed(from), "rUSDY: 'from' address not on allowlist");
}
if (to != address(0)) {
// If not burning
require(!_isBlocked(to), "rUSDY: 'to' address blocked");
require(!_isSanctioned(to), "rUSDY: 'to' address sanctioned");
require(_isAllowed(to), "rUSDY: 'to' address not on allowlist");
}
}Impact
악성 유저의 토큰을 소각할 수 없다.
Mitigation
_beforeTokenTransfer 에서 if (from != address(0)) 대신 if (from != address(0) && to != address(0)) 로 확인하여 토큰 소각시에는 리스트를 확인하지 않는다.
tags: bughunting, ondo finance, smart contract, solidity, logic flaw, erc20, severity medium