测试级漏洞合集

简介 拒绝服务 ( Dos - Denial of Service ) 简要概述 DoS 攻击在智能合约中常出现于以下场景: 攻击者通过让某个必要操作持续失败,从而阻止整个合约继续执行关键流程(如奖励分发、批量提款、循环遍历列表等)。 典型示例: 合约在循环中向所有参与者发送 ETH,攻击者故意将自己的 fallback/receive 函数设计为 永远 revert,导致程序在遍历到攻击者地址时整个交易回滚,进而导致奖励分发/提款功能长期瘫痪 易受攻击模式: function distribute() external { for (uint256 i = 0; i < participants.length; i++) { address user = participants[i]; uint256 amount = rewards[user]; // 任意一次 transfer 失败,整个分发流程就会 revert payable(user).transfer(amount); } } 攻击者只需在列表中占据一个位置,即可长期阻塞整个流程。 改进方法 使用 Pull Payment 不再向用户“发送奖励”,而是让用户自己来“领取奖励”,这样单个用户的失败不会影响其他用户 function claim() external { uint256 amount = rewards[msg.sender]; require(amount > 0, "no reward"); // Effects(先修改状态) rewards[msg.sender] = 0; // Interactions(再转账) (bool ok, ) = payable(msg.sender).call{value: amount}(""); require(ok, "send failed"); } CEI 说明: Checks:检查 reward 是否大于 0 Effects:先清零 reward 防止重入 Interactions:最后转账,不会阻塞其他用户 在必须 push 的场景中采用“非阻塞式分发” 避免因为某个地址转账失败而导致整个循环回滚 function distribute() external { for (uint256 i = 0; i < participants.length; i++) { address user = participants[i]; uint256 amount = rewards[user]; (bool ok, ) = payable(user).call{value: amount}(""); if (!ok) { // 可记录失败用户,稍后单独处理 // 不阻塞整体流程 } } } 处理 ETH 不当 ( Mishandling of ETH ) 简要概述 在Solidity智能合约中,“mishandling ETH”错误常指对以太币(ETH)接收和处理的不当管理,尤其在使用delegatecall的批量函数(如提供的batch函数)时。该函数允许通过delegatecall执行多个内部调用,并在同一交易上下文中共享msg.value。主要问题是:如果批量调用包括payable函数(如需要特定msg.value的进入抽奖函数),每个子调用都会看到相同的msg.value,导致合约仅接收一次ETH,但执行多次操作(如多次进入)。例如,在Puppy Raffle审计中,攻击者可通过batch调用多次enterRaffle(每个检查msg.value == entranceFee),仅支付一次费用却进入多次,造成资金损失或不公平。此外,依赖address(this).balance计算费用也易被操纵(如通过selfdestruct强制发送ETH) ...

August 20, 2025 · 8 min · 1540 words · Guangyang Zhong

静态分析漏洞合集

简介 整数溢出(Integer Overflow) 简要概述 在Solidity中,无符号整数(如uint256)在加/减/乘除运算时,若超出类型范围(例如uint256最大值为2^256-1),会发生“回绕”(overflow/underflow),导致意外结果,如余额错误计算、资金无限铸币或丢失。在Solidity <0.8.0版本中无内置检查,易被利用 典型示例: // 错误示范(无溢出检查) pragma solidity ^0.7.0; contract VulnerableToken { mapping(address => uint256) public balances; function transfer(address to, uint256 amount) external { require(balances[msg.sender] >= amount); balances[msg.sender] -= amount; // <-- 可能下溢(underflow) balances[to] += amount; // <-- 可能上溢(overflow) } } 攻击者可利用下溢:若余额为0,减去1会回绕成最大值,导致盗取巨额资金 改进方法 升级到Solidity ^0.8.0+(内置溢出检查,会revert),或使用SafeMath库进行安全运算 示例: // 使用内置检查(Solidity ^0.8.0) pragma solidity ^0.8.0; contract SecureToken { mapping(address => uint256) public balances; function transfer(address to, uint256 amount) external { require(balances[msg.sender] >= amount, "insufficient"); balances[msg.sender] -= amount; // 内置检查:下溢会revert balances[to] += amount; // 内置检查:上溢会revert } } 额外建议:对于旧版本,使用OpenZeppelin的SafeMath库(如balances[msg.sender] = balances[msg.sender].sub(amount));始终审计数学运算,并使用有界类型(如uint128)减少风险 不安全类型转换(Unsafe Casting) 简要概述 Solidity中进行类型转换时(如从较大类型uint256到较小类型uint8),若值超出目标类型范围,会发生隐式截断(truncation)或溢出,导致数据丢失、意外行为或安全漏洞,如余额计算错误或权限绕过。Solidity不默认检查转换安全,易被利用。 典型示例: // 错误示范(无安全检查) pragma solidity ^0.8.0; contract VulnerableVault { mapping(address => uint256) public balances; function deposit() external payable { balances[msg.sender] += msg.value; } function withdraw(uint8 amount) external { // uint8 仅0-255 require(balances[msg.sender] >= amount); balances[msg.sender] -= amount; payable(msg.sender).transfer(amount); // <-- 若amount实际>255,转换截断导致少转账 } } 攻击者传入>255的值,转换截断成小值,导致实际提取远超预期(但余额扣除完整值) ...

August 20, 2025 · 5 min · 856 words · Guangyang Zhong

低级漏洞合集

简介 此章节主要整理一些智能合约开发中的低级漏洞,适合初学者了解和防范。这些漏洞虽然"低级",但在实际项目中仍然频繁出现,可能导致严重的安全问题 不正确的 NatSpec 注释 什么是 NatSpec NatSpec(Ethereum Natural Language Specification Format)是 Solidity 的文档格式标准,用于生成用户文档和开发者文档 常见问题 // ❌ 现实审计中高频出现:transferFrom 注释完全错误 /// @title 代币转账函数 /// @notice 将代币从接收者地址转给发送者地址 ← ❌ 完全颠倒 /// @dev 使用用户的授权额度进行转账 /// @param from 接收代币的人 ← ❌ 注释与代码逻辑相反 /// @param to 发送代币的人 ← ❌ 注释与代码逻辑相反 /// @param amount 转账数量 function transferFrom(address from, address to, uint256 amount) external returns (bool); // ✅ 正确的 NatSpec 注释 /// @title 授权转账函数 /// @notice 从 `from` 账户扣除代币并转入 `to` 账户 /// @dev 需要调用者拥有足够的授权额度 /// @param from 代币来源账户(被扣款方) /// @param to 代币接收账户 /// @param amount 转账代币数量 /// @return success 转账是否成功 function transferFrom(address from, address to, uint256 amount) external returns (bool success); NatSpec 标签说明 @title:合约或函数的标题 @author:作者信息 @notice:给最终用户看的说明 @dev:给开发者看的详细说明 @param:参数说明 @return:返回值说明 @inheritdoc:继承父合约的文档 将隐私信息存于链上 问题描述 开发者误以为将变量声明为 private 就能保护数据隐私。 ...

August 16, 2025 · 2 min · 295 words · Guangyang Zhong