【漏洞分析】OSN 代幣攻擊事件:一筆資金偽造多個(gè)分紅大戶
背景
OSN 是一種 fee on transfer 代幣,會根據(jù)用戶分紅賬戶的余額對用戶發(fā)放分紅。攻擊者利用漏洞增發(fā)分紅賬戶的余額,隨后觸發(fā)分紅機(jī)制完成獲利。
OSN:https://bscscan.com/address/0x810f4c6ae97bcc66da5ae6383cc31bd3670f6d13#code
攻擊由三筆交易組成:
- https://app.blocksec.com/explorer/tx/bsc/0xbf22eabb5db8785642ba17930bddef48d0d1bb94ebd1e03e7faa6f2a3d1a5540
- https://app.blocksec.com/explorer/tx/bsc/0x69c64b226f8bf06216cc665ad5e3777ad1b120909326f120f0816ac65a9099c0
- https://app.blocksec.com/explorer/tx/bsc/0xc7927a68464ebab1c0b1af58a5466da88f09ba9b30e6c255b46b1bc2e7d1bf09
Trace 分析
攻擊交易1
攻擊者首先用 BUSD 換出 OSN 代幣

然后將少量 BUSD 和 OSN 發(fā)放到新創(chuàng)建的地址中

攻擊交易2
攻擊者操控攻擊交易1中創(chuàng)建的賬戶向 pair 添加流動(dòng)性

攻擊交易3
攻擊者首先閃電貸 50000 BUSD

隨后購入 70000 OSN

向 pair 添加流動(dòng)性,獲得 53032907572135909484703 流動(dòng)性代幣

把流動(dòng)性代幣發(fā)送到攻擊合約,然后調(diào)用其 addLiq 函數(shù) burn 35524 流動(dòng)性代幣(交易2中添加的),取回資產(chǎn)。隨后將之前收到的 53032907572135909484703 流動(dòng)性代幣轉(zhuǎn)移到下一個(gè)合約,不斷重復(fù)這個(gè)操作。

移除流動(dòng)性,取回 BUSD 和 OSN 代幣,然后反復(fù)執(zhí)行 BUSD -> OSN 和 OSN-> BUSD 兩種的兌換操作。

執(zhí)行攻擊合約的 cc 函數(shù),向 pair 添加流動(dòng)性,觸發(fā) OSNLpDividendTracker.setBalance 函數(shù),隨后給攻擊合約分紅 55 BUSD。最后將攻擊合約內(nèi)全部的 121 BUSD 轉(zhuǎn)移到攻擊者地址。

從調(diào)試界面可以知道攻擊合約內(nèi)原有 66 BUSD,加上分紅得到的 55 BUSD,一共 121 BUSD。

最后攻擊者歸還閃電貸 500250 BUSD,獲利 1767 BUSD。

漏洞分析
攻擊者在第一筆交易中創(chuàng)建了大量的賬戶,然后在第二筆交易中通過這些賬戶向 pair 添加少量的流動(dòng)性
在 OSN._transfer 函數(shù)中,會記錄流動(dòng)性賬戶 userInfo 所持有的流動(dòng)性代幣,以及分紅賬戶所持有的流動(dòng)性代幣。

隨后在第三筆交易中,攻擊者首先是添加流動(dòng)性獲取到大量的流動(dòng)性代幣,然后把流動(dòng)性代幣發(fā)送到攻擊合約,再移除攻擊合約之前添加的流動(dòng)性。
此時(shí)會進(jìn)入到 OSN._transfer 函數(shù)的另一個(gè)分支——移除流動(dòng)性分支。函數(shù)先獲取了 to 地址的流動(dòng)性代幣余額,然后通過 lpDividendTracker.setBalance 函數(shù)將該數(shù)值記錄到 to 地址的分紅賬戶上。

從下面的 trace 可以看出,攻擊合約的 newBalance 被設(shè)為了一個(gè)很大的數(shù)值。隨后攻擊者故技重施,將這筆流動(dòng)性代幣轉(zhuǎn)移到下一個(gè)攻擊合約并更新其 newBalance 值,在創(chuàng)建的多個(gè)攻擊合約之間不斷重復(fù)這個(gè)操作。

隨后攻擊者移除了流動(dòng)性,取回 BUSD 和 OSN 代幣,然后反復(fù)執(zhí)行 BUSD -> OSN 和 OSN-> BUSD 兩種的兌換操作。
當(dāng) OSN -> BUSD 時(shí),會執(zhí)行紅框內(nèi)的三個(gè)函數(shù)
swapAndSendDividends:將 OSN -> BUSD,然后將 BUSD 發(fā)送給lpDividendTracker,隨后調(diào)用lpDividendTracker.distributeDividends函數(shù)。burnPoolToken:burn 掉 pair 中一部分的 OSN 代幣。swapAndAddLiqidity:將 OSN -> BUSD,把 4/7 BUSD 發(fā)送給marketAddress,把 3/7 BUSD 發(fā)送給lpDividendTracker,隨后調(diào)用lpDividendTracker.distributeDividends函數(shù)。

lpDividendTracker.distributeDividends 函數(shù)的主要功能就是累加獎(jiǎng)勵(lì)數(shù)值 magnifiedDividendPerShare,也就是說每調(diào)用一次該函數(shù),獎(jiǎng)勵(lì)就增加一次。這也就是攻擊者反復(fù)進(jìn)行 swap 操作的原因。

在進(jìn)行完 swap 操作后,攻擊者調(diào)用攻擊合約的 cc 函數(shù)向 pair 添加少量流動(dòng)性,目的是觸發(fā)分紅發(fā)放函數(shù)來獲利。
函數(shù)調(diào)用流程如下:_transfer -> setBalance -> processAccount -> _withdrawDividendOfUser -> withdrawableDividendOf -> accumulativeDividendOf
accumulativeDividendOf 函數(shù)計(jì)算用戶可以分得的分紅,其中 magnifiedDividendPerShare 被攻擊者通過反復(fù) swap 操控,而 balanceOf 則被那筆復(fù)用的流動(dòng)性代幣所操控。

在 _withdrawDividendOfUser 函數(shù)中,根據(jù)被操控的分紅金額向攻擊地址進(jìn)行分紅,完成此次攻擊的獲利。

后記
原本以為代幣上的安全問題不會太復(fù)雜,比較一個(gè)代幣的代碼量相比其他 DeFi 協(xié)議還是比較小的。但是查看了代碼以后才發(fā)現(xiàn)這個(gè)代幣還是挺復(fù)雜的,在 ERC20 的基礎(chǔ)上加了很多機(jī)制:收稅,通縮,分紅,回購等等。所以在本篇文章也只是跟蹤關(guān)鍵的幾個(gè)受影響的變量進(jìn)行追蹤分析,如果讀者想要深入全面了解 OSN 代幣的機(jī)制的話可以閱讀他的源碼。如果文章有哪些地方分析有誤也請多多指教,感謝你的閱讀。

浙公網(wǎng)安備 33010602011771號