來(lái)源:零時(shí)科技
事件背景
2023-11-13 18:51:57 (UTC) 鏈上發(fā)生一筆針對(duì) OKC Token 的攻擊事件,黑客通過(guò)存在缺陷的MinerPool獲取了及時(shí)收益
黑客攻擊交易:
0xd85c603f71bb84437bc69b21d785f982f7630355573566fa365dbee4cd236f08
黑客攻擊合約1:
0xD5d8c2fd8A743A89BC497B2F180C52d719a007B9
黑客攻擊合約2:
0x617432Fc98c1fFaAB62B8cB94Cef6D75ABD95598
黑客攻擊合約3:
0x28e7c8337373C81bAF0A4FE88ee6E33d3C23E974
攻擊者地址:
0xbbcc139933D1580e7c40442E09263e90E6F1D66D
漏洞合約:
0x36016C4F0E0177861E6377f73C380c70138E13EE (MinerPool)
攻擊分析
通過(guò)對(duì)鏈上交易數(shù)據(jù)分析,我們對(duì)其交易進(jìn)行整理歸納。
黑客首先通過(guò)多個(gè)閃電貸進(jìn)行對(duì)攻擊資金的籌集,共借款 2,753,399 USDT Token。
隨后立即將其中 130,000 USDT Token 兌換為一個(gè)最小單位的 USDT Token 和 27,264 OKC Token 。
由于 PancakeSwapv2 使用的是AMM(恒定函數(shù)做市商),在該模型中,交易池中的兩種代幣的數(shù)量乘積是一個(gè)常數(shù)??梢杂靡韵鹿奖硎荆?/p>
其中:
? x是交易池中第一種代幣的數(shù)量。
? y是交易池中第二種代幣的數(shù)量。
? k是一個(gè)常數(shù),表示池中兩種代幣數(shù)量的乘積。
當(dāng)一個(gè)交易者想要用一種代幣兌換另一種代幣時(shí),他們會(huì)增加交易池中一種代幣的數(shù)量(dx),同時(shí)減少另一種代幣的數(shù)量(dy),以保持的不變性。這個(gè)過(guò)程會(huì)改變代幣的相對(duì)價(jià)格。
假設(shè)交易者想要用代幣A兌換代幣B,那么在交易前后,恒定乘積公式應(yīng)該保持成立:
由于k是不變的,這意味著x·y在交易前后是相同的。但是,因?yàn)榻灰渍咴黾恿舜鷰臕的數(shù)量(dx)并且減少了代幣B的數(shù)量(dy),這將導(dǎo)致代幣B的價(jià)格上升。
代幣的即時(shí)價(jià)格可以通過(guò)計(jì)算池中兩種代幣數(shù)量的比率來(lái)得出。如果代幣A是x,代幣B是y,則代幣B相對(duì)于代幣A的價(jià)格是y/x。在交易之后,代幣B的數(shù)量減少了,代幣A的數(shù)量增加了,所以新的價(jià)格變成了(y-dy)/(x+dy) 。由于分子減小而分母增大,這個(gè)比率變小了,意味著代幣B的價(jià)格上升。
在大額交易的情況下,dx和dy可能非常大,這會(huì)導(dǎo)致價(jià)格的顯著變動(dòng)。這是因?yàn)闉榱吮3謐的不變,必須從池中移除大量的dy來(lái)補(bǔ)償dx的增加。這種大額交易對(duì)池中代幣數(shù)量的巨大影響導(dǎo)致了價(jià)格的顯著變化。
故攻擊者通過(guò)使用大額閃電貸資金進(jìn)行買入OKC,導(dǎo)致 OKC 數(shù)量減少,從而拉高了 OKC Token 的價(jià)格,將 1 OKC = 0.3 USDT 的價(jià)格提升到 1 OKC = 68.9 USDT。
后攻擊者創(chuàng)建了兩個(gè)合約地址,并分別向兩個(gè)地址中發(fā)送了 0.01 OKC 和 0.0001 USDT 和 一個(gè)最小單位的OKC。
然后黑客使用主要的攻擊合約對(duì) PancakePair_USDT_OKC 池子添加流動(dòng)性操作,得到約 225,705 個(gè)LP Token。
隨后將 LP Token 全部轉(zhuǎn)移至 攻擊者創(chuàng)建的 0x28e7c8337373C81bAF0A4FE88ee6E33d3C23E974 攻擊合約中隨后立即調(diào)用漏洞合約中的 processLPReward 函數(shù),對(duì)合約內(nèi)存儲(chǔ)的 lpHolder 地址進(jìn)行獎(jiǎng)勵(lì)分配。此處雖然攻擊者的操作只是向 MinerPool 合約轉(zhuǎn)賬,但是該合約在接受轉(zhuǎn)賬的回調(diào)函數(shù)中調(diào)用了processLPReward 函數(shù)。
根據(jù)下圖,我們得知攻擊合約 0x28e7c8337373C81bAF0A4FE88ee6E33d3C23E974 在獎(jiǎng)勵(lì)領(lǐng)取中獲得了 77,890 個(gè) OKC Token。
然后攻擊者轉(zhuǎn)出攻擊合約 0x28e7..E974 的的 LP Token 并將其銷毀移除流動(dòng)性,獲得了 1,884,223 USDT Token,以及 27,264 OKC Token。
并轉(zhuǎn)移出另外兩個(gè)攻擊合約中的所有的Token至主要攻擊合約
0xD5d8c2fd8A743A89BC497B2F180C52d719a007B9 ,分別為:272 個(gè),77,890 個(gè) OKC Token。
黑客將所有的OKC ,約 104,610 OKC Token 兌換為約 136,518 USDT Token,此時(shí)黑客總持有約 2,759,918 USDT Token。
最后,黑客歸還所有閃電貸的本金和利息,最終剩余約 6,268 USDT Token,并全部轉(zhuǎn)移至攻擊者地址
0xbbcc139933D1580e7c40442E09263e90E6F1D66D。
漏洞分析
通過(guò)攻擊分析得知,黑客主要獲利資金是由 MinerPool 合約中 processLPReward 函數(shù),該函數(shù)邏輯主要是獲取 lpHolder 并根據(jù)其 LP 數(shù)量直接按比例進(jìn)行獎(jiǎng)勵(lì)。
我們可以看一下攻擊者創(chuàng)建的第三個(gè)攻擊合約中的執(zhí)行邏輯:
從該處邏輯可以看出addHolder函數(shù)中使用了 extcodesize() 來(lái)計(jì)算地址當(dāng)前的大小,用來(lái)判斷地址是否是合約地址,但是在攻擊者通過(guò) CREATE2 創(chuàng)建合約,由于合約在初始化時(shí),該地址大小依然為0,從而來(lái)攻擊者在其構(gòu)造函數(shù)中調(diào)用該函數(shù)繞過(guò)其中的合約調(diào)用限制。
其在轉(zhuǎn)賬時(shí)調(diào)用了 addHolder 函數(shù)將 合約地址添加到了 lpHolder 名單,所以該合約才可以通過(guò)領(lǐng)取獎(jiǎng)勵(lì)獲取及時(shí)的OKC獎(jiǎng)勵(lì)。
根據(jù)對(duì) processLPReward 函數(shù)代碼邏輯進(jìn)行分析,可以從下圖中看出,雖然設(shè)置了領(lǐng)取獎(jiǎng)勵(lì)的鎖定時(shí)間,但是未設(shè)置 LP 持有時(shí)間進(jìn)行校驗(yàn)或限制,導(dǎo)致黑客通過(guò)閃電貸獲取大量臨時(shí)資金,并兌換為L(zhǎng)P ,并在領(lǐng)取獎(jiǎng)勵(lì)后立即銷毀。
總結(jié)
簡(jiǎn)單來(lái)說(shuō),黑客通過(guò)閃電貸借了大量USDT,并兌換大量OKC,從而拉高了OKC的價(jià)格。并且由于OKC項(xiàng)目未設(shè)置LP獎(jiǎng)勵(lì)發(fā)放的鎖倉(cāng)要求,所以黑客在獲取獎(jiǎng)勵(lì)后立刻撤回流動(dòng)性,從而獲取了項(xiàng)目方發(fā)放的流動(dòng)性提供者的獎(jiǎng)勵(lì)。并將OKC項(xiàng)目方獎(jiǎng)勵(lì)的OKC Token出售。最終獲利 6,268 USDT。