Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OOG attack analysis #26

Merged
merged 4 commits into from
Jun 25, 2024
Merged

OOG attack analysis #26

merged 4 commits into from
Jun 25, 2024

Conversation

pmerkleplant
Copy link
Member

@pmerkleplant pmerkleplant commented Jun 17, 2024

Intro

External calls can be wrapped into try-catch blocks leading to the following behaviour:

  • catch is executed if the call reverted or ran into OOG (out-of-gas)
  • the whole block reverts if the returndata decoding fails. This is only possible if proxies are called (not the case for Aggor)

Note that OOG is (partially) controlled by the user, therefore a user may be able to manipulate the execution path towards the catch path. However, note that users can only control the gas of the full tx, ie not on a "per try-catch block" basis.

SparkLend's CappedFallbackRateSource

In SparkLend's CappedFallbackRateSource.sol this leads to an issue because the whole function's execution is just the try-catch block. Importantly, if the catch path is executed a default value is returned.

Therefore, a user can provide just too little gas to prevent the external call to run into OOG, but still enough for the whole function to return - in this case the default value.

Note that a standard Solidity call forwards 63/64 of the available gas to the called contract. The 63/64 may not be enough for the external call- leading to OOG, while the 1/64 may be enough to terminate the function afterwards - leading to a non-failed execution.

Aggor

Both Oracles, Chronicle and Chainlink, are non-proxies (as in separating storage address and implementation) and for both the gas usage is capped.

Note, however, that Chainlink is using a "forwarding proxy". This means they could update their aggregator contract to an implementation that has uncapped gas usage. Nevertheless, this seems unlikely.

This PR adds a couple of unit and integration tests to further define Aggor's behaviour wrt to capped gas usage.

The unit tests prove that any gas provided less than necessary leads to a normal OOG revert in Aggor.

The integration tests prove that it is not possible to provide such an amount of gas that the first oracle is read (Chronicle) but reading the second (Chainlink) fails due to OOG, while at the same time there's still enough gas left to finish Aggor's execution and returning just the Chronicle value. If this would be possible it would mean an attacker can manipulate Aggor's value derivation path via gas capping.

Copy link

@hexonaut hexonaut left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good. Two minor issues.

test/Aggor.t.sol Outdated Show resolved Hide resolved
test/Aggor.t.sol Outdated Show resolved Hide resolved
@pmerkleplant
Copy link
Member Author

Update re: TWAP OOG manipulation

I initially thought the TWAP call is also wrapped in a try-catch which would need an analysis as well. However, looking more closely again the TWAP call is a normal external call and therefore not applicable to this analysis.

@pmerkleplant pmerkleplant merged commit b041b8a into main Jun 25, 2024
3 checks passed
@pmerkleplant pmerkleplant deleted the ooo-try-catch-attack branch June 25, 2024 11:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants