Beosin, Düşük Sürüm Solana Anchor Çerçevesinde Kritik IDL Komutu Zafiyetini Açıkladı

iconMetaEra
Paylaş
AI summary iconÖzet
Beosin'in güvenlik ekibi, düşük sürüm Solana Anchor çerçevelerinde kritik bir IDL talimatı zafiyeti tespit etti. Bu hata, AccountInfo bildirimlerinden yararlanarak programa ait PDA hesaplarını ele geçirmeye izin verir ve kullanıcı izinleri olmadan iki adımda fon çalınmasını sağlar. Olay, akıllı sözleşme geliştirme sürecinde daha güçlü bir uyumluluk çerçevesi gerekliliğini vurgulamaktadır. MiCA (AB Kripto Varlık Piyasaları Düzenlemesi) yaklaştıkça, bu tür zafiyetler gerçek zamanlı güvenlik denetimleri ve düzenleyici standartlara uyumun önemini ortaya koymaktadır.

Anchor, Solana ekosisteminde en yaygın geliştirme çerçevesidir. Deklaratif hesap doğrulama, otomatik serileştirme ve yerleşik güvenlik kontrolleri gibi özelliklerle geliştirme engellerini büyük ölçüde düşürür. Ancak çerçeve, kolaylık sağlarken, arka planda her programın içine geliştiricilerin bilmediği bazı dahili komutlar ekler. Bu "gizli" komutlar, belirli koşullar altında saldırganlar tarafından kullanılarak ciddi finansal kayıplara neden olabilir.

Beosin güvenlik ekibi, düşük sürümlü Anchor'da geliştiricilerin Program-owned PDA hesaplarını belirtmek için AccountInfo kullandığında, saldırganların Anchor'un otomatik olarak enjekte ettiği IDL komutuyla yalnızca iki adımda hesap kontrolünü ele geçirebileceğini ve içindeki tüm SOL'ları boşaltabileceğini ortaya koyacak; bu süreçte herhangi bir ayrıcalığa gerek yoktur.

Birinci: IDL Talimatları ve İlgili Mekanizma Analizi

1.1 IDL Talimatı

Anchor, inşa sırasında no-idl özelliği açıkça etkinleştirilmediği sürece, her programda bir dizi IDL (Interface Definition Language, Arayüz Tanım Dili) yönetim komutu enjekte eder. Bu komutlar şunlardır:

IdlCreateAccount: Zincir üzerinde bir IDL hesabı oluşturun

IdlWrite: IDL hesabına / önbellek hesabına veri yazma

IdlSetAuthority: IDL hesabının yetkilisini değiştirin

IdlCloseAccount: IDL hesabını kapatın ve tüm lamports'larını belirtilen alıcıya aktarın

IdlResizeAccount: IDL hesap boyutunu ayarla

IdlCreateBuffer: IDL Buffer hesabını oluşturun

IdlSetBuffer: Önbellek hesabındaki verilerle resmi IDL hesabını üzerine yazın

Bu komutlar, zincir üstü IDL yönetimi için tasarlanmıştır, ancak programın sahip olduğu hesaplar üzerinde özel yetkilere sahiptir (verileri okuma/yazma, kontrol edeni değiştirme, kapatma ve lamports’ları aktarma) — bu da açıklığın temelidir. Saldırgan, geliştiricilerin yazdığı herhangi bir iş komutunu çağırmak zorunda değildir; doğrudan bu yerleşik komutları çağırabilir.

1.2 IDL arabellek hesabı

IDL tampon hesabı (IDL Buffer), Anchor tarafından büyük IDL verilerini parçalı olarak yüklemek için kullanılan geçici bir hesaptır. Tam IDL (JSON ile sıkıştırılmış) tek bir işlem boyutu sınırını aşabileceğinden, Anchor önce IdlCreateBuffer ile bir tampon oluşturmayı, ardından birden fazla IdlWrite ile veriyi parçalı olarak yazmayı ve nihayetinde IdlSetBuffer ile tek seferde göndermeyi sağlar.

IDL hesabının / tampon hesabının veri yapısı anahtar noktadır: Sabit bir düzenle başlayan bir başlıkla başlar ve bu başlıkta authority: Pubkey alanı bulunur (bu test çıktısında controller olarak adlandırılır). IDL komutu, bu alan aracılığıyla “hangi kişinin bu hesapla işlem yapma yetkisi olduğuna” karar verir.

Ancak sorun şudur: düşük sürüm Anchor'un IdlCreateBuffer işleme mantığı, bu programın sahibi olduğu herhangi bir hesabı giriş olarak kabul edip yetkiyi doğrudan işlem imzalayıcısına atar. Yani bir hesabın sahibi bu programsa (örneğin programın PDA kasanı), saldırgan bu hesabın kontrolcüsü olarak kendini yazabilir ve ardından IdlCloseAccount ile hesaptaki tüm SOL'ları meşru bir şekilde aktarabilir.

1.3 Güvenlik açığı tetikleme koşulları

Bu zafiyetin tetiklenmesi için aşağıdaki koşulların aynı anda karşılanması gerekir:

  • Eski sürüme sahip Anchor kullanın: Yetersiz hesap doğrulaması nedeniyle tehlikeli IDL komutları, iş hesaplarını IDL hesapları olarak yanlış işleme izin verir.
  • no-idl etkinleştirilmedi: Program, inşa sırasında varsayılan olarak enjekte edilen IDL yönerge giriş noktasını korudu ve saldırı yüzeyi dışa açıldı.
  • AccountInfo ile programın sahip olduğu PDA'yı bildirin: Geliştiriciler,资金 hesabı (örneğin, kasa PDA) taşımak için doğrudan AccountInfo kullanır; bu, Anchor tipleştirilmiş hesaplarının (örneğin, Account) sunduğu discriminator/owner ayrımını içermez ve bu hesap, IDL komutu için IDL hesabından "ayırt edilemez" hale gelir.
  • Hesap programa aittir ve lamports tutar: owner == bu program, IDL komutunun bunu işlemesi için önkoşuldur; SOL tutulması durumunda boşaltılma değeri vardır.

Yukarıdaki koşullar karşılandığında, saldırganın yalnızca iki normal işlem yapması yeterlidir: önce IdlCreateBuffer ile controller’ı ele geçirip, ardından IdlCloseAccount ile tüm SOL’u aktararak saldırıyı tamamlayabilir; bu süreçte hedef programdan herhangi bir izin verilmesine gerek yoktur.

1.4 Saldırı Zinciri

Aşağıda, Anchor'un dahili uygulamasını birlikte inceleyerek, saldırganın nasıl sadece iki dahili komut kullanarak sıradan bir fon kasanızı bir IDL hesabına "gizleyip" boşalttığını adım adım açıklayacağız.

Saldırı akışının genel bakışı

Adım 1: IdlCreateBuffer(treasury, signer = attacker)    
└─ treasury.controller  ==>  attacker   (kontrolcü olur) 
Adım 2: IdlCloseAccount(treasury, authority = attacker, dest = attacker)  
  └─ treasury.lamports    ==>  attacker   (hazine boşaltılır)

Adım 1: IdlCreateBuffer ile yetkiyi ele geçirin

Anchor içsel implementasyonu yaklaşık olarak şöyledir:

#[derive(Accounts)]pub struct IdlCreateBuffer {  
#[account(zero)]          // ← Key: bir discriminator değeri tümüyle 0 olan hesap  pub buffer: Account,  
pub authority: Signer,}    
pub fn idl_create_buffer(ctx: Context) -> Result 
{ 
 let idl = &mut ctx.accounts.buffer;  idl.authority = *ctx.accounts.authority.key; // set attack as authority  Ok(())}

#[account(zero)] anlamı: Programın sahibi olan ve discriminator'ı tamamen sıfır olan bir hesabı, başlatılmamış bir IDL hesabı olarak başlatmaktır. Vault ise tam olarak bu iki koşulu aynı anda karşılar:

Kasanın durumu

Şartlar

program tarafından sahiplenildi

init_if_needed sonrası sahip, bu programa atanmıştır

diskriminatör tamamen sıfır

AccountInfo türü kullanılır, Anchor discriminator yazmaz, veriler sıfırdır.

Saldırgan, vault'ı IdlCreateBuffer'a aktardıktan sonra:

  • Anchor, vault öncesinde ilk 8 baytına IdlAccount ayrıştırıcısını yazın;
  • Saldırganın genel anahtarını authority alanına yazın.

Bu şekilde, kasa, saldırganın yetkili olduğu bir IdlAccount olarak "sahte" hale getirildi — içeriğindeki SOL miktarı ise tamamen değişmeden kaldı.

İkinci adım: IdlCloseAccount —— Fonları boşaltın

#[derive(Accounts)]pub struct IdlCloseAccount {  #[account(mut, has_one = authority)]  // ← check authority == signer  pub account: Account,  pub authority: Signer,  #[account(mut)]  pub destination: AccountInfo,  // ← attack wallet}

Şu anda kasa tamamen doğrulandı:

  • discriminator IdlAccount ile eşleştirilir
  • authority alanı = Saldırganın genel anahtarı
  • has_one = authority doğrulaması başarılı

Bu nedenle kasanın içindeki tüm lamports (kullanıcının yatırdığı tüm SOL), yasadışı olarak saldırganın hesabına aktarıldı ve kasa sıfırlandı.

Temel neden:

deposit.rs içinde türlenmiş bir Anchor Hesabı yerine AccountInfo kullanılması, bu güvenlik açığının kritik nedenidir:

(1) Türü olan hesaplar (örneğin Account) başlatıldığında bu yapıya özel 8 bayt discriminator yazılır;

(2) Kendi discriminator'ı yazıldıktan sonra, Anchor, bunu IdlAccount (discriminator uyumsuz) olarak kullanamaz, bu nedenle ilk adım olan IdlCreateBuffer başarısız olur ve saldırı zinciri kırılır.

İkinci: Vaka analizi

Aşağıdaki test, Anchor 0.31.0 ile oluşturulmuş bir çapraz zincir köprü sözleşmesinin PoC'sidir. Test, sahibi köprü uygulaması olan ve kullanıcıların 1.001281 SOL yatırdığı gerçek bir köprü kasanını simüle eder. Saldırgan cüzdanı başlangıçta 2 SOL'a sahiptir ve herhangi bir ayrıcalığa sahip değildir.

Proje

Sayı / Açıklama

Köprü Programı

CJutNlr8d3oxdb11ReOLaZd5jPsqUxgwt2mv5e7equtE

Kasayı (Treasury)

DxGkzaMhP5Wy824GhoehErdD6MudfuEPGPwaV2s77FsM

KuCoin Sahibi

= Köprü programı (programa ait PDA)

KuCoin başlangıç bakiyesi

1.001281 SOL (Kullanıcı tarafından yatırılan tutar)

Başlangıç Controller

0x0000...0000 (tümü sıfır, ayarlanmamış)

Saldırganın cüzdanı başlangıç bakiyesi

2.000000 SOL

Gerekli yetkiler

YOK (Herhangi bir yetki gerekmiyor)

İşlem sayısı

2 adet

KuCoin Son Bakiye

0,000000 SOL (boşaltıldı)

Saldırgan kazanç elde etti

+1.001281 SOL

PoC çalışma ekran görüntüsü (tests/poc-idl-hijack.ts):

https://wdcdn.qpic.cn/MTMxMDI3MDE1MTgxMDU0NzA_812435_a37-yrU_dY02i1_I_1785900257?w=1080&h=1287

Görüldüğü gibi, Adım 1'deki IdlCreateBuffer, saldırganı kasa kontrolörü olarak ayarlıyor (bakiye değişmiyor); Adım 2'deki IdlCloseAccount, kasanın 1,001281 SOL'ünü tamamen saldırganın cüzdanına aktarıyor ve kasa bakiyesini sıfırlıyor.

Düzeltme / Koruma Önerileri:

(1) Anchor sürümünü yükseltin: En son sürüm bu sorunu düzeltti (IDL komutları, IDL hesapları ile iş hesapları arasında sıkı bir ayrım yapar); düşük sürüm Anchor kullanmaktan kaçınmak en doğrudan ve temel savunma yöntemidir.

(2) no-idl etkinleştirilerek yapılandırın: Üretim ortamı programlarında IDL komut enjeksiyonunu açıkça kapatın ve bu saldırı yüzeyini kökten ortadan kaldırın.

(3) Diskriminatörlü ve sahiplik doğrulaması içeren Account / SystemAccount gibi tipleştirilmiş hesapları, boş AccountInfo yerine finansal hesapları taşımak için kullanın, böylece IDL komutları bunları yanlışlıkla tanımlamaz.

(4) Temizlenebilir hesapları sahiplenen minimum program: Fonların depolandığı PDA'ya açık bir sahip/seeds/discriminator kısıtlaması ekleyin ve kritik komutlarda hesap ayrıştırıcısını doğrulayın.

Sonuç

Bu açıklık, "çerçeve gizli komutu + hesap türü tanımlama eksikliği" kombinasyonudur. Geliştiriciler, Anchor'ın varsayılan olarak enjekte ettiği IDL komutlarının gerçek bir saldırı yüzeyi olduğunu anlamalı ve çerçeveyi güncellemeli, ayrıca fon hesaplarında güçlü tip sınırlamaları uygulamalıdır; bu şekilde yetkisiz fon boşaltma riski etkili bir şekilde önlenir.

Beosin, projelerin başlatılmasından önceki akıllı sözleşme güvenlik denetimleri, projelerin çalışması sırasında güvenlik risklerinin izlenmesi ve engellenmesi, çalınan varlıkların geri kazanılması, sanal varlıkların para aklama (AML) önleme ve soruşturma takibi konularında uzmanlaşmış önde gelen bir blockchain güvenlik ve düzenleyici uyumluluk teknolojisi şirketidir. Beosin, dünya çapında 20'den fazla ülke ve bölgedeki düzenleyici ve uygulama kurumlarına, 200'den fazla sanal varlık hizmet sağlayıcısına ve 4.500'den fazla Web3 projesine “tek duraklı” blockchain uyumluluk ürünleri ve güvenlik hizmetleri sunmaktadır. Lütfen公众号 mesaj kutusuna tıklayarak bize ulaşın.

Yasal Uyarı: Bu sayfadaki bilgiler üçüncü şahıslardan alınmış olabilir ve KuCoin'in görüşlerini veya fikirlerini yansıtmayabilir. Bu içerik, herhangi bir beyan veya garanti olmaksızın yalnızca genel bilgilendirme amacıyla sağlanmıştır ve finansal veya yatırım tavsiyesi olarak yorumlanamaz. KuCoin, herhangi bir hata veya eksiklikten veya bu bilgilerin kullanımından kaynaklanan sonuçtan sorumlu değildir. Dijital varlıklara yapılan yatırımlar riskli olabilir. Lütfen bir ürünün risklerini ve risk toleransınızı kendi finansal koşullarınıza göre dikkatlice değerlendirin. Daha fazla bilgi için lütfen Kullanım Koşullarımıza ve Risk Açıklamamıza bakınız.