本文介绍了 Trident,一个为 Solana 程序设计的模糊测试框架,它采用了手动引导的模糊测试(MGF)技术,旨在帮助开发者更有效地发现 Solana 程序中特有的漏洞,例如账户混淆、并行执行中的竞态条件和跨程序调用(CPI)相关的漏洞。文章还提供了使用 Trident 进行模糊测试的策略、最佳实践和高级技术。
直到最近,Solana 开发者几乎无法使用模糊测试工具。虽然以太坊拥有成熟的模糊测试生态系统,但到目前为止,Solana 的安全测试主要包括单元测试、集成测试和尚未投入生产的学术研究工具。
Trident 改变了这一点,它将最先进的智能合约模糊测试技术,手动引导模糊测试 (MGF),直接带到 Solana 程序中。这使 Solana 开发者能够享受用于安全测试的最佳模糊测试方法。
单元测试和集成测试提供了重要的基础级别保护,但它们会遗漏复杂的边界情况。 传统的黑盒模糊测试试图通过暴力破解来探索整个状态空间,但 Solana 程序的状态空间太大,无法完全搜索。
关键问题在于黑盒模糊器要么在任意点停止,要么实现启发式方法来引导探索。 这两种方法都会遗漏关键漏洞。
MGF 不是依赖于算法启发式,而是使开发者和安全研究人员能够:
这种方法已在我们以太坊安全工作中证明有效,始终发现其他自动化方法和手动审计遗漏的漏洞。
Solana 的执行模型在状态管理方面与以太坊的 EVM 不同。与维护内部持久存储的以太坊合约不同,Solana 程序 是无状态的可执行文件,它们对每次交易中传递的外部账户进行操作。
这种分离启用了 Solana 的并行处理能力,但也引入了特定类型的漏洞。 通用的模糊测试工具会遗漏这些独特的攻击向量。
Solana 程序 必须显式验证交易中提供的每个账户,从而为账户混淆攻击创造机会。 当攻击者实际提供了恶意替代品时,程序可能会假定某个账户是其拥有的程序派生地址 (PDA) 之一。
漏洞模式示例:
// Vulnerable: No ownership verification
// 易受攻击:没有所有权验证
pub fn process_instruction(
program_id: &Pubkey,
accounts: &[AccountInfo],
instruction_data: &[u8],
) -> ProgramResult {
let vault_account = &accounts[0]; // Assumes this is the correct vault
// 假设这是正确的 vault
// Process without verifying vault_account.owner == program_id
// 在不验证 vault_account.owner == program_id 的情况下进行处理
}
黑盒模糊测试无法系统地发现这些漏洞,因为它没有考虑预期的账户关系。 MGF 定义了测试账户替换场景的特定流程。
当 Solana 的 Sealevel 运行时在账户访问上没有冲突时,它会并发执行交易。 虽然账户锁定可以防止基本的竞争条件,但仍然会出现细微的时序问题,尤其是在多指令交易和跨程序调用 (CPI) 附近。
Solana 程序 经常通过 CPI 调用其他程序,从而创建复杂的交易流程。 单个用户交易可以在不同程序中打包多个指令,每个指令都可能回调到其他程序。 这会创建 Solana 特定的攻击面,例如程序无法验证目标程序 ID 的任意 CPI 漏洞。
账户恢复:账户关闭和恢复攻击发生在程序通过将 lamport 归零而不进行适当标记来关闭账户时。 攻击者可以通过将 lamport 转回同一交易中来“恢复”账户。
MGF 流程示例:
## Flow 1: Close account (zeroes lamports)
# 流程 1:关闭账户(将 lamport 归零)
def flow_close_account():
close_user_stake_account(attacker_account)
## Flow 2: Revive account (same transaction)
# 流程 2:恢复账户(同一交易)
def flow_revive_account():
system_transfer(attacker, closed_account, 1_lamport)
## Flow 3: Exploit revived account
# 流程 3:利用恢复的账户
def flow_exploit_revived():
claim_rewards(closed_account) # Should fail but might succeed
# 应该失败但可能会成功
## Invariant: Closed accounts should not be reusable
# 不变性:关闭的账户不应可重用
@invariant
def account_closure_invariant():
assert closed_accounts_are_not_exploitable()
缺少签名者检查:FuzzDelSol 研究在许多已部署的程序中发现了此类漏洞,在这些程序中,关键操作在没有适当的签名者验证的情况下进行。
任意 CPI 攻击:允许用户指定的程序 ID 的程序通过模仿合法接口的恶意程序创建攻击向量。
漏洞模式:
// Dangerous: User-controlled program_id
// 危险:用户控制的 program_id
invoke(
&token_instruction,
&[\
user_provided_token_program.clone(), // Attacker controls this\
// 攻击者控制这个
source_account.clone(),\
dest_account.clone(),\
],
)?;
Trident 0.11.0 是 Solana 安全测试方面迈出的重要一步。 虽然以太坊已经有了手动引导模糊测试多年,但 Solana 开发者以前缺乏用于这种高级测试方法的原生工具。Trident 将最复杂的 智能合约 测试技术直接引入 Solana 的执行模型。
黑盒模糊测试依赖于统计抽样来查找漏洞,Trident 能够系统地构建攻击场景。 这种有针对性的方法已经在领先的 Solana 协议中发现了漏洞,证明了引导式发现优于暴力破解的力量。
为什么要使用 Trident:
在主要协议上经过实战测试:
Trident 已通过与领先的 Solana 项目的实际实施得到验证:
这些部署证明了 Trident 处理复杂的生产级协议的能力,在这些协议中,安全故障可能会导致重大财务损失。
替代工具: Mollusk 为高性能场景提供轻量级 SVM 执行。 自定义集成使用 RPC 接口,但会牺牲进程内的性能优势。
首先,使用 Solana 工具链、Anchor 框架 和所选的模糊测试工具设置测试环境。
对于 Trident 集成:
cargo install trident-cli
trident init your-project
不变性是在任何操作序列之后必须始终成立的属性。 它们是在每次流程执行后进行检查的安全断言。
定义捕获基本安全属性的不变性:
流程表示序列中的单个测试步骤。 可以将其视为更大攻击场景中的单个交易或指令调用。 流程允许你通过将特定指令链接在一起来模拟真实世界的攻击模式。
根据程序功能和已知的漏洞模式识别关键指令序列。 专注于可能暴露竞争条件或状态不一致的多指令交易。
确保模糊测试活动覆盖:
在高-级语言中实现复杂数学运算的简化模型,以便与链上实施进行比较。
该技术已证明可以有效地识别 Solidity 库中的精度误差,并且同样适用于处理金融计算的 Solana 程序。
虽然 Solana 不支持像以太坊的 Anvil 那样的直接主网 Fork,但开发者可以将特定的主网账户克隆到测试环境中。
这使得能够针对真实的链上数据进行测试,同时保持测试环境的安全性。
Solana 的计算预算限制对模糊测试场景施加了实际限制。 设计流程以保持在实际交易计算限制范围内,同时仍能执行关键代码路径。
考虑使用 Mollusk 来进行高性能是优先事项的高迭代场景。
Solana 上的手动引导模糊测试需要深入了解程序逻辑和 Solana 的执行模型。 该技术擅长查找复杂的交互错误,但严重依赖于定义的流程和不变性的质量。
MGF 的主要局限性:
缓解策略:
Solana 的架构需要专业的安全方法。 MGF 将测试从数百个单独的集成测试转变为系统的攻击向量验证,从而发现现有方法遗漏的漏洞。
成功需要了解 Solana 的独特特征和相关的攻击向量。 其回报是在生产部署之前系统地发现细微的漏洞。
Solana 生态系统的安全性取决于积极的测试方法,这些方法能够跟上日益复杂的协议。 Trident 为从第一天起将安全性构建到开发工作流程中奠定了基础。
Trident 使任何 Solana 开发团队都可以使用手动引导模糊测试。 该框架是开源的,旨在根据你的安全需求而发展,从基本的模糊测试到引导式精确测试。
开始使用:
cargo install trident-cli
- 原文链接: ackee.xyz/blog/trident-b...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!