Beosin Mengungkap Kerentanan Instruksi IDL Kritikal dalam Kerangka Solana Anchor Versi Lama

iconMetaEra
Kongsi
AI summary iconRingkasan
Pasukan keselamatan Beosin telah mengenal pasti kerentanan arahan IDL kritikal dalam rangka kerja Solana Anchor versi rendah. Kelemahan ini membolehkan penyerang mengambil alih akaun PDA yang dimiliki program dengan memanfaatkan penghujahan AccountInfo, membolehkan pencurian dana dalam dua langkah tanpa keperluan pengguna. Insiden ini menekankan keperluan untuk kerangka pematuhan yang lebih kuat dalam pembangunan kontrak pintar. Dengan MiCA (Peraturan Pasar EU dalam Aset Kripto) yang semakin hampir, kerentanan seperti ini menekankan kepentingan audit keselamatan masa nyata dan kepatuhan terhadap piawaian peraturan.

Anchor adalah kerangka pengembangan paling utama dalam ekosistem Solana. Ia secara besar-besaran mengurangkan rintangan pengembangan melalui ciri-ciri seperti pengesahan akaun deklaratif, pengurutan automatik, dan pemeriksaan keselamatan lalai. Walau bagaimanapun, semasa memberikan kemudahan, kerangka ini secara senyap menyuntikkan beberapa arahan dalaman ke dalam setiap program yang mungkin tidak diketahui oleh pengembang. Arahan "tersembunyi" ini boleh dimanfaatkan oleh penyerang dalam keadaan tertentu, menyebabkan kerugian dana yang serius.

Pasal ini oleh pasukan keselamatan Beosin akan mengungkap corak lubang keamanan penting: dalam versi Anchor yang lebih lama, apabila pembangun menggunakan AccountInfo untuk menyatakan akaun PDA yang dimiliki oleh program, penyerang boleh mengambil alih kawalan akaun dan mengosongkan semua SOL di dalamnya hanya dengan dua langkah menggunakan arahan IDL yang diinject secara automatik oleh Anchor, tanpa memerlukan sebarang keistimewaan.

Satu, Analisis arahan IDL dan mekanisme berkaitan

1.1 Arahan IDL

Anchor secara lalai akan menyuntikkan satu set arahan IDL (Interface Definition Language) ke dalam setiap program, kecuali ciri no-idl diaktifkan secara eksplisit semasa pembinaan. Arahan-arahan ini termasuk:

IdlCreateAccount:Mencipta akaun IDL di rantai

IdlWrite: Menulis data ke akaun IDL / akaun buffer

IdlSetAuthority: Mengubah authority akaun IDL

IdlCloseAccount: Tutup akaun IDL dan pindahkan semua lamports ke penerima yang ditentukan

IdlResizeAccount: Menyesuaikan saiz akaun IDL

IdlCreateBuffer: Mencipta akaun buffer IDL (IDL Buffer)

IdlSetBuffer: Menimpa akaun IDL rasmi dengan data daripada akaun buffer

Perintah-perintah ini dirancang khusus untuk pengurusan IDL di rantai, tetapi perintah-perintah ini mempunyai kemampuan khas terhadap akaun yang dimiliki oleh program (membaca dan menulis data, mengubah pemilik, menutup dan memindahkan lamports) — inilah inti kelemahan tersebut. Penyerang tidak perlu memanggil sebarang perintah perniagaan yang ditulis oleh pembangun; mereka boleh terus memanggil perintah-lalai ini.

1.2 Akaun penyangga IDL

Akaun penyangga IDL (IDL Buffer) ialah akaun sementara yang diperkenalkan oleh Anchor untuk muat naik data IDL besar secara berperingkat. Oleh kerana IDL penuh (ditekan dalam format JSON) mungkin melebihi had saiz satu transaksi, Anchor membenarkan pembinaan buffer terlebih dahulu melalui IdlCreateBuffer, diikuti dengan penulisan bertahap menggunakan beberapa IdlWrite, dan akhirnya diserahkan sekali gus melalui IdlSetBuffer.

Titik utama ialah struktur data akaun IDL / akaun buffer: ia bermula dengan kepala dengan susunan tetap, yang mengandungi medan authority: Pubkey (disebut sebagai controller dalam output ujian artikel ini). Arahan IDL menggunakan medan ini untuk menentukan “siapa yang berkuasa mengendalikan akaun tersebut”.

Namun, masalahnya ialah: logik pemprosesan IdlCreateBuffer pada versi Anchor yang lebih lama akan menginisialisasi mana-mana akaun yang dimiliki oleh program ini sebagai akaun penyangga, dan menetapkan kuasa secara langsung kepada penandatangan transaksi. Dengan kata lain, sekiranya pemilik akaun adalah program ini (contohnya, PDA simpanan program), penyerang boleh menetapkan diri mereka sebagai pengawas akaun tersebut, kemudian menggunakan IdlCloseAccount untuk secara sah memindahkan semua SOL dari akaun tersebut.

1.3 Syarat pemicu lubang keamanan

Pengaktifan lubang ini memerlukan pemenuhan syarat-syarat berikut secara serentak:

  • Menggunakan versi Anchor yang lebih lama: Arahan IDL yang tidak mencukupi dalam pengesahan akaun membenarkan akaun perniagaan disalahanggap sebagai akaun IDL.
  • no-idl tidak diaktifkan: program mengekalkan entri arahan IDL yang disuntik secara lalai semasa pembinaan, membuka permukaan serangan.
  • Menggunakan AccountInfo untuk menyatakan PDA yang dimiliki oleh program: Pembangun menggunakan AccountInfo mentah untuk membawa akaun dana (seperti PDA gudang), tetapi kekurangan discriminator / pemilik yang disediakan oleh akaun bertype Anchor (seperti Account), menjadikan akaun ini tidak dapat dibezakan daripada akaun IDL dalam arahan IDL.
  • Akaun dimiliki dan dipegang oleh program dengan lamports: owner == program ini adalah syarat agar arahan IDL boleh mengendalikannya; hanya mempunyai SOL yang memberikan nilai untuk dikosongkan.

Setelah memenuhi syarat-syarat di atas, penyerang hanya memerlukan dua transaksi biasa: terlebih dahulu IdlCreateBuffer untuk mengambil alih controller, kemudian IdlCloseAccount untuk memindahkan semua SOL, sehingga serangan dapat dilakukan tanpa memerlukan keizinan apa pun dari program sasaran.

1.4 Rantai Serangan

Di bawah ini, dengan menggabungkan pelaksanaan dalam Anchor, kita akan menguraikan secara bertahap bagaimana penyerang hanya menggunakan dua arahan bawaan untuk menyamar sebagai akaun IDL dan mengosongkannya.

Gambaran keseluruhan proses serangan

Langkah 1  IdlCreateBuffer(treasury, signer = attacker)    
└─ treasury.controller  ==>  attacker   (menjadi pengawas) 
Langkah 2  IdlCloseAccount(treasury, authority = attacker, dest = attacker)  
  └─ treasury.lamports    ==>  attacker   (menarik dana dari perbendaharaan)

Langkah pertama: IdlCreateBuffer mengambil kuasa

Anchor melaksanakan dalaman secara kasar seperti berikut:

#[derive(Accounts)] pub struct IdlCreateBuffer {  
#[account(zero)]          // ← Key: akaun dengan discriminatornya semua 0  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; // tetapkan serangan sebagai otoriti  Ok(())}

Maksud #[account(zero)] ialah: menerima akaun yang discriminator-nya semua sifar dan dimiliki oleh program, sebagai akaun IDL yang belum inisialisasi. Vault memenuhi kedua-dua syarat ini:

Status vault

Syarat

dimiliki oleh program

setelah init_if_needed, pemilik ditetapkan kepada program ini

discriminator semua sifar

Menggunakan jenis AccountInfo, Anchor tidak menulis discriminator, data semua sifar

Maka penyerang memasukkan vault ke dalam IdlCreateBuffer selepas itu:

  • Anchor menulis discriminator IdlAccount ke 8 bait pertama sebelum vault;
  • Masukkan kunci awam penyerang ke dalam bidang authority.

Dengan ini, vault telah "disamarkan" sebagai IdlAccount dengan penyerang sebagai otoriti—dan SOL di dalamnya tidak berubah sedikit pun.

Langkah kedua: IdlCloseAccount —— Kosongkan dana

#[derive(Accounts)] pub struct IdlCloseAccount { #[account(mut, has_one = authority)] // ← semak authority == penandatangan pub account: Account, pub authority: Signer, #[account(mut)] pub destination: AccountInfo, // ← dompet serangan}

Vault pada masa ini telah sepenuhnya lulus pengesahan:

  • discriminator sepadan dengan IdlAccount
  • bidang authority = kunci awam penyerang
  • has_one = autoriti disahkan

Oleh itu, semua lamports (SOL yang disetorkan oleh pengguna) dalam vault ditransfer secara sah ke akaun penyerang, menjadikan vault kosong.

Sebab asas:

Menggunakan AccountInfo dalam deposit.rs berbanding dengan Anchor Account yang berjenis adalah punca utama kelemahan ini:

(1) Akaun dengan jenis tertentu (seperti Account) akan menulis discriminator 8 bait khas struktur tersebut semasa inisialisasi;

(2) Setelah discriminator sendiri ditulis, Anchor tidak lagi boleh menganggapnya sebagai IdlAccount (discriminator tidak sepadan), sehingga IdlCreateBuffer pada langkah pertama akan gagal, dan rantai serangan terputus.

Dua, Analisis Kes

Ujian berikut dibina berdasarkan kontrak jambatan lintas rantai PoC yang dibina pada Anchor 0.31.0. Ujian mensimulasikan sebuah dana jambatan (Bridge Treasury) sebenar, di mana pemiliknya ialah program jambatan itu sendiri, yang mengandungi 1.001281 SOL yang disetorkan oleh pengguna. Dompet penyerang awalnya memegang 2 SOL dan tidak memiliki sebarang hak istimewa.

Projek

Nilai / Penerangan

Program Jambatan

CJutNlr8d3oxdb11ReOLaZd5jPsqUxgwt2mv5e7equtE

Akaun Baitul Mal (Treasury)

DxGkzaMhP5Wy824GhoehErdD6MudfuEPGPwaV2s77FsM

Pemilik KuCoin

Program-owned PDA

Saldo awal KuCoin

1.001281 SOL (dana yang disetorkan pengguna)

Controller awal

0x0000...0000 (semua sifar, tidak ditetapkan)

Saldo awal dompet penyerang

2.000000 SOL

Hak yang diperlukan

TIDAK ADA (tidak memerlukan kebenaran apa-apa)

Jumlah transaksi

2 transaksi

Baki akhir KuCoin

0.000000 SOL (dikosongkan)

Penyerang mendapat keuntungan

+1.001281 SOL

Skrin ranah PoC (tests/poc-idl-hijack.ts):

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

Dapat dilihat, IdlCreateBuffer pada Langkah 1 menjadikan penyerang sebagai pengendali gudang (baki tidak berubah); IdlCloseAccount pada Langkah 2 memindahkan seluruh 1.001281 SOL dari gudang ke dompet penyerang, menjadikan baki gudang sifar.

Cadangan pembaikan/penjagaan:

(1) Naik taraf versi Anchor: Versi terkini telah memperbaiki masalah ini (arahan IDL akan membezakan dengan ketat akaun IDL dan akaun perniagaan); mengelakkan penggunaan versi Anchor yang lebih lama adalah langkah pertahanan paling langsung dan paling asas.

(2) Aktifkan no-idl semasa pembinaan: Matikan secara eksplisit penyuntikan arahan IDL untuk program persekitaran pengeluaran, menghapuskan permukaan serangan ini dari sumbernya.

(3) Gunakan akaun berjenis daripada AccountInfo telanjang: Gunakan akaun dana yang dibawa oleh Account / SystemAccount dengan pemeriksaan discriminator dan owner untuk mengelakkan ia disalahertikan oleh arahan IDL.

(4) Meminimumkan akaun yang boleh dikosongkan oleh program: Tambahkan sekatan pemilik / biji / pembez yang jelas kepada PDA yang menyimpan dana, dan semak pembez akaun dalam arahan penting.

Penutup

Kerentanan ini pada dasarnya adalah kombinasi “arahan tersembunyi kerangka kerja + kegagalan pengenalpastian jenis akaun”. Pembangun harus menyedari bahawa arahan IDL yang disuntikkan secara lalai oleh Anchor adalah permukaan serangan yang sebenar, dan dengan meningkatkan versi kerangka kerja serta menerapkan sekatan jenis ketat pada akaun dana, risiko penarikan dana tanpa kebenaran semacam ini boleh dielakkan secara berkesan.

Beosin ialah syarikat teknologi keselamatan blockchain dan kepatuhan peraturan terkemuka, yang berfokus pada audit keselamatan kontrak pintar sebelum pelancaran projek, pemantauan dan penghalangan risiko keselamatan semasa operasi projek, pemulihan aset yang dicuri, anti pencucian wang (AML) aset maya, serta penyiasatan dan pelacakan. Beosin telah menyediakan produk kepatuhan blockchain "sehenti" dan perkhidmatan keselamatan kepada 200 lebih penyedia aset maya dan 4,500 lebih projek Web3 di lebih 20 negara dan wilayah di seluruh dunia. Sila klik kotak pesan di saluran kami untuk menghubungi kami.

Penafian: Maklumat yang terdapat pada halaman ini mungkin telah diperoleh daripada pihak ketiga dan tidak semestinya menggambarkan pandangan atau pendapat KuCoin. Kandungan ini adalah disediakan bagi tujuan maklumat umum sahaja, tanpa sebarang perwakilan atau waranti dalam apa jua bentuk, dan juga tidak boleh ditafsirkan sebagai nasihat kewangan atau pelaburan. KuCoin tidak akan bertanggungjawab untuk sebarang kesilapan atau pengabaian, atau untuk sebarang akibat yang terhasil daripada penggunaan maklumat ini. Pelaburan dalam aset digital boleh membawa risiko. Sila menilai risiko produk dan toleransi risiko anda dengan teliti berdasarkan keadaan kewangan anda sendiri. Untuk maklumat lanjut, sila rujuk kepada Terma Penggunaan dan Pendedahan Risiko kami.