【漏洞分析】OSN 代币攻击事件:一笔资金伪造多个分红大户

背景

OSN 是一种 fee on transfer 代币,会根据用户分红账户的余额对用户发放分红。攻击者利用漏洞增发分红账户的余额,随后触发分红机制完成获利。

OSN:https://bscscan.com/address/0x810f4c6ae97bcc66da5ae6383cc31bd3670f6d13#code

攻击由三笔交易组成:

  1. https://app.blocksec.com/explorer/tx/bsc/0xbf22eabb5db8785642ba17930bddef48d0d1bb94ebd1e03e7faa6f2a3d1a5540
  2. https://app.blocksec.com/explorer/tx/bsc/0x69c64b226f8bf06216cc665ad5e3777ad1b120909326f120f0816ac65a9099c0
  3. https://app.blocksec.com/explorer/tx/bsc/0xc7927a68464ebab1c0b1af58a5466da88f09ba9b30e6c255b46b1bc2e7d1bf09

Trace 分析

攻击交易1

攻击者首先用 BUSD 换出 OSN 代币

【漏洞分析】OSN 代币攻击事件:一笔资金伪造多个分红大户

然后将少量 BUSD 和 OSN 发放到新创建的地址中

【漏洞分析】OSN 代币攻击事件:一笔资金伪造多个分红大户

攻击交易2

攻击者操控攻击交易1中创建的账户向 pair 添加流动性

【漏洞分析】OSN 代币攻击事件:一笔资金伪造多个分红大户

攻击交易3

攻击者首先闪电贷 50000 BUSD

【漏洞分析】OSN 代币攻击事件:一笔资金伪造多个分红大户

随后购入 70000 OSN

【漏洞分析】OSN 代币攻击事件:一笔资金伪造多个分红大户

向 pair 添加流动性,获得 53032907572135909484703 流动性代币

【漏洞分析】OSN 代币攻击事件:一笔资金伪造多个分红大户

把流动性代币发送到攻击合约,然后调用其 addLiq 函数 burn 35524 流动性代币(交易2中添加的),取回资产。随后将之前收到的 53032907572135909484703 流动性代币转移到下一个合约,不断重复这个操作。

【漏洞分析】OSN 代币攻击事件:一笔资金伪造多个分红大户

移除流动性,取回 BUSD 和 OSN 代币,然后反复执行 BUSD -> OSN 和 OSN-> BUSD 两种的兑换操作。

【漏洞分析】OSN 代币攻击事件:一笔资金伪造多个分红大户

执行攻击合约的 cc 函数,向 pair 添加流动性,触发 OSNLpDividendTracker.setBalance 函数,随后给攻击合约分红 55 BUSD。最后将攻击合约内全部的 121 BUSD 转移到攻击者地址。

【漏洞分析】OSN 代币攻击事件:一笔资金伪造多个分红大户

从调试界面可以知道攻击合约内原有 66 BUSD,加上分红得到的 55 BUSD,一共 121 BUSD。

【漏洞分析】OSN 代币攻击事件:一笔资金伪造多个分红大户

最后攻击者归还闪电贷 500250 BUSD,获利 1767 BUSD。

【漏洞分析】OSN 代币攻击事件:一笔资金伪造多个分红大户

漏洞分析

攻击者在第一笔交易中创建了大量的账户,然后在第二笔交易中通过这些账户向 pair 添加少量的流动性

OSN._transfer 函数中,会记录流动性账户 userInfo 所持有的流动性代币,以及分红账户所持有的流动性代币。

【漏洞分析】OSN 代币攻击事件:一笔资金伪造多个分红大户

随后在第三笔交易中,攻击者首先是添加流动性获取到大量的流动性代币,然后把流动性代币发送到攻击合约,再移除攻击合约之前添加的流动性。

此时会进入到 OSN._transfer 函数的另一个分支——移除流动性分支。函数先获取了 to 地址的流动性代币余额,然后通过 lpDividendTracker.setBalance 函数将该数值记录到 to 地址的分红账户上。

【漏洞分析】OSN 代币攻击事件:一笔资金伪造多个分红大户

从下面的 trace 可以看出,攻击合约的 newBalance 被设为了一个很大的数值。随后攻击者故技重施,将这笔流动性代币转移到下一个攻击合约并更新其 newBalance 值,在创建的多个攻击合约之间不断重复这个操作。

【漏洞分析】OSN 代币攻击事件:一笔资金伪造多个分红大户

随后攻击者移除了流动性,取回 BUSD 和 OSN 代币,然后反复执行 BUSD -> OSN 和 OSN-> BUSD 两种的兑换操作。

当 OSN -> BUSD 时,会执行红框内的三个函数

  1. swapAndSendDividends:将 OSN -> BUSD,然后将 BUSD 发送给 lpDividendTracker,随后调用 lpDividendTracker.distributeDividends函数。
  2. burnPoolToken:burn 掉 pair 中一部分的 OSN 代币。
  3. swapAndAddLiqidity:将 OSN -> BUSD,把 4/7 BUSD 发送给 marketAddress,把 3/7 BUSD 发送给 lpDividendTracker,随后调用 lpDividendTracker.distributeDividends 函数。

【漏洞分析】OSN 代币攻击事件:一笔资金伪造多个分红大户

lpDividendTracker.distributeDividends 函数的主要功能就是累加奖励数值 magnifiedDividendPerShare,也就是说每调用一次该函数,奖励就增加一次。这也就是攻击者反复进行 swap 操作的原因。

【漏洞分析】OSN 代币攻击事件:一笔资金伪造多个分红大户

在进行完 swap 操作后,攻击者调用攻击合约的 cc 函数向 pair 添加少量流动性,目的是触发分红发放函数来获利。

函数调用流程如下:_transfer -> setBalance -> processAccount -> _withdrawDividendOfUser -> withdrawableDividendOf -> accumulativeDividendOf

accumulativeDividendOf 函数计算用户可以分得的分红,其中 magnifiedDividendPerShare 被攻击者通过反复 swap 操控,而 balanceOf 则被那笔复用的流动性代币所操控。

【漏洞分析】OSN 代币攻击事件:一笔资金伪造多个分红大户

_withdrawDividendOfUser 函数中,根据被操控的分红金额向攻击地址进行分红,完成此次攻击的获利。

【漏洞分析】OSN 代币攻击事件:一笔资金伪造多个分红大户

后记

原本以为代币上的安全问题不会太复杂,比较一个代币的代码量相比其他 DeFi 协议还是比较小的。但是查看了代码以后才发现这个代币还是挺复杂的,在 ERC20 的基础上加了很多机制:收税,通缩,分红,回购等等。所以在本篇文章也只是跟踪关键的几个受影响的变量进行追踪分析,如果读者想要深入全面了解 OSN 代币的机制的话可以阅读他的源码。如果文章有哪些地方分析有误也请多多指教,感谢你的阅读。

发表评论

相关文章