如何审计Solana 智能合约:系统方法

介绍一下solana智能合约审计和安全的一些系统方法!

images.jpeg 文章开头分享一个区块链安全和智能合约审计的交流群:741631068! And enjoy it!

Solana 因其极低的交易费用而大受欢迎。随着越来越多的高价值 Dapps 在 Solana 上构建,为它们发展审计技术至关重要。

然而,与以太坊(在过去三年中建立了审计规则)相比,审计 Solana 智能合约需要新的和更高级的技能。Solana 在两个主要方面与以太坊不同:

  1. 它使用不同的语言——Rust(相对于以太坊中的 Solidity)
  2. 解耦代码和数据

在本系列文章中,我们将介绍一种系统的方法,包括一些用于审计 Solana 智能合约的自动化技术。

攻击者想要什么以及他们可能做什么?

首先,审计应该_培养攻击者的心态并了解他们的动机.以下是来自攻击者的一些想法:

  • 我可以从智能合约中窃取资金(SPL 代币、SOL 或其他本地货币)吗?
  • 我可以冻结智能合约(锁定用户资金、禁用存款/取款流程、禁用升级等)吗?
  • 我可以制定智能合约来向错误的用户汇款吗?
  • 我可以更改智能合约的关键状态(更改所有者、多重签名所有者或验证者列表)吗?
  • 我可以更改智能合约的代码(将其升级为恶意代码)吗?
  • 我可以低价购买代币吗?
  • 我可以申请比应得的更多的退款吗?
  • 我可以购买超过允许数量的代币吗?
  • ……

上面的列表可以很容易地扩展到包括利用智能合约中任何经济或逻辑错误的攻击。

智能合约中的攻击面有哪些?

然后找出智能合约的所有攻击面。与攻击者可以调用每个公共或外部函数的 Solidity 不同,Solana 智能合约具有单个入口点宏定义:entrypoint!

entrypoint!(process_instruction);
fn process_instruction(
program_id: &Pubkey,
accounts: &[AccountInfo],
instruction_data: &[u8],
) -> ProgramResult 

在上面,函数process_instruction是单一入口点。它传递三个参数:program_id、accounts和instruction_data,后两个参数可以由攻击者控制(除了program_id)。换句话说: 攻击者可以为 Solana 智能合约提供任意数据给参数accounts和instruction_data并加以利用由 program_id 标识的 Solana 智能合约 在process_instruction中,合约可以实现任何业务逻辑。以下显示了solido的代码片段:

pub fn process(program_id: &Pubkey, accounts: &[AccountInfo], input: &[u8]) -> ProgramResult {
let instruction = LidoInstruction::try_from_slice(input)?;
match instruction {
    LidoInstruction::Initialize {…} => process_initialize(…),
    LidoInstruction::Deposit {…} => process_deposit(…),
    LidoInstruction::StakeDeposit { … } => process_stake_deposit(…),
    ...
}

根据instruction_data的解析结果,然后合约调用不同的函数来处理不同的逻辑process_initialize , process_deposit , process_stake_deposit,等等。这些函数可以在accounts中读写数据,调用 Rust 库和 Solana 辅助函数,或者进一步调用其他链上程序. 如果这些代码路径中的任何一个存在缺陷,攻击者可能会利用它们来窃取金钱或做其他坏事。

攻击者可以在 Solana 中利用哪些常见漏洞?

然后,了解Solana 中特定领域的规则和复杂性 。虽然智能合约漏洞和攻击向量的数量在不断增加,但已知的漏洞有多个,有些在所有智能合约中都很常见,有些在 Solana 中是独一无二的:

  1. 缺少签名者检查:如果一条指令只对一组受限制的实体可用,但程序不验证调用是否已由适当的实体签名(例如,通过检查AccountInfo::is_signer)。
  2. 缺少所有权检查:对于不应完全由用户控制的帐户,程序不会检查该AccountInfo::owner字段。
  3. 缺少免租检查:所有持有 Account、Mint 或 Multisig 的 Solana 帐户必须包含足够的 SOL 才能被视为免租。否则帐户可能无法加载。
  4. 未验证程序的签名调用:该程序不验证通过invoke_signed()API 调用的任何程序的公钥。
  5. Solana 账户混淆:该程序无法确保账户数据具有其预期的类型。
  6. 重新启动与跨实例混淆
  7. 算术上溢/下溢:如果算术运算产生更高或更低的值,则该值将用二进制补码环绕。
  8. 数值精度错误:浮点数值计算会导致精度错误,并且这些错误会累积。
  9. 计算精度损失:除法等整数类型的数值计算可能会损失精度。
  10. 不正确的计算:例如,由于 复制/粘贴错误导致的不正确的数值计算
  11. 铸造截断
  12. 计算的指数复杂度
  13. 缺少冻结权限检查
  14. SPL-Token 账户验证不足
  15. 多付/少付贷款

Solana 和 Rust 程序中的一般问题是什么?

审计还应记住,Solana 区块链和 Rust 编程语言存在几个普遍问题,例如跨程序调用的深度、有限的可重入性、不安全的 Rust 等。

  • Solana 跨程序调用的深度:深度目前被限制为 4
  • 可重入性:由于跨程序调用的深度限制,Solana 允许自递归限制在固定深度。这可以防止以太坊中发现的大多数重入攻击。
  • 不安全 Rust 代码:Rust 类型系统 不检查不安全 Rust 代码的内存安全性。因此,如果智能合约包含任何不安全的 Rust 代码,它仍可能遭受内存损坏,例如缓冲区溢出、释放后使用、未初始化的内存等。
  • 过时的依赖项:Rust/Cargo 使管理依赖项变得容易,但依赖项可能已过时或包含已知的安全漏洞。cargo-outdated可用于检查过时的依赖项。
  • 冗余代码:可以清理或简化以降低代码复杂性的重复代码或死代码。
  • 不遵循安全最佳实践:未能正确使用断言、检查用户错误、多重签名等。

检查高层逻辑和经济错误

除了检查这些常见漏洞和一般问题外,审计还应检查智能合约是否存在高级语义错误,例如:

  • 确保合同逻辑正确实施项目规范
  • 详细检查合约特定低级漏洞的代码
  • 排除经济攻击
  • 排除拒绝服务攻击
  • 检查允许抢先运行或夹心攻击的指令
  • 检查可能导致未来引入常见漏洞的不安全设计
  • 检查由 Solana 区块链结构引起的任何其他未知类别的漏洞
  • 检查 rug-pull 机制或隐藏的后门

结尾

Happy for it!

点赞 1
收藏 3
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
Polaris_tow
Polaris_tow
0x215B...F2F1
欢迎一起学习哦,web3世界的守护者! 交流群:741631068 可以加v:zz15842945138 twitter:https://twitter.com/Polaris_tow