Closed howlbot-integration[bot] closed 2 months ago
trust1995 changed the severity to 2 (Med Risk)
trust1995 marked the issue as satisfactory
Hi @trust1995, thanks for judging!
This report and #85 describe the same issue, which I think is different from #55.
According to the C4 rule, if fixing the Root Cause (in a reasonable manner) would cause the finding to no longer be exploitable, then the findings are duplicates
. Yet, the fix of #55 does not fix the issue described by this report and #85. Therefore, based on the C4 rule, would this report and #85 be reconsidered as a separate valid issue?
trust1995 marked the issue as not a duplicate
trust1995 marked the issue as duplicate of #85
Agreed, separated out the other issues.
trust1995 changed the severity to 3 (High Risk)
Lines of code
https://github.com/code-423n4/2024-06-thorchain/blob/5b91b5c6683a222b0ce046533515e301c9699d74/chain/ethereum/contracts/THORChain_Router.sol#L131-L140 https://github.com/code-423n4/2024-06-thorchain/blob/5b91b5c6683a222b0ce046533515e301c9699d74/chain/ethereum/contracts/THORChain_Router.sol#L143-L160 https://github.com/code-423n4/2024-06-thorchain/blob/5b91b5c6683a222b0ce046533515e301c9699d74/chain/ethereum/contracts/THORChain_Router.sol#L185-L207 https://github.com/code-423n4/2024-06-thorchain/blob/5b91b5c6683a222b0ce046533515e301c9699d74/chain/ethereum/contracts/THORChain_Router.sol#L209-L238
Vulnerability details
Impact
An attacker can call the following
depositWithExpiry
function with an address controlled by him as thevault
input. After the_deposit
function below is called, he has sent theamount
tokens to the router, and_vaultAllowance[vault][asset]
for his controlled address has increased by theamount
. This is problematic when theasset
is a "vault-like" token, such as stETH that needs to be supported by this protocol according to this protocol's token whitelist.https://github.com/code-423n4/2024-06-thorchain/blob/5b91b5c6683a222b0ce046533515e301c9699d74/chain/ethereum/contracts/THORChain_Router.sol#L131-L140
https://github.com/code-423n4/2024-06-thorchain/blob/5b91b5c6683a222b0ce046533515e301c9699d74/chain/ethereum/contracts/THORChain_Router.sol#L143-L160
As shown by the
StETH
contract's functions below, calling theStETH.transferFrom
function, which eventually calls theStETH.getSharesByPooledEth
function, updates the stETH holders' shares instead of updating their balances directly. The stETH holders'shares
are stored in theStETH
contract, and according to theStETH.balanceOf
function, their stETH balances corresponding to theirshares
are dynamic depending on the total pooled Ether and total shares for theStETH
contract. After the attacker'sdepositWithExpiry
function call, the router'sshares
is increased by a share amount that corresponds to theamount
stETH tokens based on the total pooled Ether and total shares for theStETH
contract at the moment of the attacker's deposit. Subsequently, more deposits can occur for legitimate vaults, and the router's stETH shares are further increased.https://etherscan.io/address/0x17144556fd3424edc8fc8a4c940b2d04936d17eb#code#F27#L237
https://etherscan.io/address/0x17144556fd3424edc8fc8a4c940b2d04936d17eb#code#F27#L375
https://etherscan.io/address/0x17144556fd3424edc8fc8a4c940b2d04936d17eb#code#F27#L300
https://etherscan.io/address/0x17144556fd3424edc8fc8a4c940b2d04936d17eb#code#F27#L441
https://etherscan.io/address/0x17144556fd3424edc8fc8a4c940b2d04936d17eb#code#F27#L166
https://etherscan.io/address/0x17144556fd3424edc8fc8a4c940b2d04936d17eb#code#F27#L309
When more on chain interactions with the
StETH
contract happen, the total pooled Ether and total shares for theStETH
contract are changed; after such change, based on theStETH.getSharesByPooledEth
function, theamount
stETH tokens can be equivalent to an stETH share amount that is higher than the router's stETH share increment for the attacker's deposit of the sameamount
stETH tokens. Then, the attacker can use his controlled address to call the followingtransferOut
or_transferOutV5
function to send all of the_vaultAllowance
for his controlled address, which equals theamount
, to himself. As shown below, sinceStETH.transfer
function also eventually calls theStETH.getSharesByPooledEth
function, for the sameamount
stETH tokens, the attacker would receive an stETH share amount that is higher than what was removed from him for his deposit; in this case, the extra stETH shares sent to the attacker should belong to the legitimate vaults. As a result, the attacker has stolen some of the stETH shares that should be controlled by the legitimate vaults.https://github.com/code-423n4/2024-06-thorchain/blob/5b91b5c6683a222b0ce046533515e301c9699d74/chain/ethereum/contracts/THORChain_Router.sol#L185-L207
https://github.com/code-423n4/2024-06-thorchain/blob/5b91b5c6683a222b0ce046533515e301c9699d74/chain/ethereum/contracts/THORChain_Router.sol#L209-L238
https://etherscan.io/address/0x17144556fd3424edc8fc8a4c940b2d04936d17eb#code#F27#L185
Proof of Concept
Using the
StETH
contract's following example, the following steps can occur for the described scenario.https://etherscan.io/address/0x17144556fd3424edc8fc8a4c940b2d04936d17eb#code#F27#L19
StETH
contract.user1
calls thedepositWithExpiry
function with his controlled address as thevault
input to deposit 2 stETH, which is equivalent to 100 stETH shares.user2
calls thedepositWithExpiry
function with a legitimate vault as thevault
input to also deposit 2 stETH, which is equivalent to 100 stETH shares as well.StETH
contract occur, the total pooled Ether changes to 19 ETH and total share amount changes to 1000 for theStETH
contract.user1
uses his controlled address to call thetransferOut
function to transfer 2 stETH to himself._vaultAllowance
for his controlled address was 2 stETH before thistransferOut
function call.user1
receives2 * 1000 / 19 = 105
stETH shares and unfairly gains 5 more stETH shares because only 100 stETH shares should belong to him.200 - 105 = 95
stETH shares.user1
has stolen these 5 stETH shares from the legitimate vault.Tools Used
Manual Review
Recommended Mitigation Steps
The
depositWithExpiry
function can be updated to revert if thevault
input does not correspond to a legitimate vault. Moreover, for "vault-like" tokens like stETH, the router can be updated to store the respective_vaultAllowance
by accumulating and decumulating share amounts instead of token amounts and transfer the respective token shares from the router when needed.Assessed type
ERC20