# EGD_finance Reentry

By [Fuzzingq](https://paragraph.com/@liusy) · 2023-11-27

---

### 背景

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()的值，有两个办法：

1.  增加池子中EGD token的数量
    
2.  减少池子中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](https://storage.googleapis.com/papyrus_images/1bd82ffdac49f767dc1f4e75d00e048bafbdf7e01c18947b30e1e66ac68a9345.png)

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](https://explorer.phalcon.xyz/tx/bsc/0x50da0b1b6e34bce59769157df769eb45fa11efc7d0e292900d6b0a86ae66a2b3)

![](https://storage.googleapis.com/papyrus_images/ca9d01c68254ab5e452ff90cfb98abe9f1efd095e972779b8a11404294cde795.png)

---

*Originally published on [Fuzzingq](https://paragraph.com/@liusy/egd-finance-reentry)*
