# EGD_finance Reentry **Published by:** [Fuzzingq](https://paragraph.com/@liusy/) **Published on:** 2023-11-27 **URL:** https://paragraph.com/@liusy/egd-finance-reentry ## Content 背景 2022年08月07日 BSC链上智能合约EGD_finance受到重入攻击被黑,攻击者操纵了类似于质押奖励价格从而获取了高额奖励。 EGD_finance contract address: 0x93c175439726797dcee24d08e4ac9164e88e7aee 攻击TX: 0x50da0b1b6e34bce59769157df769eb45fa11efc7d0e292900d6b0a86ae66a2b3 分析 问题出现在EGD_finance合约中的claimAllReword()函数中,函数实现如下:可以看到合约会根据用户质押的代币数量:userInfo[msg.sender].userStakeList 质押时间:block.timestamp - info.claimTime 以及一个比例量 info.rates 来计算用户可以获得的代币奖励: function claimAllReward() external { require(userInfo[msg.sender].userStakeList.length > 0, 'no stake'); require(!black[msg.sender],'black'); uint[] storage list = userInfo[msg.sender].userStakeList; uint rew; uint outAmount; uint range = list.length; for (uint i = 0; i < range; i++) { UserSlot storage info = userSlot[msg.sender][list[i - outAmount]]; require(info.totalQuota != 0, 'wrong index'); uint quota = (block.timestamp - info.claimTime) * info.rates; if (quota >= info.leftQuota) { quota = info.leftQuota; } rew += quota * 1e18 / getEGDPrice(); // 这一行是计算奖励的核心 info.claimTime = block.timestamp; info.leftQuota -= quota; info.claimedQuota += quota; if (info.leftQuota == 0) { userInfo[msg.sender].totalAmount -= info.totalQuota; delete userSlot[msg.sender][list[i - outAmount]]; list[i - outAmount] = list[list.length - 1]; list.pop(); outAmount ++; } } userInfo[msg.sender].userStakeList = list; EGD.transfer(msg.sender, rew); userInfo[msg.sender].totalClaimed += rew; emit Claim(msg.sender,rew); } } 具体的计算公式为: rew += quota * 1e18 / getEGDPrice(); 也就是说,getEGDPrice()所获得的值越小,用户获得的奖励数量rew就越大。所以就可以看下getEGDPrice()的实现:这里的实现非常简单,仅仅是计算了EGD-USD这个交易对pair中存储的EGD和USD的数量并作除法。所以要想减小getEGDPrice()的值,有两个办法: 增加池子中EGD token的数量 减少池子中USD token的数量 function getEGDPrice() public view returns (uint){ uint balance1 = EGD.balanceOf(pair); uint balance2 = U.balanceOf(pair); return (balance2 * 1e18 / balance1); } 而我们又知道,EGD-USD这个合约对是一个pancakeswap pair因此,他是继承有闪电贷swap函数并具有闪电贷功能的,具体实现可以见pancakeswap合约: PancakePair.sol 所以 如果我们通过闪电贷的方法从池子中借出usd token并在调用合约中实现pancakeCall方法并立马执行EGD_finance的claimAllreward方法获取奖励,这时候由于EGD-USD pair中被借出了大量的USD导致getPrice获取的价格被操纵。 通过这种方式,攻击者可以获取远超预期的EGD token奖励,之后再归还闪电贷使getPrice的价格恢复即可。 整体流程为: 1.Attack合约调用 EGD_USD pair合约,借出大量USD,并触发回调pancakeCall 2.getprice()由于USD数量减少而减小 3.在pancakeCall中调用EGD_finance合约的claimAllReward获取奖励 4.在pancakeCall中归还EGD_USD pair合约中借出的USD以及利息(0.3%) 5.getprice()价格回归正常 6.攻击者卖出EGD token获利 可以参考: https://explorer.phalcon.xyz/tx/bsc/0x50da0b1b6e34bce59769157df769eb45fa11efc7d0e292900d6b0a86ae66a2b3 ## Publication Information - [Fuzzingq](https://paragraph.com/@liusy/): Publication homepage - [All Posts](https://paragraph.com/@liusy/): More posts from this publication - [RSS Feed](https://api.paragraph.com/blogs/rss/@liusy): Subscribe to updates - [Twitter](https://twitter.com/_fuzzingq): Follow on Twitter