news 2026/9/3 15:22:42

Solana Anchor开发框架的 IDL 指令攻击分析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Solana Anchor开发框架的 IDL 指令攻击分析

Anchor 是 Solana 生态中最主流的开发框架。它通过声明式账户验证、自动序列化和内置安全检查等特性,极大地降低了开发门槛。然而,框架在提供便利性的同时,也在幕后向每个程序注入了一些开发者可能并不了解的内部指令。这些“隐藏”指令在特定条件下可以被攻击者利用,造成严重的资金损失。

本文Beosin安全团队将揭示一个关键漏洞模式:在低版本 Anchor 中,当开发者使用 AccountInfo<'info> 来声明程序拥有(program-owned)的 PDA 账户时,攻击者可以通过 Anchor 自动注入的 IDL 指令,仅需两步操作就能夺取账户控制权并清空其中的所有 SOL,整个过程无需获取任何特权。

一、IDL 指令及相关机制分析

1.1 IDL 指令

Anchor 默认会在每一个程序中注入一组 IDL(Interface Definition Language,接口定义语言)管理指令,除非在构建时显式启用 no-idl feature。这些指令包括:

IdlCreateAccount:创建一个链上 IDL 账户

IdlWrite:向 IDL 账户 / 缓冲账户写入数据

IdlSetAuthority:变更 IDL 账户的 authority(控制者)

IdlCloseAccount:关闭 IDL 账户,并将其全部 lamports 转给指定接收方

IdlResizeAccount:调整 IDL 账户大小

IdlCreateBuffer:创建 IDL 缓冲账户(IDL Buffer)

IdlSetBuffer:用缓冲账户中的数据覆盖正式 IDL 账户

这些指令的设计初衷是用于链上 IDL 管理,但它们对程序拥有的账户具有特殊的操作能力(读写数据、变更控制者、关闭并转走 lamports)——这正是漏洞的核心所在。攻击者不需要调用开发者编写的任何业务指令,直接调用这些内置指令即可。

1.2 IDL 缓冲账户

IDL 缓冲账户(IDL Buffer)是 Anchor 为了分段上传大型 IDL 数据而引入的临时账户。由于完整的 IDL(JSON 压缩后)可能超过单笔交易的大小限制,Anchor 允许先通过 IdlCreateBuffer 建立一个缓冲区,再用多笔IdlWrite 分批写入,最后通过IdlSetBuffer 一次性提交。

关键点在于 IDL 账户 / 缓冲账户的数据结构:它以一个固定布局的头部开头,头部中包含一个 authority: Pubkey 字段(本文测试输出中称之为controller)。IDL 指令通过这个字段判断“谁有权操作该账户”。

而问题在于:低版本 Anchor 的 IdlCreateBuffer 处理逻辑会把传入的、由本程序拥有的任意账户当作缓冲账户来初始化,并将 authority 直接设置为交易签名者。也就是说,只要一个账户的 owner 是本程序(例如程序的 PDA 金库),攻击者就能把自己写成它的 controller,随后再用 IdlCloseAccount 名正言顺地把账户里的 SOL 全部转走。

1.3 漏洞触发条件

该漏洞的触发需要同时满足以下条件:

  • 使用低版本 Anchor:危险的 IDL 指令未做充分的账户判别,允许把业务账户误当作 IDL 账户操作。
  • 未启用 no-idl:程序在构建时保留了默认注入的 IDL 指令入口,攻击面对外暴露。
  • 以 AccountInfo 声明程序拥有的 PDA:开发者用裸的AccountInfo<'info> 承载资金账户(如金库 PDA),缺少 Anchor 类型化账户(如 Account<'info, T>)自带的 discriminator / owner 判别,使该账户在 IDL 指令看来与 IDL 账户“无法区分”。
  • 账户为程序所有且持有 lamports:owner == 本程序 是 IDL 指令能操作它的前提;持有 SOL 才有被清空的价值。

满足以上条件后,攻击者只需两笔普通交易:先 IdlCreateBuffer 夺取 controller,再 IdlCloseAccount 转走全部 SOL,即可完成攻击,全程无需目标程序授予任何权限。

1.4 攻击链

下面结合 Anchor 内部实现,逐步拆解攻击者如何仅用两条内置指令,把一个普通的资金 vault “伪装”成 IDL 账户并将其清空。

攻击流程概览

Step 1 IdlCreateBuffer(treasury, signer = attacker) └─ treasury.controller ==> attacker (become controller) Step 2 IdlCloseAccount(treasury, authority = attacker, dest = attacker) └─ treasury.lamports ==> attacker (drain the treasury)

第一步:IdlCreateBuffer 夺取 authority

Anchor 内部实现大致如下:

#[derive(Accounts)]pub struct IdlCreateBuffer<'info> { #[account(zero)] // ← Key: an account with its discriminator all 0 pub buffer: Account<'info, IdlAccount>, pub authority: Signer<'info>,} 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)] 的含义是:接受一个discriminator 全为零、被程序拥有 的账户,当作未初始化的 IDL 账户来初始化。而 vault 恰好同时满足这两个条件:

vault 的状态

条件

owned by program

init_if_needed 后 owner 被设为本程序

discriminator 全零

使用 AccountInfo 类型,Anchor 不写入 discriminator,数据全零

于是攻击者将 vault 传入 IdlCreateBuffer 后:

  • Anchor 往 vault 前 8 字节写入 IdlAccount 的 discriminator;
  • 将攻击者公钥写入 authority 字段。

至此,vault 被“伪装”成了一个以攻击者为 authority 的 IdlAccount——而它内部的 SOL 分文未动。

第二步:IdlCloseAccount —— 清空资金

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

此时的 vault 已经完全通过校验:

  • discriminator 匹配 IdlAccount
  • authority 字段 = 攻击者公钥
  • has_one = authority 校验通过

因此vault 内所有 lamports(用户存入的全部 SOL)被合法地转入攻击者账户,金库归零。

根本原因:

在deposit.rs 中使用AccountInfo<'info> 而非有类型的 Anchor Account,是本漏洞的致命根源:

(1) 有类型的 Account(如 Account<'info, Vault>)在初始化时会写入该结构体专属的 8 字节 discriminator;

(2) 一旦写入了自身的 discriminator,Anchor 便无法再把它当作 IdlAccount(discriminator 不匹配),第一步的 IdlCreateBuffer 就会失败,攻击链随之断裂。

二、案例分析

以下测试基于Anchor 0.31.0 构建的跨链桥合约 PoC。测试模拟一个真实的桥金库(Bridge Treasury),其 owner 为桥程序本身,内含用户存入的 1.001281 SOL。攻击者钱包最初持有 2 SOL,且不具备任何特权。

项目

数值 / 说明

桥程序 (Bridge Program)

CJutNlr8d3oxdb11ReOLaZd5jPsqUxgwt2mv5e7equtE

金库账户 (Treasury)

DxGkzaMhP5Wy824GhoehErdD6MudfuEPGPwaV2s77FsM

金库 Owner

= 桥程序(program-owned PDA)

金库初始余额

1.001281 SOL(用户存入资金)

初始 Controller

0x0000...0000(全零,未设置)

攻击者钱包初始余额

2.000000 SOL

所需特权

NONE(无需任何授权)

交易笔数

2 笔

金库最终余额

0.000000 SOL(被清空)

攻击者获利

+1.001281 SOL

PoC 运行截图(tests/poc-idl-hijack.ts):

可以看到,Step 1 的 IdlCreateBuffer 把攻击者设置为金库的 controller(余额不变);Step 2 的 IdlCloseAccount 将金库 1.001281 SOL 全部转入攻击者钱包,金库余额归零。

修复/防护建议:

(1) 升级 Anchor 版本:最新版本已修复该问题(IDL 指令会严格区分 IDL 账户与业务账户),避免使用低版本 Anchor是最直接、最根本的防御手段。

(2) 构建时启用 no-idl:对生产环境程序显式关闭 IDL 指令注入,从源头消除该攻击面。

(3)使用类型化账户而非裸 AccountInfo:以Account<'info, T> / SystemAccount 等带 discriminator 与 owner 校验的类型承载资金账户,使其无法被 IDL 指令误认。

(4) 最小化程序拥有的可清空账户:对存放资金的 PDA 增加明确的 owner / seeds / discriminator 约束,并在关键指令中校验账户判别符。

结语

该漏洞本质是“框架隐藏指令 + 账户类型判别缺失”的组合。开发者应认识到 Anchor 默认注入的 IDL 指令是真实存在的攻击面,升级框架版本并对资金账户使用强类型约束,即可有效杜绝此类未授权资金清空风险。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/3 15:20:57

晶闸管原理与应用:从半控特性到相位控制的工程实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/3 15:17:35

人形机器人淘汰赛:从技术演示到量产交付的底层逻辑

近两年&#xff0c;人形机器人几乎成了科技行业最热的关键词。从实验室的步态演示&#xff0c;到工厂里的搬运测试&#xff0c;再到各种行业展会上的整机亮相&#xff0c;赛道热度一直居高不下。但如果你把时间线拉长一点&#xff0c;会发现一个明显信号&#xff1a;行业的叙事…

作者头像 李华
网站建设 2026/9/3 15:14:33

酒桌互动小程序源码解析:轻量级线下社交破冰方案

简介&#xff1a;这是一套专为微信小程序开发者打造的酒桌互动类应用源码&#xff0c;面向前端初学者与轻量级项目实践者&#xff0c;解决聚会场景下快速部署趣味喝酒小游戏的需求。资源共252个文件&#xff0c;包含76个JS逻辑脚本、108个PNG图标与背景图、22个WXSS样式文件、1…

作者头像 李华
网站建设 2026/9/3 15:14:20

SpringBoot+Vue大学生体测管理系统:从架构设计到毕业实践

简介&#xff1a;本资源是一套完整的基于Spring Boot的大学生体质测试管理系统毕业设计实现&#xff0c;面向计算机专业本科生及Java Web开发初学者&#xff0c;解决高校体育教学中体质数据采集、成绩管理与多角色协同的信息化需求。压缩包含797个文件&#xff0c;总计53.23MB&…

作者头像 李华
网站建设 2026/9/3 15:14:13

券商金工研报Python复现实战:从合规代码到生产部署

简介&#xff1a;这是一套面向量化投资初学者与金融工程学习者的Python实战教程资源&#xff0c;专为计算机、人工智能、金融工程等相关专业学生及从业者设计&#xff0c;解决券商金工研报复现难、代码调试无从下手、理论与实操脱节等核心痛点。资源共211个文件&#xff0c;包含…

作者头像 李华
网站建设 2026/9/3 15:14:11

Python自动化预约系统:从协议分析到云服务器部署实战

简介&#xff1a;这是一套面向Java与前端开发者、自动化运维实践者的茅台App多账户自动预约系统源码&#xff0c;专为解决官方渠道抢购难、人工操作效率低等痛点而设计&#xff0c;适用于个人部署、技术学习或小规模商用场景。资源包共556个文件&#xff0c;涵盖209个Java后端核…

作者头像 李华