0x.1 Arka Plan
15 Ekim 2021 tarihinde saat 02:38'de (UTC+8), dahili izleme sistemimiz şüpheli flashloan işlemlerini tespit etti:

Yaptığımız araştırmanın ardından, bunun Indexed Finance'i hedef alan bir fiyat manipülasyonu saldırısı olduğunu tespit ettik. Özellikle, saldırgan bu projenin fiyat hesaplamak için kullandığı hatalı formülü istismar ederek saldırıyı gerçekleştirdi ve 16 milyon dolar kâr elde etti.
Sosyal medyada bu konuya ilişkin bazı tartışmalar mevcuttur ve proje resmi bir olay sonrası raporu yayımlamıştır (Indexed Saldırısı Olay Sonrası Raporu). Ancak mevcut analizler bu güvenlik olayını tam olarak açıklamamaktadır. Bu nedenle, bu blog yazısında projenin mekanizması, güvenlik açığı, saldırı ve elde edilen kâr dahil olmak üzere kapsamlı bir analiz sunmayı amaçlıyoruz.
0x1.1 İlgili Sözleşme Adresleri
-
MarketCapSqrtController: 0x120c6956d292b800a835cb935c9dd326bdb4e011
-
DEFI5: 0xfa6de2697d59e88ed7fc4dfe5a33dac43565ea41
-
CC10: 0x17ac188e09a7890a1844e5e65471fe8b0ccfadf3
0x1.2 Saldırı İşlemleri
-
Saldırı TX-I: 0x44aad3b853866468161735496a5d9cc961ce5aa872924c5d78673076b1cd95aa
-
Saldırı TX-II: 0xbde4521c5ac08d0033019993b0e7e1d29b1457e80e7743d318a3c27649ca4417
0x2. Indexed Finance'in Mekanizması
Güvenlik açığını/saldırıyı daha iyi anlamak için, saldırgan tarafından ele geçirilen havuz olan DEFI5'i kullanarak Indexed Finance'in mekanizmasını açıklayacağız.
0x2.1 Token Bağlama
DEFI5, Ethereum'daki DeFi projelerinin ilk 5 token'ı için işlem hizmeti sunmak üzere tasarlanmıştır. Özellikle, Indexed Finance token sıralamalarını MarketCapSqrtController aracılığıyla piyasa değerlerine göre güncelleyecektir. İlk 5 token'ın sıralaması zamanla değişebileceğinden, DEFI5 havuzu tarafından kullanılan token sayısı aşağıdaki kodda gösterildiği gibi 5'ten fazla olabilir:

Şekil 1'de görüldüğü üzere, yeni bir token bağlamak için DEFI5'in, yalnızca MarketCapSqrtController'ın reindexPools fonksiyonu tarafından çağrılabilen reindexTokens fonksiyonu tarafından çağrılan _bind fonksiyonunu tetiklemesi gerekmektedir:

Şekil 2'de gösterildiği üzere, MarketCapSqrtController önce piyasalardan token bilgilerini (TotalSupply ve fiyat dahil) alır, ardından piyasa değerlerine göre sıralamayı hesaplar.
reindexPool fonksiyonu çağrıldığında, üst sıradaki token adresleri reindexTokens fonksiyonunu çağırmak için argüman olarak iletilir.
Yeni eklenen token'ın, DEFI5'teki orijinal token'ların yerini almadan DEFI5'e bağlanacağını unutmayın.
0x2.2 Sırada Ne Var?
Token bağlamasının ardından DEFI5, işlemin etkinleştirilmesi için token durumunu belirten ready adlı değişkeni true olarak ayarlamak zorundadır:

Kod mantığına göre, sözleşme başlatmanın dışında ready yalnızca gulp fonksiyonunda ayarlanabilir.
Şekil 3'te gösterildiği üzere, bu durum DEFI5 içindeki token bakiyesi _minimumBalances değerine eşit veya daha büyük olduğunda gerçekleşir.
Bu arada, başlangıç token ağırlığı (yani denorm) aşağıdaki formüle göre hesaplanacaktır:

0x3. Güvenlik Açığı Analizi
Güvenlik açığı içeren kod, MarketCapSqrtController'ın updateMinimumBalance fonksiyonuna aittir.

Şekil 4'te gösterildiği gibi, updateMinimumBalance, ready değeri false olan bir token'ın minimumBalance değerini poolValue'nun 1/100'ü olarak değiştirebilir. poolValue'nun hesaplanması güvenlik açığının temel noktasıdır.

Şekil 5'teki hesaplama yalnızca aşağıdaki formülü uygulamaktadır:

Ancak bu formülde iki potansiyel sorun bulunmaktadır:
- tüm havuzun değerini tahmin etmek için yalnızca bir token'ın likiditesinin kullanılması;
- havuzun (
_totalWeight) ve token'ın (token.denorm) ağırlıklarının likidite değişiminden etkilenmemesi. Aslında bunlar, dış piyasaların Piyasa Değeri tarafından etkilenmektedir. Ayrıca değişimleri zaman dilimiyle sınırlandırılmıştır; yani saatte %1 artış veya azalış.
Kısacası, saldırgan flashloan kullanarak bir token'ın likiditesinde anlık olarak büyük bir değişime yol açabilir ve bu sırada havuzun ve token'ın ağırlıkları buna göre değişmeden kalır; böylece poolValue değeri manipüle edilebilir.
Bunu yaparak, (ready değeri false olan) token'ın minimumBalance değeri manipüle edilerek fiyat manipülasyonu saldırısı başlatılabilir.
0x4. Saldırı Analizi
Saldırı aşağıdaki 9 adımdan oluşmaktadır:
Adım 1: SUSHI'yi bağlamak için reindexPool fonksiyonu çağrılır. Çağrıdan önce DEFI5 havuzunda UNI, AAVE, COMP, SNX, CRV ve MKR dahil olmak üzere 6 token bulunmaktadır. SUSHI'nin Piyasa Değeri İlk 5'e girdiğinde, SUSHI havuza eklenecektir.

Adım 2: SushiSwap aracılığıyla IndexPool tarafından desteklenen 6 token'ın tamamı (UNI, AAVE, COMP, SNX, CRV ve MKR) ödünç alınır.

Adım 3: Ödünç alınan token'larla (örneğin COMP) swapExactAmountIn fonksiyonu birden fazla kez çağrılarak UNI takas edilir.
Not 1: Burada birden fazla kez çağrılmasının nedeni
MAX_IN_RATIOkısıtlamasıdır; bir seferde token bakiyesinin en fazla yarısı takas edilebilir.Not 2: Bu adımda, havuzdaki UNI (
firstTokenolarak) bakiyesi büyük ölçüde azaldığındanpoolValueciddi biçimde düşük tahmin edilecektir.

Adım 4: updateMinimumBalance fonksiyonu çağrılarak SUSHI'nin minimumBalance değeri değiştirilir.
- adımda hesaplanan anormal
poolValuenedeniyleminimumBalancedeğerinin normal değerden daha düşük olduğuna dikkat edin.

Adım 5: Likidite sağlamak için joinswapExternAmountIn fonksiyonu çağrılarak LP token'ları hazırlanır. Bu LP token'larının daha fazla SUSHI'yi geri takas etmek için kullanıldığını göreceğiz.
Not:
MAX_IN_RATIO'nun etkisi nedeniylejoinswapExternAmountInfonksiyonunun birden fazla kez çağrılması gerekmektedir.

Adım 6: Önce büyük miktarda SUSHI ödünç alınıp havuza aktarılarak, ardından gulp fonksiyonu çağrılarak SUSHI'nin ready değeri true olarak ayarlanarak DEFI5 havuzundaki SUSHI ağırlığı manipüle edilir. Bu sayede SUSHI'nin başlangıç ağırlığı (denorm) yüksek bir değere ulaşır.

Adım 7: exitPool fonksiyonu çağrılarak LP token'ları temel token'lara (UNI, AAVE, COMP, SNX, CRV, MKR ve SUSHI) geri takas edilir.
exitPoolfonksiyonunun her token'ın ağırlığını DİKKATE ALMАDIĞINI unutmayın; bu nedenle temel token'lar eşit oranda geri iade edilecektir.
Adım 8: Likidite sağlamak için SUSHI ile joinswapExternAmountIn fonksiyonu çağrılarak LP token'ları takas edilir. O anki SUSHI'nin anormal ağırlığı sayesinde daha fazla LP token'ı elde edilebilir.


joinswapPoolAmountIn fonksiyonunun, alınan temel token'ın (bu durumda SUSHI) ağırlığına göre LP token'ı basacağını unutmayın.
Adım 9: 8. adımda elde edilen LP token'larıyla exitPool fonksiyonu çağrılarak havuz boşaltılır.
0x5. Kâr Analizi
Araştırmamız, saldırganın kullandığı tüm paranın (işlem ücretleri dahil) Tornado Cash'ten geldiğini göstermektedir.
Toplamda iki saldırı işlemi gerçekleştirilmiştir:
-
Birinci işlemde, saldırgan şunları elde etti: 6.226,8 AAVE, 15 ETH, 192.358,6 UNI, 5.459,5 COMP, 721.611,3 CRV, 16.680,6 SNX, 406,5 MKR.
-
İkinci işlemde, saldırgan şunları ele geçirdi: 109,6 MKR, 17.844 UMA, 1.002,4 COMP, 34.602,5 UNI, 131.645,4 BAT, 28.754,1 SNX, 1.273,6 AAVE, 124.194,2 CRV, 33.215,4 LINK, 5,24 YFI.
Bunların yanı sıra, saldırganın birkaç başarısız girişimi de oldu.
Bu yazının kaleme alındığı tarih itibarıyla, saldırganın elde ettiği kâr 16 milyon ABD doları değerindedir ve henüz transfer edilmemiştir.
BlockSec Hakkında
BlockSec, 2021 yılında küresel alanda tanınmış güvenlik uzmanlarından oluşan bir ekip tarafından kurulmuş öncü bir blok zinciri güvenlik şirketidir. Şirket, kitlesel benimsemeyi kolaylaştırmak amacıyla gelişmekte olan Web3 dünyasının güvenliğini ve kullanılabilirliğini artırmaya kararlıdır. Bu doğrultuda BlockSec; akıllı sözleşme ve EVM zinciri güvenlik denetimi hizmetleri, güvenlik geliştirme ve tehditleri proaktif olarak engelleme için Phalcon platformu, fon takibi ve soruşturma için MetaSleuth platformu ve kripto dünyasında verimli şekilde gezinen web3 geliştiricileri için MetaSuites eklentisi sunmaktadır.
Bugüne kadar şirket, MetaMask, Uniswap Foundation, Compound, Forta ve PancakeSwap gibi 300'den fazla saygın müşteriye hizmet vermiş; Matrix Partners, Vitalbridge Capital ve Fenbushi Capital gibi önde gelen yatırımcılardan iki tur finansmanda on milyonlarca ABD doları almıştır.
Resmi web sitesi: https://blocksec.com/
Resmi Twitter hesabı: https://twitter.com/BlockSecTeam



