solidity 特性导致的漏洞

news2024/11/15 19:24:03

目录

1、默认可见性

2、浮点数精度缺失

3、错误的构造函数

4、自毁函数

5、未初始化指针-状态变量覆盖


1、默认可见性

Solidity 的函数和状态变量有四种可见性:external、public、internal、private。函数可见性默认为 public,状态变量可见性默认为 internal。

可见范围:private < internal < external < public

  • private:只有当前合约可见
  • internal:外部合约不可见,只有当前合约内部和子类合约可见
  • external:只能被外部合约或者外部调用者可见
  • public:公共函数和状态变量对所有智能合约可见

solidity 0.4 版本,函数不设置访问修饰符编译不会报错,函数默认的可见性是 public,如果一下敏感函数没有设置访问修饰符,就可能发生越权函数调用

漏洞场景:

敏感函数忘记设置访问修饰符

漏洞代码示例:

pragma solidity ^0.4.5;

contract HashForEther {
    function withdrawWinnings() {
        // Winner if the last 8 hex characters of the address are 0. 
        require(uint32(msg.sender) == 0);
        sendWinnings();
     }

     function sendWinnings() {
         msg.sender.transfer(this.balance);
     }
}

sendWinnings 函数忘记设置函数访问修饰符了,而默认可见性是 public,于是导致任意地址都可以调用改函数而获得转账。

2、浮点数精度缺失

浮点型,定长浮点型——Solidity目前暂时不支持浮点型,也不完全支持定长浮点型。

fixed/ufixed 表示有符号和无符号的定长浮点数,浮点型可以用来声明变量,但不可以用来赋值。

除法运算:除法运算的结果会四舍五入,如果出现小数,小数点后的部分都会被舍弃,只取整数部分

pragma solidity ^0.4.0;

contract C {
    uint constant public weiPerEth = 1e18;
    uint public token1;
    uint256 public token2;
    uint256  public token3;

    function testC(uint n1, uint n2) external  {
        token1 = 200 wei / weiPerEth;
        token2 = 80 / 10;
        token3 = n1 /n2;
    }
}

token1 由于除法运算出现了小数(0.0...02),取整数部分,变成了0。当 n1 小于 n2 时,如 8/10 ,token3 也将取 0.8 的整数部分,变成 0。

执行结果:

漏洞场景:

转账发送以太时,以太数量由除法运算结果所得,运算数字可控,可能导致结果精度丢失,最终导致以太丢失

漏洞示例:

pragma solidity ^0.4.23;

contract FunWithNumbers{
    uint constant public tokensPerEth = 10;
    uint constant public weiPerEth = 1e18;
    mapping(address => uint) public balances;

    function buyTokens() public payable {
        uint tokens = msg.value/weiPerEth * tokensPerEth; // 第一处浮点和精确度问题
        balances[msg.sender] += tokens;
    }

    function sellTokens(uint tokens) public {
        require(balances[msg.sender] >= tokens);
        uint eth = tokens/tokensPerEth;                ?// 第二处浮点和精确度问题
        balances[msg.sender] -= tokens;
        msg.sender.transfer(eth * weiPerEth);
    }
}

3、错误的构造函数

在 Solidity 0.4.22 版本之前,在Solidity中的0.4.22版本之前,所有的合约名和构造函数同名。编写合约时,如果构造函数名和合约名不相同,合约会添加一个默认的构造函数,自己设置的构造函数就会被当作普通函数,导致自己原本的合约设置未按照预期执行,从而造成安全漏洞。

漏洞场景:

  1. Solidity 0.4.22 前,构造函数与合约名相同,但是大小写不一样
  2. 构造函数错误地声明为了 public 或者 external

示例 1:

pragma solidity ^0.4.20;

contract OwnerWallet {

    address public owner;

    function ownerWallet(address _owner) public {
        owner = _owner;
    }

    function () payable {}

    function withdraw() public {
        require(msg.sender == owner);
        msg.sender.transfer(this.balance);
    }
}

示例 2:采用更安全的 constructor 

pragma solidity ^0.4.0;

contract C {
    address owner;
    constructor() public {
        owner = msg.sender;
    }
}

4、自毁函数

Solidity 智能合约中存在一个 selfdestruct() 自毁函数,该函数可以对创建的合约进行自毁,并且可强制将合约里的 Ether 转到自毁函数定义的地址中。

contract DeleteContract {


    constructor() payable {}

    receive() external payable {}

    function deleteContract() external {
        // 调用selfdestruct销毁合约,并把剩余的ETH转给msg.sender
        selfdestruct(payable(msg.sender));
    }

}

漏洞场景:

合约限制账户转入的以太数量,而攻击者可以使用自毁函数强制转入任意数量,并且使用 this.balance 作为敏感操作的判断条件

漏洞示例:

contract EtherGame {

    uint public payoutMileStone1 = 3 ether;
    uint public mileStone1Reward = 2 ether;
    uint public payoutMileStone2 = 5 ether;
    uint public mileStone2Reward = 3 ether; 
    uint public finalMileStone = 10 ether; 
    uint public finalReward = 5 ether; 

    mapping(address => uint) redeemableEther;
    function play() public payable {
        require(msg.value == 0.5 ether); 
        uint currentBalance = this.balance + msg.value;
        require(currentBalance <= finalMileStone);
        if (currentBalance == payoutMileStone1) {
            redeemableEther[msg.sender] += mileStone1Reward;
        }
        else if (currentBalance == payoutMileStone2) {
            redeemableEther[msg.sender] += mileStone2Reward;
        }
        else if (currentBalance == finalMileStone ) {
            redeemableEther[msg.sender] += finalReward;
        }
        return;
    }

    function claimReward() public {
        require(this.balance == finalMileStone);
        require(redeemableEther[msg.sender] > 0); 
        redeemableEther[msg.sender] = 0;
        msg.sender.transfer(redeemableEther[msg.sender]);
    }
}

攻击者角度分析

由于合约设置参与者每次提交的 Ether 数为 0.5,提交多次后就会达到10 Ether,因此攻击者就可以创建带有 selfdestruct() 函数的合约,通过 selfdestruct() 函数强制给它提供 0.1 Ether,当强制转入的 0.1 Ether 进入条件判断,最终的计算数值将永远不会成为整数,this.balance==finalMileStone 判断将永远不会成立,导致参与者永远不会获得奖励。所有参与者的 Ether 就会永远锁在 EtherGame 合约中。

5、未初始化指针-状态变量覆盖

合约中状态变量存储在 storage 中,会按声明顺序存入卡槽 slot

contract A{
    address owner;
    B addrB;
}

Solidity 对于复杂的数据类型,在函数中作为局部变量时,会默认存储在 storage 中。当声明的复杂数据类型局部变量未初始化时,它会默认成为指向 storage 的指针,就会指向 slot 0,这时如果声明了状态变量,那么第一个状态变量将会被覆盖。

pragma solidity ^0.4.0;

contract CC { 

    string public _name1;
    string public _name2;

    struct NameRecord {  
        string name1;   
        string name2; 
    }

    function CC() {
        _name1 = "makabaka";
        _name2 = "nigubigu";
    } 

    function register(string n1, string n2) public { 
        // 设置新的NameRecord ,未初始化
        NameRecord newRecord; 
        newRecord.name1 = n1; 
        newRecord.name2 = n2;  
    } 
    
}

register 函数中的结构体类型局部变量 newRecord,由于未初始化,默认会指向 slot 0,于是 newRecord.name1 会覆盖状态变量 _name1,newRecord.name2 会覆盖状态变量 _name2

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1310132.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

51单片机控制1602LCD显示屏输出自定义字符二

51单片机控制1602LCD显示屏输出自定义字符二 1.概述 1602LCD除了内置的字符外还提供自定义字符功能&#xff0c;当内置的字符中没有我们想要输出的字符时&#xff0c;我们就可以自己创造字符让他显示&#xff0c;下面介绍1602如何创建自定义字符。 2.1602LCD创建字符原理 自…

2023 re:Invent使用 PartyRock 和 Amazon Bedrock 安全高效构建 AI 应用程序

前言 本篇文章授权活动官方亚马逊云科技文章转发、改写权&#xff0c;包括不限于在 亚马逊云科技开发者社区, 知乎&#xff0c;自媒体平台&#xff0c;第三方开发者媒体等亚马逊云科技官方渠道 “Your Data, Your AI, Your Future.&#xff08;你的数据&#xff0c;你的AI&…

利用Microsoft Visual Studio Installer Projects打包安装包

利用Microsoft Visual Studio Installer Projects打包安装包 具体步骤步骤1&#xff1a;安装扩展步骤2&#xff1a;创建 Setup 项目步骤3&#xff1a;设置属性步骤4&#xff1a;添加输出步骤5&#xff1a;添加文件步骤6&#xff1a;添加桌面快捷方式步骤7&#xff1a;添加菜单快…

使用Pytorch从零开始构建StyleGAN

本文介绍的是当今最好的 GAN 之一&#xff0c;来自论文《A Style-Based Generator Architecture for Generative Adversarial Networks》的 StyleGAN &#xff0c;我们将使用 PyTorch 对其进行干净、简单且可读的实现&#xff0c;并尝试尽可能接近原始论文。 如果您没有阅读过…

如何实现电脑文件夹自动备份?以下是图解教程

在当今迅猛发展的科技时代&#xff0c;电脑已经成为不可或缺的办公工具。随着使用时间的增加&#xff0c;存储在电脑中的文件数量也逐渐增多。然而&#xff0c;由于设备故障、手动误删等原因&#xff0c;文件的丢失问题成为一个不可忽视的风险。如果丢失的文件具有重要性&#…

文字转语音自动合成系统源码:让你的语音自动转成文字 附带完整的搭建教程

人工智能技术的不断发展&#xff0c;语音识别和自然语言处理技术已经逐渐成熟。文字转语音自动合成系统就是结合了这两项技术&#xff0c;将文字信息转化为语音输出&#xff0c;为用户提供更加便捷、高效的信息获取方式。这种系统在语音助手、智能客服、教育学习等领域有着广泛…

54 代码审计-TP5框架审计写法分析及代码追踪

目录 知识点1知识点2演示案例:demo代码段自写和规则写分析hsycms-TP框架-不安全写法-未过滤weipan21-TP框架-规则写法-内置过滤 知识点1 调试&#xff0c;访问&#xff0c;路由&#xff0c;配置&#xff0c;版本等 知识点2 自写写法&#xff1a;自己写代码&#xff0c;一步步…

PyQt6 简单介绍与安装

前文&#xff0c;参考文章&#xff1a; 参考文章一 参考文章二 PyQt6 简单介绍与安装 1、简单介绍2、PyQt6安装3、PyQt6版本查看4、PyQt6模块4.1 界面承载部分( 控件 )4.2 界面框架部分&#xff08;布局&#xff09;4.3 界面组件部分&#xff08;其实也是Widget类&#xff0…

Json数据报文解析-Gson库-JsonObject类-JsonParse类-JsonArray类

一、前言 本文我们将介绍如何解析Json数据&#xff0c;主要通过Gson库中的相关类来实现。 二、详细步骤 首先&#xff0c;我们要拿到一个基础的Json数据&#xff0c;这里将以下面的Json数据作为示例&#xff1a; {"code":"1","msg":"ok&q…

电脑监控软件丨老板的“管理神器”?员工的“噩梦伊始”?

不得不承认&#xff0c;老板们都很喜欢用电脑监控软件来管控员工的工作情况。但是面对这个话题&#xff0c;他们却又有不一样的感受。 老板的“管理神器”&#xff1f;——首先来说老板 不得不说&#xff0c;老板确实很喜欢用域之盾软件--电脑管控功能https://www.yuzhidun.cn…

mfc140u.dll丢失的解决方法的详细介绍,六种解决mfc140u.dll丢失的方法

今天的这篇文章将向各位分享一个有关电脑出现关于丢失mfc140u.dll错误的弹窗问题&#xff0c;这是一个很常见的问题。无论你是一名大学生还是其他身份&#xff0c;都可能会遇到这个问题。下面我会对mfc140u.dll丢失的解决方法进行详细的介绍。 一.六种解决mfc140u.dll丢失的方法…

浪潮信息大突破:全面开源1026亿参数模型源2.0

近日&#xff0c;浪潮信息发布了一项重大成就&#xff0c;宣布全面开源其1026亿参数的基础大模型——源2.0。该举措在AI产业界引起了广泛关注&#xff0c;被视为推动生成式人工智能产业快速发展的关键一步。 源2.0模型概览 源2.0是一个多参数级别的大模型&#xff0c;提供了1…

‘BLEUUID‘ does not name a type错误怎么解决?

摘要&#xff1a;arduino环境下对esp32蓝牙编程时会遇到BLEUUID does not name a type错误&#xff0c;本文介绍解决方法。 硬件设备是安信可ESP32-S模组。 错误发生在代码最开始的地方&#xff0c;include了一个蓝牙设备头文件&#xff0c;然后定义了UUID&#xff0c;注意看&a…

Conda 使用教程大全来啦

什么是 Conda&#xff1f; Conda 是一款功能强大的软件包管理器和环境管理器&#xff0c;您可以在 Windows 的 Anaconda 提示符或 macOS 或 Linux 的终端窗口中使用命令行命令 Conda 可以快速安装、运行和更新软件包及相关依赖项。Conda 可以在本地计算机上创建、保存、加载和…

人工智能改变医疗保健:人工智能如何革命医学

人工智能&#xff08;Artificial Intelligence, 简称AI&#xff09;的快速发展正逐渐改变着我们的生活方式和社会结构。在医疗保健领域&#xff0c;AI的应用不仅提供了更准确、高效的诊断和治疗手段&#xff0c;还为医生和患者之间的交流提供了新的途径。本文将探讨人工智能如何…

计算机组成原理-ATT格式vsIntel格式

文章目录 AT&T格式 vs lntel格式 x86汇编语言是lntel格式&#xff0c;还有一种汇编语言格式是AT&T AT&T格式 vs lntel格式 lntel格式中取主存地址内容未指明长度默认为32位&#xff0c;对应下图中第四行右边的指令 百分号 美元符号 小括号 可用于计算机结构体数组…

有意思!40小时工作制来了,996再见

​在中国&#xff0c;加班文化已经深入人心。工资越高加班越多&#xff0c;“996”已成为一些行业标签&#xff0c;月薪30k以上的职场人中超过86&#xff05;经常加班。所以今天我就来说一下这40小时工作制到底是从何而来&#xff0c;感兴趣的往下看看吧&#xff01; 40小时工…

2023自动化测试框架的设计原则你都知道吗?快来看!

1.代码规范 测试框架随着业务推进&#xff0c;必然会涉及代码的二次开发&#xff0c;所以代码编写应符合通用规范&#xff0c;代码命名符合业界标准&#xff0c;并且代码层次清晰。特别在大型项目、多人协作型项目中&#xff0c;如果代码没有良好的规范&#xff0c;那么整个框架…

安装LLaMA-Factory微调chatglm3,修改自我认知

安装git clone https://github.com/hiyouga/LLaMA-Factory.git conda create -n llama_factory python3.10 conda activate llama_factory cd LLaMA-Factory pip install -r requirements.txt 之后运行 单卡训练&#xff0c; CUDA_VISIBLE_DEVICES0 python src/train_web.py…

MagicAnimate:Temporally consistent human image animation using diffusion model

1.Introduction 本文研究了任务形象动画人物&#xff0c;旨在根据特定的运动序列生成一个具有特定参考身份的视频。现有的人物图像动画的数据驱动方法可以基于所使用的生成主干模型分为两类&#xff0c;1.基于GAN&#xff0c;通常使用变形函数将参考图变形为目标姿态&#xff0…