├── README_CN.md └── README.md /README_CN.md: -------------------------------------------------------------------------------- 1 | # 慢雾安全团队 SUI Move 合约审计方法 2 | 3 | ![https://img.shields.io/twitter/url/https/twitter.com/slowmist_team.svg?style=social&label=Follow%20%40SlowMist_Team](https://img.shields.io/twitter/url/https/twitter.com/slowmist_team.svg?style=social&label=Follow%20%40SlowMist_Team) 4 | 5 | [English Version](./README.md) 6 | 7 | - [慢雾安全团队 SUI Move 合约审计方法](#慢雾安全团队-sui-move-合约审计方法) 8 | - [关键知识点](#关键知识点) 9 | - [1. 模块声明和可见性](#1-模块声明和可见性) 10 | - [1.1 `public(friend)` 函数(在最新的Sui的版本中 `public(friend)`替换成 `public(package)`)](#11-publicfriend-函数在最新的sui的版本中-publicfriend替换成-publicpackage) 11 | - [1.2 `entry` 函数](#12-entry-函数) 12 | - [1.3 `public` 函数](#13-public-函数) 13 | - [2. 对象管理](#2-对象管理) 14 | - [2.1 对象的唯一性](#21-对象的唯一性) 15 | - [2.2 包装和解包](#22-包装和解包) 16 | - [2.3 自定义转移策略](#23-自定义转移策略) 17 | - [2.4 对象的属性](#24-对象的属性) 18 | - [2.5 对象的权限检查](#25-对象的权限检查) 19 | - [Address-Owned Objects](#address-owned-objects) 20 | - [Immutable Objects](#immutable-objects) 21 | - [Shared Objects](#shared-objects) 22 | - [Wrapped Objects](#wrapped-objects) 23 | - [3. 安全性检查](#3-安全性检查) 24 | - [3.1 数值溢出检查](#31-数值溢出检查) 25 | - [3.2 重入检查](#32-重入检查) 26 | - [审计入门](#审计入门) 27 | - [溢出审计 Overflow Audit](#溢出审计-overflow-audit) 28 | - [算术精度误差审计 Arithmetic Accuracy Deviation Audit](#算术精度误差审计-arithmetic-accuracy-deviation-audit) 29 | - [条件竞争审计 Race Conditions Audit](#条件竞争审计-race-conditions-audit) 30 | - [访问控制审计 Access Control Audit](#访问控制审计-access-control-audit) 31 | - [对象管理审计 Object Management Audit](#对象管理审计-object-management-audit) 32 | - [Token 代币消耗审计 Token Consumption Audit](#token-代币消耗审计-token-consumption-audit) 33 | - [闪电贷攻击审计 Flashloan Attack Audit](#闪电贷攻击审计-flashloan-attack-audit) 34 | - [权限漏洞审计 Permission Vulnerability Audit](#权限漏洞审计-permission-vulnerability-audit) 35 | - [合约升级的安全审计 Smart Contract Upgrade Security Audit](#合约升级的安全审计-smart-contract-upgrade-security-audit) 36 | - [外部调用安全审计 External Call Function Security Audit](#外部调用安全审计-external-call-function-security-audit) 37 | - [返回值的检查 Unchecked Return Values](#返回值的检查-unchecked-return-values) 38 | - [拒绝服务审计 Denial of Service Audit](#拒绝服务审计-denial-of-service-audit) 39 | - [Gas 优化审计 Gas Optimization Audit](#gas-优化审计-gas-optimization-audit) 40 | - [设计逻辑审计 Design Logic Audit](#设计逻辑审计-design-logic-audit) 41 | - [其他 Others](#其他-others) 42 | - [参考](#参考) 43 | 44 | 45 | ## 关键知识点 46 | 47 | ### 1. 模块声明和可见性 48 | 49 | #### 1.1 `public(friend)` 函数(在最新的Sui的版本中 `public(friend)`替换成 `public(package)`) 50 | 51 | **定义**: 52 | 53 | `public(friend)`(最新版本中为 `public(package)`)用于声明函数,使其只能被指定的友元模块访问。这提供了更细粒度的访问控制,介于 `public` 和 `private` 之间。 54 | 55 | **示例**: 56 | 57 | ``` 58 | public(friend) fun example_function() { 59 | // 仅友元模块可调用 60 | } 61 | ``` 62 | 63 | #### 1.2 `entry` 函数 64 | 65 | **定义**: 66 | 67 | `entry` 函数是模块的入口点,允许从事务块中直接调用。参数必须来自事务块的输入,不能是块中先前事务的结果或被修改的数据。此外,`entry` 函数只能返回具有 `drop` 能力的类型。 68 | 69 | **示例**: 70 | 71 | ``` 72 | public entry fun transfer_coin(coin: Coin, recipient: address) { 73 | // 事务入口函数 74 | } 75 | ``` 76 | 77 | #### 1.3 `public` 函数 78 | 79 | **定义**: 80 | 81 | `public` 函数可以从事务块和其他模块调用,适合外部交互。在参数和返回值上没有和 `entry` 函数一样的限制,通常用于将功能暴露给外部。 82 | 83 | **示例**: 84 | 85 | ``` 86 | public fun get_balance(account: &Account): u64 { 87 | // 允许外部模块和事务块调用 88 | account.balance 89 | } 90 | ``` 91 | 92 | ### 2. 对象管理 93 | 94 | #### 2.1 对象的唯一性 95 | 96 | **定义**: 97 | 98 | 每个 SUI 对象都有唯一的 `objID`,确保了对象在链上的唯一性。 99 | 100 | #### 2.2 包装和解包 101 | 102 | **定义**: 103 | 104 | - **直接包装**:将一个 SUI 对象作为另一个对象的字段,解包时必须销毁包装对象。 105 | - **对象包装**:包装后的对象成为另一对象的一部分,不再独立存在。解包后对象的 ID 不变。 106 | 107 | #### 2.3 自定义转移策略 108 | 109 | **定义**: 110 | 111 | ​ 使用 `sui::transfer::transfer` 定义自定义转移策略,针对具有 `store` 能力的对象,可以通过 `sui::transfer::public_transfer` 创建。 112 | 113 | #### 2.4 对象的属性 114 | 115 | **定义**: 116 | 117 | ​ SUI 对象的属性包括 `copy`, `drop`, `store`, 和 `key`,这些属性决定了对象的行为方式。 118 | 119 | #### 2.5 对象的权限检查 120 | 121 | ##### Address-Owned Objects 122 | 123 | **定义**: 124 | 125 | ​ 由特定地址(账户地址或对象 ID)拥有的对象,只有对象的所有者可以访问和操作这些对象。 126 | 127 | ##### Immutable Objects 128 | 129 | **定义**: 130 | 131 | ​ 不可变对象无法被修改或转移,任何人都可以访问。适用于需要全局访问但不需要修改的数据。 132 | 133 | ##### Shared Objects 134 | 135 | **定义**: 136 | 137 | ​ 共享对象可以被多个用户访问和操作,适用于去中心化应用等场景,但由于需要共识,操作成本较高。 138 | 139 | ##### Wrapped Objects 140 | 141 | **定义**: 142 | 143 | ​ 包装对象是将一个对象嵌入另一个对象,包装后的对象不再独立存在,必须通过包装对象访问。 144 | 145 | ## 3. 安全性检查 146 | 147 | ### 3.1 数值溢出检查 148 | 149 | Sui Move 默认进行数值溢出检查。 150 | 151 | ### 3.2 重入检查 152 | 153 | 所谓的重入攻击是在一笔正常的合约调用交易中,被插入一笔非预期的(外部)调用,从而改变整体的业务调用流程然后进行非法获利的问题。涉及到外部合约调用的位置,都可能存在潜在的重入风险。目前的重入问题我们可以分为三类:单函数重入、跨函数重入以及跨合约重入。 154 | 155 | - Move 中无动态调用,其外部调用都需先通过 use 进行导入,即外部调用都是预期、确定的 156 | - 无 Native 代币转账触发 Fallback 功能 157 | - 在 Move 中,资源模型确保资源一次只能由单个执行上下文访问。这意味着如果函数执行未完成,则在执行完成之前其他函数无法访问同一资源。 158 | 159 | 160 | 161 | # 审计入门 162 | 163 | 164 | 165 | ## 溢出审计 Overflow Audit 166 | 167 | **说明**: 168 | 169 | Move 进行数学运算时会进行溢出检查,运算溢出交易将失败。但需要注意的是位运算并不会进行检查。此外,自定义溢出检测函数可能存在缺陷,导致数值截断问题。 170 | 171 | **定位**: 172 | 173 | - 寻找代码中进行位运算的位置,检查是否有溢出风险。 174 | - 检查自定义溢出检测函数的阈值设置和边界条件判断。 175 | - 验证位移操作后是否会超出目标类型最大值而被截断。 176 | 177 | **示例**: 178 | 179 | ```move 180 | // 错误示例 181 | public fun checked_shlw(n: u256): (u256, bool) { 182 | let mask = 0xffffffffffffffff << 192; // ❌ 错误的掩码 任何小于 `0xffffffffffffffff << 192` 的值都可以通过 183 | if (n > mask) { // ❌ 错误的判断条件 184 | (0, true) 185 | } else { 186 | ((n << 64), false) // ⚠️ 左移溢出被截断 187 | } 188 | } 189 | ``` 190 | 191 | 192 | ## 算术精度误差审计 Arithmetic Accuracy Deviation Audit 193 | 194 | **说明**: 195 | 196 | Move 中没有浮点类型。因此,在进行算术运算时,如果运算结果需要以浮点数表示,可能会产生精度误差。虽然精度误差在某些情况下难以完全避免,但可以通过优化和合理设计来减轻其影响。 197 | 198 | **定位**: 199 | 200 | 审查代码中所有涉及算术运算的部分,特别是可能产生精度误差的计算,确保这些运算不会对合约逻辑或数值准确性产生负面影响,并提出优化建议以减轻精度误差。 201 | 202 | 203 | 204 | ## 条件竞争审计 Race Conditions Audit 205 | 206 | **说明**: 207 | 208 | Sui 中的验证者也可以对用户提交的交易进行排序,因此在审计中我们仍需要注意在同一个区块中对交易进行排序而进行获利的问题。 209 | 210 | **定位**: 211 | 212 | - 是否有对`函数调用前`合约的数据状态进行预期管理。 213 | - 是否有对`函数执行中`的合约数据状态进行预期管理。 214 | - 是否有对`函数调用后`的合约数据状态进行预期的管理。 215 | 216 | 217 | 218 | ## 访问控制审计 Access Control Audit 219 | 220 | **说明**: 221 | 222 | 合约中的某些关键函数应仅限于内部调用,例如能够直接更新用户存款数额的函数。如果这些函数不慎对外部开放,可能绕过权限控制,导致安全漏洞,甚至引发资产损失。因此,必须严格设置访问权限,确保只有授权角色或模块可以调用这些函数,或者确保函数只能在内部使用。 223 | 224 | **定位**: 225 | 226 | 需要检查所有函数的访问控制设置,特别是那些不应该对外公开的函数,确保它们只能在内部调用。如果发现不应暴露的函数接口已经公开,必须标记为高风险并提出修正建议。 227 | 228 | 229 | 230 | ## 对象管理审计 Object Management Audit 231 | 232 | **说明**: 233 | 234 | 在 SUI 中,对象可以被转换为共享对象(Shared Object),这意味着对象的访问权限可能从私有变为公共。因此,需要对所有使用的对象进行详细审查,明确每个对象是静态的还是共享的。特别要注意是否有对象被错误地从私有对象转换为共享对象,这样可能导致未经授权的用户访问这些对象,带来潜在的安全风险。 235 | 236 | **定位**: 237 | 238 | 整理并分析模块中所有涉及的对象,检查对象的类型和权限设置,确保该对象的权限与业务需求匹配。如果发现私有对象被错误地转换为共享对象,必须标记为潜在风险并提出修正建议。 239 | 240 | 241 | 242 | ## Token 代币消耗审计 Token Consumption Audit 243 | 244 | **说明**: 245 | 246 | SUI 的代币模型与其他链的代币模型有所不同。SUI 允许对象持有代币,并且代币对象可以嵌套在其他对象中,还可以进行拆分。因此,在涉及代币消耗的场景中,需要特别关注代币的管理和流转,以避免安全问题或意外损失。 247 | 248 | **定位**: 249 | 250 | 在审计代币消耗时,需要检查以下关键点: 251 | 252 | 1. 消耗的金额是否准确。 253 | 2. 代币对象是否已经正确转移。 254 | 3. 代币的拆分和合并是否合理。 255 | 4. 检查代币与对象的绑定。 256 | 257 | ## 闪电贷攻击审计 Flashloan Attack Audit 258 | 259 | **说明**: 260 | 261 | Sui 的 Move 也有闪电贷的用法(Hot Potato)。用户可以在一笔交易中借取大量的资金任意使用,只需在这笔交易内归还资金即可。恶意用户通常使用闪电贷放大自身的资金规模进行价格操控等大资金攻击。 262 | 263 | **定位**: 264 | 265 | 分析协议本身的算法(奖励、利率等)、预言机依赖是否合理。 266 | 267 | ## 权限漏洞审计 Permission Vulnerability Audit 268 | 269 | **说明**: 270 | 271 | 在 Sui 的 Move 合约中权限漏洞这部分和业务的需求以及功能设计关系较大,所以遇见较为复杂的 Module 的时候,就需要和项目方一一确认各个方法的调用权限。这里的权限一般是指函数的可见性和函数的调用权限。 272 | 273 | **定位**: 274 | 275 | - 检查和确认所有函数方法的可见性及调用权限,在项目评估阶段就需要项目方提供设计文档,审计时候根据设计文档中的描述一一确认权限。 276 | 277 | - 梳理项目方角色的权限范围,如果项目方角色的权限会影响用户的资产,则存在权限过大的风险。 278 | 279 | - 分析对外函数里面传递进去的对象是什么类型的对象,如果是一些特权函数那必须要有一些特权对象参与。 280 | 281 | 282 | 283 | ## 合约升级的安全审计 Smart Contract Upgrade Security Audit 284 | 285 | **说明**: 286 | 287 | 在 Move 中,外部模块通过 `use` 关键字导入。需要注意的是,Sui 的合约是可升级的,但发布的合约包(package)是不可变的对象,一旦发布就无法撤回或修改。合约升级的本质是通过在新的地址上重新发布更新的合约,并将旧版本合约的数据迁移至新的合约中。因此,合约升级过程中需要特别注意以下几点: 288 | 289 | - **init 函数**:`init` 函数仅在合约第一次发布时执行,后续合约升级时不会再次触发。 290 | - **升级合约不会自动更新依赖**:如果您的合约包依赖于外部包,当外部包升级时,您的合约包不会自动指向升级后的合约地址。您需要手动升级自己的合约包以指定新的依赖项。 291 | 292 | **定位**: 293 | 294 | 需要对合约升级过程中数据迁移的逻辑进行详细检查,确保迁移操作安全、准确,并避免遗漏重要数据或依赖更新的问题。 295 | 296 | 297 | 298 | ## 外部调用安全审计 External Call Function Security Audit 299 | 300 | **说明**: 301 | 302 | 与外部模块使用审计项相同,由于 Move 中进行外部调用需要先将外部模块导入,因此理论上外部调用的结果都是开发人员所预期,所需主要的是外部模块的稳定性。 303 | 304 | **定位**: 305 | 306 | 需要对外部引入的库进行检查。 307 | 308 | 309 | 310 | ## 返回值的检查 Unchecked Return Values 311 | 312 | **说明**: 313 | 314 | 在 Move 合约中,和其他智能合约语言类似,某些函数的返回值需要进行检查。如果忽略了对这些返回值的处理,可能会导致关键逻辑没有正确执行,进而引发安全问题。 315 | 316 | **定位**: 317 | 318 | 需要检查代码中每个函数调用的返回值,特别是那些涉及外部调用或重要状态更新的函数。如果返回值未被处理或验证,可能会导致不可预期的行为,应该标注为潜在风险点。 319 | 320 | 321 | 322 | ## 拒绝服务审计 Denial of Service Audit 323 | 324 | **说明**: 325 | 326 | 拒绝服务(DoS)攻击可能由代码逻辑错误、兼容性问题或其他安全漏洞引发,导致智能合约无法正常运行。此类问题可能影响合约的可用性,甚至使其完全瘫痪。 327 | 328 | **定位** 329 | 330 | - 重点检查业务逻辑的健壮性,确保在各种情况下都能正常执行,不会因错误或漏洞导致合约中断。 331 | 332 | - 关注与外部模块交互的部分,确保其兼容性,以防止由于外部依赖问题导致的服务中断。 333 | 334 | 335 | 336 | ## Gas 优化审计 Gas Optimization Audit 337 | 338 | **说明**: 339 | 340 | 与以太坊一样,Sui 也有 Gas 机制,任何模块脚本调用都会消耗 Gas。因此对一些冗长且高复杂度的代码进行优化是有必要的。 341 | 342 | **定位**: 343 | 344 | - 涉及到复杂的调用看是否可以解耦。 345 | - 涉及到高频率的调用看是否可以优化函数内部执行的效率。 346 | 347 | 348 | 349 | ## 设计逻辑审计 Design Logic Audit 350 | 351 | **说明**: 352 | 353 | 设计逻辑审计的重点是检查代码中的业务流程和实现,确认是否存在设计缺陷或与预期不符的情况。代码实现如果与预期逻辑不一致,可能会导致意外的行为或安全风险。 354 | 355 | **定位**: 356 | 357 | - 根据不同角色的权限和作用范围,梳理业务流程中的可能调用路径。 358 | - 确定每个业务流程所涉及的数据范围,确保数据的操作与业务设计一致。 359 | - 将实际的调用路径与预期的业务流程进行比较,识别并分析任何可能导致非预期结果的调用情况。 360 | 361 | ## 其他 Others 362 | 363 | 未在上述表述中体现的内容。 364 | 365 | # 参考 366 | 367 | 368 | [Sui book](https://intro.sui-book.com/) 369 | 370 | [Sui Doc](https://docs.sui.io/) 371 | 372 | [Move Book CN](https://move-dao.github.io/move-book-zh/introduction.html) 373 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SlowMist Security Team SUI Move Contract Audit Method 2 | 3 | ![https://img.shields.io/twitter/url/https/twitter.com/slowmist_team.svg?style=social&label=Follow%20%40SlowMist_Team](https://img.shields.io/twitter/url/https/twitter.com/slowmist_team.svg?style=social&label=Follow%20%40SlowMist_Team) 4 | 5 | [中文版本](./README_CN.md) 6 | - [SlowMist Security Team SUI Move Contract Audit Method](#slowmist-security-team-sui-move-contract-audit-method) 7 | - [Key Knowledge Points](#key-knowledge-points) 8 | - [1. Module Declarations and Visibility](#1-module-declarations-and-visibility) 9 | - [1.1 `public(friend)` Function (Replaced by `public(package)` in the Latest Version of Sui)](#11-publicfriend-function-replaced-by-publicpackage-in-the-latest-version-of-sui) 10 | - [1.2 `entry` Function](#12-entry-function) 11 | - [1.3 `public` Function](#13-public-function) 12 | - [2. Object Management](#2-object-management) 13 | - [2.1 Object Uniqueness](#21-object-uniqueness) 14 | - [2.2 Wrapping and Unwrapping](#22-wrapping-and-unwrapping) 15 | - [2.3 Custom Transfer Strategy](#23-custom-transfer-strategy) 16 | - [2.4 Object Properties](#24-object-properties) 17 | - [2.5 Object Permission Checks](#25-object-permission-checks) 18 | - [Address-Owned Objects](#address-owned-objects) 19 | - [Immutable Objects](#immutable-objects) 20 | - [Shared Objects](#shared-objects) 21 | - [Wrapped Objects](#wrapped-objects) 22 | - [3. Security Checks](#3-security-checks) 23 | - [3.1 Overflow Checks](#31-overflow-checks) 24 | - [3.2 Reentrancy Checks](#32-reentrancy-checks) 25 | - [Audit Basics](#audit-basics) 26 | - [Overflow Audit](#overflow-audit) 27 | - [Arithmetic Accuracy Deviation Audit](#arithmetic-accuracy-deviation-audit) 28 | - [Race Conditions Audit](#race-conditions-audit) 29 | - [Access Control Audit](#access-control-audit) 30 | - [Object Management Audit](#object-management-audit) 31 | - [Token Consumption Audit](#token-consumption-audit) 32 | - [Flashloan Attack Audit](#flashloan-attack-audit) 33 | - [Permission Vulnerability Audit](#permission-vulnerability-audit) 34 | - [Smart Contract Upgrade Security Audit](#smart-contract-upgrade-security-audit) 35 | - [External Call Function Security Audit](#external-call-function-security-audit) 36 | - [Unchecked Return Values](#unchecked-return-values) 37 | - [Denial of Service Audit](#denial-of-service-audit) 38 | - [Gas Optimization Audit](#gas-optimization-audit) 39 | - [Design Logic Audit](#design-logic-audit) 40 | - [Others](#others) 41 | - [References](#references) 42 | 43 | 44 | ## Key Knowledge Points 45 | 46 | ### 1. Module Declarations and Visibility 47 | 48 | #### 1.1 `public(friend)` Function (Replaced by `public(package)` in the Latest Version of Sui) 49 | 50 | **Definition**: 51 | 52 | `public(friend)` (replaced by `public(package)` in the latest version) is used to declare functions that can only be accessed by specified friend modules. This provides finer-grained access control, positioned between `public` and `private`. 53 | 54 | **Example**: 55 | 56 | ``` 57 | public(friend) fun example_function() { 58 | // Can only be called by friend modules 59 | } 60 | ``` 61 | 62 | #### 1.2 `entry` Function 63 | 64 | **Definition**: 65 | 66 | The `entry` function is an entry point of the module, allowing it to be called directly from a transaction block. Parameters must come from the input of the transaction block and cannot be the result of or data modified by previous transactions in the block. Additionally, `entry` functions can only return types with the `drop` ability. 67 | 68 | **Example**: 69 | 70 | ``` 71 | public entry fun transfer_coin(coin: Coin, recipient: address) { 72 | // Entry point of the transaction 73 | } 74 | ``` 75 | 76 | #### 1.3 `public` Function 77 | 78 | **Definition**: 79 | 80 | `public` functions can be called from transaction blocks and other modules, suitable for external interaction. Unlike `entry` functions, there are no restrictions on parameters and return values, making them commonly used to expose functionality to the outside. 81 | 82 | **Example**: 83 | 84 | ``` 85 | public fun get_balance(account: &Account): u64 { 86 | // Allows external modules and transaction blocks to call 87 | account.balance 88 | } 89 | ``` 90 | 91 | ### 2. Object Management 92 | 93 | #### 2.1 Object Uniqueness 94 | 95 | **Definition**: 96 | 97 | Every SUI object has a unique `objID`, ensuring the uniqueness of objects on the chain. 98 | 99 | #### 2.2 Wrapping and Unwrapping 100 | 101 | **Definition**: 102 | 103 | - **Direct Wrapping**: Embedding a SUI object as a field of another object. To unwrap, the wrapped object must be destroyed. 104 | - **Object Wrapping**: A wrapped object becomes part of another object and no longer exists independently. Unwrapping it does not change the object's ID. 105 | 106 | #### 2.3 Custom Transfer Strategy 107 | 108 | **Definition**: 109 | 110 | Use `sui::transfer::transfer` to define a custom transfer strategy. For objects with the `store` ability, `sui::transfer::public_transfer` can be created. 111 | 112 | #### 2.4 Object Properties 113 | 114 | **Definition**: 115 | 116 | SUI object properties include `copy`, `drop`, `store`, and `key`. These properties determine how objects behave. 117 | 118 | #### 2.5 Object Permission Checks 119 | 120 | ##### Address-Owned Objects 121 | 122 | **Definition**: 123 | 124 | Objects owned by a specific address (account address or object ID) can only be accessed and manipulated by the owner. 125 | 126 | ##### Immutable Objects 127 | 128 | **Definition**: 129 | 130 | Immutable objects cannot be modified or transferred, but anyone can access them. They are suitable for data that requires global access without modification. 131 | 132 | ##### Shared Objects 133 | 134 | **Definition**: 135 | 136 | Shared objects can be accessed and operated on by multiple users, which is useful for decentralized applications. However, due to the need for consensus, operations are more costly. 137 | 138 | ##### Wrapped Objects 139 | 140 | **Definition**: 141 | 142 | Wrapped objects are objects embedded within another object, and once wrapped, they no longer exist independently. They can only be accessed through the wrapping object. 143 | 144 | ## 3. Security Checks 145 | 146 | ### 3.1 Overflow Checks 147 | 148 | Sui Move performs overflow checks by default. 149 | 150 | ### 3.2 Reentrancy Checks 151 | 152 | A reentrancy attack is when an unexpected (external) call is inserted into a normal contract transaction, altering the overall flow of the transaction and enabling illegal profit. Any place involving external contract calls may have potential reentrancy risks. Current reentrancy issues can be categorized into three types: single-function reentrancy, cross-function reentrancy, and cross-contract reentrancy. 153 | 154 | - Move does not have dynamic calls; all external calls must be imported via `use`, meaning external calls are pre-determined and expected. 155 | - There is no native token transfer triggering fallback functions. 156 | - In Move, the resource model ensures that a resource can only be accessed by a single execution context at a time. This means if a function is not finished executing, other functions cannot access the same resource. 157 | 158 | # Audit Basics 159 | 160 | ## Overflow Audit 161 | 162 | **Explanation**: 163 | 164 | Move performs overflow checks during mathematical operations, and transactions with overflow will fail. However, bitwise operations do not undergo such checks. Additionally, custom overflow detection functions may have flaws that lead to value truncation issues. 165 | 166 | **Positioning**: 167 | 168 | - Identify locations in the code where bitwise operations are performed and check for potential overflow risks. 169 | - Check threshold settings and boundary condition judgments in custom overflow detection functions. 170 | - Verify whether bit shift operations may exceed the maximum value of the target type and be truncated. 171 | 172 | ```move 173 | // Error example 174 | public fun checked_shlw(n: u256): (u256, bool) { 175 | let mask = 0xffffffffffffffff << 192; // ❌ Wrong mask - any value less than `0xffffffffffffffff << 192` can pass through 176 | if (n > mask) { // ❌ Wrong condition 177 | (0, true) 178 | } else { 179 | ((n << 64), false) // ⚠️ Left shift overflow gets truncated 180 | } 181 | } 182 | ``` 183 | 184 | ## Arithmetic Accuracy Deviation Audit 185 | 186 | **Explanation**: 187 | 188 | Move does not have floating-point types. Therefore, arithmetic operations that would result in floating-point results may cause precision errors. While precision errors are difficult to entirely avoid in certain cases, they can be mitigated through optimization and careful design. 189 | 190 | **Positioning**: 191 | 192 | Review all parts of the code involving arithmetic operations, especially those where precision errors may occur. Ensure these operations do not negatively impact contract logic or numerical accuracy and propose optimizations to reduce precision errors. 193 | 194 | ## Race Conditions Audit 195 | 196 | **Explanation**: 197 | 198 | In Sui, validators can also sort the transactions submitted by users. Thus, we still need to be aware of issues where transaction ordering in the same block could lead to profit. 199 | 200 | **Positioning**: 201 | 202 | - Whether there is any expectation management for contract data states before function calls. 203 | - Whether there is expectation management for contract data states during function execution. 204 | - Whether there is expectation management for contract data states after function calls. 205 | 206 | ## Access Control Audit 207 | 208 | **Explanation**: 209 | 210 | Some key functions in a contract should be limited to internal calls, such as those that directly update user deposit amounts. If these functions are accidentally exposed to the outside, they might bypass permission control, leading to security vulnerabilities and even asset loss. Therefore, access control must be strictly set to ensure only authorized roles or modules can call these functions, or that they are restricted to internal use only. 211 | 212 | **Positioning**: 213 | 214 | Check the access control settings for all functions, especially those that should not be exposed externally, to ensure they are restricted to internal use. If any interfaces that should not be exposed are found to be open, mark them as high-risk and propose corrective measures. 215 | 216 | ## Object Management Audit 217 | 218 | **Explanation**: 219 | 220 | In SUI, objects can be converted into shared objects, meaning their access rights may change from private to public. It is necessary to carefully review all objects in use to clarify whether each object is static or shared. Special attention should be paid to whether any object has been incorrectly converted from private to shared, which could result in unauthorized access to those objects, posing potential security risks. 221 | 222 | **Positioning**: 223 | 224 | Sort and analyze all objects involved in the module, check their types and permission settings, and ensure that the object's permissions match business requirements. If any private objects have been incorrectly converted into shared objects, mark them as potential risks and propose corrective actions. 225 | 226 | ## Token Consumption Audit 227 | 228 | **Explanation**: 229 | 230 | SUI's token model differs from other chains. SUI allows objects to hold tokens, and token objects can be nested within other objects and split. Therefore, in scenarios involving token consumption, special attention must be paid to token management and circulation to avoid security issues or unexpected losses. 231 | 232 | **Positioning**: 233 | 234 | When auditing token consumption, check the following key points: 235 | 236 | 1. Is the consumed amount accurate? 237 | 2. Has the token object been correctly transferred? 238 | 3. Are the token splits and merges reasonable? 239 | 4. Check the binding of tokens to objects. 240 | 241 | ## Flashloan Attack Audit 242 | 243 | **Explanation**: 244 | 245 | Sui's Move also supports flashloan functionality (Hot Potato). Users can borrow large amounts of funds in a single transaction for arbitrary use, as long as the funds are returned within the same transaction. Malicious users often use flashloans to amplify their capital to execute large-scale attacks such as price manipulation. 246 | 247 | **Positioning**: 248 | 249 | Analyze the protocol's algorithms (rewards, interest rates, etc.) and check whether the oracle dependencies are reasonable. 250 | 251 | ## Permission Vulnerability Audit 252 | 253 | **Explanation**: 254 | 255 | In Sui's Move contracts, permission vulnerabilities are closely related to business requirements and function design. Therefore, when encountering more complex modules, it is necessary to confirm the permissions of each method with the project team. Permissions generally refer to the visibility and invocation permissions of functions. 256 | 257 | **Positioning**: 258 | 259 | - Check and confirm the visibility and invocation permissions of all functions. During the project evaluation phase, the project team should provide design documentation, and permissions should be confirmed during the audit based on the documentation. 260 | - Analyze the permissions of the project team's roles. If the roles have permissions that affect user assets, there is a risk of over-permission. 261 | - Analyze the types of objects passed into external functions. If they are privileged functions, privileged objects must be involved. 262 | 263 | ## Smart Contract Upgrade Security Audit 264 | 265 | **Explanation**: 266 | 267 | In Move, external modules are imported using the `use` keyword. It is important to note that Sui contracts are upgradable, but the published contract package (package) is an immutable object that cannot be withdrawn or modified once deployed. The essence of contract upgrades is to redeploy an updated contract at a new address and migrate data from the old version of the contract to the new one. Therefore, the following points must be carefully considered during the contract upgrade process: 268 | 269 | - **Init Function**: The `init` function is only executed when the contract is first deployed and will not be triggered during subsequent upgrades. 270 | - **Upgrades Do Not Automatically Update Dependencies**: If your contract package depends on an external package, upgrading the external package does not automatically update your contract package. You must manually upgrade your package to point to the new dependency. 271 | 272 | **Positioning**: 273 | 274 | Carefully review the data migration logic during contract upgrades to ensure the migration is safe and accurate, and avoid issues with missing critical data or dependency updates. 275 | 276 | ## External Call Function Security Audit 277 | 278 | **Explanation**: 279 | 280 | This is similar to the external module usage audit. Since external calls in Move require importing external modules, the external call results are theoretically expected by the developer. The main focus is the stability of the external module. 281 | 282 | **Positioning**: 283 | 284 | Review the external libraries that are imported. 285 | 286 | ## Unchecked Return Values 287 | 288 | **Explanation**: 289 | 290 | In Move contracts, similar to other smart contract languages, the return values of certain functions need to be checked. If these return values are ignored, critical logic might not execute properly, leading to security issues. 291 | 292 | **Positioning**: 293 | 294 | Check the return values of all function calls in the code, especially those involving external calls or important state updates. If return values are not handled or verified, it could result in unexpected behavior and should be flagged as a potential risk. 295 | 296 | ## Denial of Service Audit 297 | 298 | **Explanation**: 299 | 300 | Denial of Service (DoS) attacks may be caused by code logic errors, compatibility issues, or other security vulnerabilities, rendering the smart contract unusable. Such issues may affect the contract's availability or even cause it to crash entirely. 301 | 302 | **Positioning**: 303 | 304 | - Focus on the robustness of business logic to ensure that it can execute normally under various circumstances and is not interrupted by errors or vulnerabilities. 305 | - Pay attention to parts that interact with external modules, ensuring compatibility to avoid service interruptions due to external dependency issues. 306 | 307 | ## Gas Optimization Audit 308 | 309 | **Explanation**: 310 | 311 | Like Ethereum, Sui has a gas mechanism, and any module script calls will consume gas. Therefore, optimizing lengthy and complex code is necessary. 312 | 313 | **Positioning**: 314 | 315 | - For complex calls, check whether they can be decoupled. 316 | - For high-frequency calls, check whether the efficiency of internal function execution can be optimized. 317 | 318 | ## Design Logic Audit 319 | 320 | **Explanation**: 321 | 322 | Design logic audits focus on checking the business processes and implementations in the code to ensure there are no design flaws or inconsistencies with expectations. If the code implementation does not align with the intended logic, it may lead to unexpected behaviors or security risks. 323 | 324 | **Positioning**: 325 | 326 | - Based on the permissions and scope of different roles, sort out the potential invocation paths in the business process. 327 | - Determine the scope of data involved in each business process and ensure that the operations on the data are consistent with the business design. 328 | - Compare the actual invocation paths with the expected business process and identify any cases where unexpected results could occur. 329 | 330 | ## Others 331 | 332 | Anything not covered in the above sections. 333 | 334 | # References 335 | 336 | [Sui book](https://intro.sui-book.com/) 337 | 338 | [Sui Doc](https://docs.sui.io/) 339 | 340 | [Move Book CN](https://move-dao.github.io/move-book-zh/introduction.html) 341 | --------------------------------------------------------------------------------