背景介绍

近期,我们监控到一起针对 BNB Smart Chain 的链上攻击事件,

https://bscscan.com/tx/0xd4c7c11c46f81b6bf98284e4921a5b9f0ff97b4c71ebade206cb10507e4503b0

被攻击的项目为Bankroll Network 的DeFi项目。

攻击及事件分析

首先,攻击者通过 pancakeSwap 利用 flash 借了 16,000 WBNB ,

零时科技 || Bankroll 攻击事件分析

随后,调用 Bankroll 的 buyfor 函数,将闪电贷获得的 16000 WBNB 购买了 Bankroll 的 share ,类似于质押。

零时科技 || Bankroll 攻击事件分析

接着,攻击者大量调用 buyfor 函数,使 Bankroll 自己的合约购买 Bankroll 的 share。

零时科技 || Bankroll 攻击事件分析

我们看一下 buyfor 函数的定义,如下图:

零时科技 || Bankroll 攻击事件分析

首先,函数从 _customerAddress 将 token 转入当前合约,其中 token 为 WBNB 。随后,调用purchaseTokens 购买 share ,最后调用 distribute 函数。

我们看一下该函数的定义:

零时科技 || Bankroll 攻击事件分析

在该函数中,会更新 profitPerShare_ ,该值为拥有一个 share 的利润。然后,通过 sell 函数将最开始利用 buyfor 转入 WBNB 获取的所有 share 卖出,再通过 Withdraw提取所有的 WBNB 。

我们看一下 sell 函数的定义:

零时科技 || Bankroll 攻击事件分析

可以看到, payoutsTo_[_customerAddress] 和 profitPerShare_ 的关系为, profitPerShare_越大, payoutsTo_[_customerAddress] 越小,且 payoutsTo_[_customerAddress] 为负数。

接下来我们再看一下 withdraw 函数的定义:

零时科技 || Bankroll 攻击事件分析

可以看出,提取的金额来源于 myDividends 函数,我们继续跟踪;

零时科技 || Bankroll 攻击事件分析

由上述分析,我们可以得出结论,只要 profitPerShare_ 越大,相同 share 下可以提取的 WBNB就越多。那么,由于攻击者一开始通过 buyfor获得了一定数量的 share ,攻击者只需要操纵 profitPerShare_ ,将其数值拉高即可提空合约中的 Token 。再回到最初分析 buyfor 函数得到的结论,只要调用 buyfor 函数购买 share 即可拉高profitPerShare_ 。但是 buyfor 函数没有限制 _customerAddress 不能为该合约本身,所以,攻击者通过将 _customerAddress 传入 Bankroll 的合约地址,即可完成不用转入 WBNB 来拉高profitPerShare_ ,最终完成攻击。攻击者从 Bankroll 合约中获得 16,412 WBNB ,还掉闪电贷的本金和利息 16,008 WBNB ,获利403 WBNB 约合 230k USD

总结

本次漏洞在于 Bankroll 的代码中,没有做输入限制,导致攻击者可以使购买方为项目方本身。使得每一个单位的 share 被大幅拉升,从而使攻击者将 Bankroll 的所有资产已 share 的利润方式提取。建议项目方在合约上线前,针对智能合约进行充分的审计和交叉审计,避免此类安全问题。