25921 - [SC - Insight] Flaw in upgradeToAndCall leads to the proxy cal...

Submitted on Nov 21st 2023 at 03:11:43 UTC by @neth for Boost | DeGate

Report ID: #25921

Report type: Smart Contract

Report severity: Insight

Target: https://etherscan.io/address/0x54D7aE423Edb07282645e740C046B9373970a168#code

Impacts:

  • Contract fails to deliver promised returns, but doesn't lose value

Description

Bug Description

In OwnedUpgradeabilityProxy, function upgradeToAndCall

  function upgradeToAndCall(address implementation, bytes memory data) payable public onlyProxyOwner {
    upgradeTo(implementation);
    (bool success, ) = address(this).call{value: msg.value}(data);
    require(success);
  }

calls himself by doing address(this).call..., which redirects to the fallback function in Proxy with msg.sender == address(this), instead of directly delegatecalling to the implementation with the caller being Timelock, which is bad as proxies are not supposed to "initiate" transactions, but delegate them.

Impact

In the implementation, the owner is responsible for calling setCheckBalance, which is, at the moment, an EOA (see https://etherscan.io/address/0xacD3A62F3eED1BfE4fF0eC8240d645c1F5477F82) but it seems it will be Timelock in the future. That means it is NOT, by any means, the proxy, so trying to update the implementation via upgradeToAndCall will revert, as the modifier will check for msg.sender == owner with owner != address(proxy).

The same applies to ExchangeProxy

Recommendation

Proof of concept

(Simplified POC, if you need the mainnet fork I can give it to you but it was far more verbose)

Last updated

Was this helpful?