• Move 合约漏洞,Move 合约中最常见的 10 种 Bug


    Move 合约漏洞,Move 合约中最常见的 10 种 Bug

    Move 语言的设计,更难以写出 bug,并且 Move 确实相当程度上做到了,有一些类型 bug 是不会发生的。
    但 Bug 是无法根除的,正如所有事情的情况一样 – 而且智能合约的 bug 几乎总是有可能造成负面的财务影响。
    在经过许多 Move 审计之后,我们观察到一些 bug 的出现模式。因此,这篇文章的目的是记录我们发现并报告给客户的最常见的 bug 类型。
    💡 我们创建了一个虚构的、易受攻击的自动做市商(AMM)协议,名为 “DonkeySwap”,以展示每个 bug 类型,并描述我们将如何在这篇文章中修复每个问题。
    DonkeySwap 源代码在这里
    请注意,大多数 bug 的影响通常取决于上下文。


    1. 缺少泛型类型检查

    对于 Move 中的公共函数而言,泛型类型是另一种形式的用户输入,必须进行有效性检查。我们经常发现一些函数在接受一个泛型类型时没有

    • 检查该类型是否是一个有效的/白名单的类型。
    • 检查该类型是否为预期的类型(例如,没有与存储的类型相比较)。

    例如,DonkeySwap(我们举例的易受攻击的协议)在以下方面易受攻击:

    DonkeySwap:函数 cancel_order 没有检查 BaseCoinType 泛型

    • 类别:编码错误
    • 严重程度:关键
    • 影响:严重
    • 可能性: 高
    描述

    cancel_order 函数没有断言输入的 BaseCoinType 泛型与存储在 Order 资源中的 base_type 类型信息相匹配。
    这个函数为给定的 BaseCoinType 解锁流动资金,并将存储的 Coin 数量返回给用户:

    public fun cancel_order(
            user: &signer,
            order_id: u64
        ) acquires OrderStore, CoinStore {
            // [...]
            deposit_funds(order_store, address_of(user), order.base);
            // [...]
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    影响

    攻击者有可能通过限价兑换订单和取消订单 – 传递不正确的 Coin 类型,从 AMM 中抽干流动性。
    下面的概念证明证明了攻击者有能力窃取其他用户的锁定流动性:

    ##[test(admin=@donkeyswap, user=@0x2222)]
    fun WHEN_exploit_lack_of_type_checking(admin: &signer, user: &signer) acquires CoinCapability {
        let (my_usdc, order_id) = setup_with_limit_swap(admin, user, 1000000000000000);
    
        // let's say the admin deposits some ZEL
    
        mint(my_usdc, address_of(admin));
        let _admin_order_id = market::limit_swap(admin, my_usdc, 1000000000000000);
    
        // now, let's try stealing from the admin
    
        assert!(coin::balance(address_of(user)) == 0, ERR_UNEXPECTED_BALANCE);
        assert!(coin::balance(address_of(user)) == 0, ERR_UNEXPECTED_BALANCE);
    
        market::cancel_order(user, order_id); // ZEL is not the right coin type!
    
        assert!(coin::balance(address_of(user)) == 0, ERR_UNEXPECTED_BALANCE);
        assert!(coin::balance(address_of(user)) == my_usdc, ERR_UNEXPECTED_BALANCE); // received ZEL?
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    修改建议

    在 cancel_order 函数中添加以下类型检查断言:

    assert!(order.base_type == type_info::type_of(), ERR_ORDER_WRONG_COIN_TYPE);
    
    • 1

    2. 无限制执行

    无限制执行(Unbounded execution),也被称为 gas griefing/loop bombing,是一种拒绝服务的攻击,当用户可以无限制的向多个用户共享的循环代码(即可以被许多用户执行)添加迭代时,就会存在这种攻击。
    攻击者有可能引起循环迭代足够多的次数,使其耗尽能量而中止。这可能会阻止应用程序的关键功能。

    DonkeySwap:While 循环轰炸阻断了一些功能

    • 类别:编码错误
    • 严重程度: 高
    • 影响: 高
    • 可能性: 高
    描述

    下面的循环遍历每一个开放的订单,有可能因为注册了许多订单而被阻塞:

    fun get_order_by_id(
        order_store: &OrderStore,
        order_id: u64
    ): (Option) {
        let i = 0;
        let len = vector::length(&order_store.orders);
        while (i < len) {
            let order = vector::borrow(&order_store.orders
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
  • 相关阅读:
    计算机毕业设计ssm大学生身心健康管理系统的设计与实现d223r系统+程序+源码+lw+远程部署
    海格里斯HEGERLS托盘式四向穿梭车批发定制|24小时全自动无人化立体仓库批量托盘作业
    记录一次WLAN Panic导致的gcore问题分析
    Vue源码学习(十三):实现watch(一):方法,对象
    软件测试 | 测试工程师都能看懂的redis,进阶测试开发工程师......
    以太坊学习二:签名
    Vue学习--模板语法-插值
    DataGridXL 2.0 for JavaScript Crack
    JS DataTable中导出PDF右侧列被截断的问题解决
    STC51单片机学习笔记6——串口发送&中断接收
  • 原文地址:https://blog.csdn.net/weixin_28733483/article/details/132827555