目标合约漏洞分析这次的攻击目标依然是获得 HackMe 合约中的 owner 权限,我们可以看到两个合约中除了 HackMe 合约中的构造函数可以修改合约的 owner 其他地方并没有修改 owner 的函数,但是却可以修改位置slot0的值,而HackMe 合约中插槽slot0表示的便是Lib的地址,那么我们就先修改Lib的地址为我们的地址,再次调用HackMe 合约时就会运行我们合约中的逻辑,那么想改哪个位置插槽的值不就都由我们控制了吗 攻击合约下面是我们本次的攻击合约:接下来我们来看看攻击的整个逻辑:1. Attack.attack() 函数先将自己的地址转换为 uint256 类型(这一步是为了兼容目标合约中的数据类型)第一次调用 HackMe.doSomething() 函数;2. 修复建议我们在合约的开发中使用delegatecall要时刻注意其被调用的合约地址要始终在我们设计的逻辑内运行,不能让其有可能超出我们设计时的适用范围,一旦出现了超出我们预期设计的情况,那么合约就有可能被不法之徒利用
的3个安全问题。 分析攻击合约可以发现该合约中的多个安全问题: 1、Dice2win是一个不断更新的合约,存在多个版本。 合约之后,我们不难发现,由于智能合约和传统的服务端逻辑不同,导致许多我们惯用的安全思路遇到了更多问题,区块链的不可信原则直接导致了随机数生成方式的难度加深。 就目前为止,无论是底层的机制也好,又或是随机数的生成方式也好,智能合约的安全还有很长的路要走。 ---- ▼ 智能合约审计服务 ▼ 针对目前主流的以太坊应用,知道创宇提供专业权威的智能合约审计服务,规避因合约安全问题导致的财产损失,为
的3个安全问题。 Dice2win安全性分析 选择中止攻击 让我们来回顾一下dice2win的代码 function placeBet(uint betMask, uint modulo, uint commitLastBlock 分析攻击合约可以发现该合约中的多个安全问题: 1、Dice2win是一个不断更新的合约,存在多个版本。 成功溢出 总结 在回溯分析完整个Dice2win合约之后,我们不难发现,由于智能合约和传统的服务端逻辑不同,导致许多我们惯用的安全思路遇到了更多问题,区块链的不可信原则直接导致了随机数生成方式的难度加深 就目前为止,无论是底层的机制也好,又或是随机数的生成方式也好,智能合约的安全还有很长的路要走。
类似地,将 2 ^ 8 = 256 加到 uint8 类型的变量将使变量值保持不变,因为我们已经绕过uint的整个周期范围。 这类似于在三角函数的自变量角度添加2π,其值不变,即 : sin(x)= sin(x + 2π) 变量加上大于数据类型范围的数值称为溢出。 但是一旦存入,用户可以确保他们的以太安全地被锁定至少一周。这个合约写得正确吗? 然后,他们可以调用 increaseLockTime 函数,并传递数值 2 ^ 256 - userLockTime 作为参数。 OppenZepplin 在构建和审核安全库方面做得非常出色,可以被以太坊社区使用。特别值得一提,他们的安全数学库可用于避免上溢/下溢漏洞的参考库。
智能合约代码通常无法修改来修复安全漏洞,因此从智能合约中被盗窃的资产是无法收回的,且被盗资产极难追踪。 由于智能合约问题而被盗取或丢失的价值总额很容易超过 10 亿美元。 仅仅在项目结束时对您的智能合约进行审计已经不足以成为项目的唯一安全考虑。 安全性来源于适当的设计和开发过程,所以在您编写第一行智能合约代码之前,安全性就应该被考虑。 重入攻击重入攻击时在编写智能合约代码时应该考虑的最大且最重要的安全问题。 虽然以太坊虚拟机不能同时运行多个合约,一个合约可以调用另一个合约来暂停一个合约的执行和内存状态,直到被重新调用。 其他攻击除了上面的重入攻击,智能合约还会收到许多其他类型的攻击需要注意,例如:·溢出攻击·自毁攻击·delegatecall数据篡改·随机数问题安全工具虽然了解以太坊安全基础知识和聘请专业审计公司审查您的代码是无可替代的 ,但在合约编写的过程中学会使用安全工具,能帮助你更有效率的发现和改正代码中出现的错误和漏洞。
举个例子: 合约A 图片 合约B 图片 当合约B调用testDelegatecall()函数时,合约B的地址c的值会变为合约A的地址,而地址a则是不变。 因为合约A的函数test()改变的是插槽slot1的值,同样的在合约B中运行时,改变的也是插槽slot1的值,即地址c的值。 目标合约 图片 漏洞分析 我们可以看到有两个合约,Lib 合约中只有一个 pwn 函数用来修改合约的 owner,在 HackMe 合约中存在 fallback 函数,fallback 函数的内容是使用 攻击合约 图片 现在我们来看看整个攻击的逻辑: 1.攻击者调用attack()发起攻击,attack 函数首先去调用 HackMe.pwn(); 2.HackMe 合约中并没有 pwn 函数,此时触发 在使用 delegatecall 时应注意被调用合约的地址不能是可控的; 2. 在较为复杂的合约环境下需要注意变量的声明顺序以及存储位置。
selfdestruct函数(自毁函数)由以太坊智能合约提供,用于销毁区块链上的合约系统。当合约执行自毁操作时,合约账户上剩余的以太币会发送给指定的目标,然后其存储和代码从状态中被移除。 selfdestruct函数虽然能在紧急情况下帮助开发人员删除智能合约并将合约内的余额转移到指定的地址,但这一特性也被不法分子利用,使它成为了攻击手段。 玩家每次玩游戏时都会调用 EtherGame.deposit 函数向合约中先打入一个ETH,随后函数会检查合约中的余额(balance)是否小于等于 7 ,只有合约中的余额小于等于 7 时才能继续否则将回滚 合约中的余额(balance)是通过 address(this).balance 取到的,这就意味着我们只要有办法在产生 winner 之前改变 EtherGame 合约中的余额让他等于 7 就会使该合约瘫痪 攻击合约 图片 攻击者调用攻击函数attack()销毁合约并将合约中的余额强制转账到“幸运7”的游戏合约地址,制造出游戏合约查询余额address(this).balance大于7的情况,导致函数回退,
众所周知,以太坊的转账不仅可以在钱包地址之间进行,合约与钱包地址之间、合约与合约之间也可以,而合约在接收到转账的时候会触发 fallback 函数执行相应的逻辑,这是一种隐藏的外部调用。 攻击者就会利用这一点,在合约的fallback 函数中写入恶意逻辑重新进入到被攻击的合约内部,让被攻击的合约执行非预期的外部调用,从而到达获取不正当利益的目的。 函数一直提币从而将合约账户清空。 攻击合约下面我们看看攻击者编写的攻击合约中的攻击手法是否与我们的漏洞分析相同:图片我们看到 EtherStore 合约是一个充提合约,我们可以在其中充值和提现。 2. 加入防重入锁。下面是一个防重入锁的代码示例:图片3. 记住所有涉及到外部合约调用的代码位置都是不安全的。
2. increaseLockTime 函数是根据用户传入的 _secondsToIncrease 参数来进行运算从而改变用户的存入代币的锁定时间的,由于这里的 _secondsToIncrease 参数是可控的 首先部署 TimeLock 合约;2. 再部署 Attack 合约并在构造函数中传入 TimeLock 合约的地址;3. ),之后 Attack.attack 又调用 TimeLock.increaseLockTime 函数并传入 uint 类型可表示的最大值(2^256 - 1)加 1 再减去当前 TimeLock 合约中记录的锁定时间 此时 TimeLock.increaseLockTime 函数中的 lockTime 的计算结果为 2^256 这个值,在 uint256 类型中 2^256 这个数存在上溢所以计算结果为 2^256 使用 Solidity 0.8 及以上版本来开发合约,这里还有一点:需要慎用 unchecked,因为在 unchecked 修饰的代码块里面是不会对参数进行溢出检查的;2.
漏洞示例 示例合约如下所示: pragma solidity ^0.4.25; contract TypoOneCommand { uint numberOne = 2; function alwaysOne() public returns(uint a){ return numberOne =+ 1; } } 编译并部署合约之后调用alwaysOne来进行简易测试 防御措施 1、所有的数值运算操作全部采用SafeMath来实现 2、使用最新的编译器,最新版本编译器会自动检测是否存在类似的安全问题 ?
译文出自:登链翻译计划[1] 译者:翻译小组[2] 校对:Tiny 熊[3] 本文是关于调试 EVM 智能合约系列的第 2 篇,本系列包含 7 篇文章: 第 1 篇:汇编表示[4] 第 2 篇:部署智能合约 更确切地说,复制智能合约代码从Stack(2)个字节到Stack(2)+Stack(1)个字节。看一下堆栈,这是位于0x22(=34 的十进制)和(22+3f=61,即 97 的十进制)之间的代码。 让我们部署这个智能合约,参数 a=1,b=2,msg.value=1 ether,设置与之前一样(启用优化器, runs 设置为 1,solidity 0.8.7)。 智能合约结束了它的执行。 总结 最后总结一下合约部署情况: 它像每个智能合约一样存储了空闲内存指针。 它复制了由交易数据提供的 2 个参数,并将其存储到内存中。 [10] 第7篇:外部调用和合约部署: https://medium.com/@TrustChain/reversing-and-debugging-theevm-part-7-2a20a44a555e
本次我们将带大家了解智能合约中一个经常被用到的东西——随机数。智能合约的开发中常常会用到随机数,例如 Lottery 和现在流行的 NFT 数字藏品的属性等都需要用到随机数。 2)使用预言机生成随机数预言机是专门为生成随机数种子而搭建的链上或者链下的服务。 当然这种方法也会有一些安全风险,例如依赖第三方给出的随机数种子的话同样会存在第三方作弊或者受贿的情形,即使是自己搭建的随机数服务也可能因为故障等原因无法使用,项目方也有可能操控随机数对 DApp 的运行和用户造成重大的损失 接下来我们还是用合约代码来给大家演示弱随机数可能带来的危害。 下面我们来看攻击合约:攻击合约图片下面我们先来分析攻击流程:攻击者调用Attack.attack()函数,它模拟了 GuessTheRandomNumber 合约中随机数的生成方式生成随机数后调用 guessTheRandomNumber.guess
event是合约中定义的事件,用于记录合约中的重要操作和状态变化,定义event的格式如下: event EventName(arg1Type arg1, arg2Type arg2, ...); 其中 ,emit的格式如下: emit EventName(arg1, arg2, ...); 其中EventName为事件名称,arg1、arg2等为事件参数的值,例如:在合约中调用"Deposit"事件并传递相应的参数 sendTransaction跟web3标准下的用法是一样的,这时你再使用getbalance去看合约拥有的eth就会发现变成了2,说明它本来上面存了1个eth,然后我们返回攻击合约运行attack函数就可以完成攻击了 场景覆盖面充分以及合约代码的覆盖率 安全审计 智能合约在正式上线之前建议先寻找可靠的、可信任的第三方区块链智能合约安全审计公司对合约的安全性进行安全审计评估,在初次审计完成后需要对合约中存在的安全漏洞进行修复调整 ,同时在修复后还需要请安全审计公司再次进行安全审计来检查漏洞修复是否有效可行,同时也建议项目方在进行安全审计的时候可以邀请2-3家安全审计公司进行审计来实现对合约安全的多重安全保障 文末小结 智能合约安全审计是区块链应用开发过程中不可或缺的一环
译文出自:登链翻译计划[1] 译者:翻译小组[2] 校对:Tiny 熊[3] 译者注:本文作者是Matthew Di Ferrante[4], 是 ZK Labs 的创始人,也是一个知名智能合约开发者及审计人员 然而,安全不是一个检查清单,安全是一个过程,不仅在编写代码时,而且在项目和架构的设计时就得首先考虑,安全应该成为你心态的一部分。 举个例子:现在有多少人在写智能合约时知道 ETH 可以在不调用回退函数的情况下被发送到合约中,即使该函数是不可支付的(non-payable?)? 原文:https://mirror.xyz/mattdf.eth/InOuMtm9aQ1M2EIYpdqtIBE0AXRxCkp90pxtGFylHfc 参考资料 [1] 登链翻译计划: https:/ /github.com/lbc-team/Pioneer [2] 翻译小组: https://learnblockchain.cn/people/412 [3] Tiny 熊: https://learnblockchain.cn
其中,Fabric联盟链平台智能合约具有很好的代表性,本文主要分析其智能合约安全性,其他联盟链平台合约亦如此,除了代码语言本身的问题,也存在系统机制安全,运行时安全,业务逻辑安全等问题。 uint16 = uint16(2) fmt.Println(gas1 + rebate2) // 1 ? •访问外部资源 合约访问外部资源时,如第三方库,这些第三方库代码本身可能存在一些安全隐患。引入第三方库代码可能会暴露合约未预期的安全隐患,影响链码业务逻辑。 •外部合约调用引入安全隐患 在某些业务场景中,智能合约代码可能引入其他智能合约,这些未经安全检查的合约代码可能存在一些未预期的安全隐患,进而影响链码业务本身的逻辑。 总结 联盟链的发展目前还处于项目落地初期阶段,对于联盟链平台上的智能合约开发,项目方应该强化对智能合约开发者的安全培训,简化智能合约的设计,做到功能与安全的平衡,严格执行智能合约代码安全审计(自评/项目组
我们把这种同一个合约可能存在多个具有相同名称的变量,这种变量称为影子变量。 在更复杂的合约系统中,这种情况可能不会引起注意,并且随后可能引起某些安全问题。 这种场景下极容易出现变量隐藏的安全问题。 在 Solidity 编码中,变量隐藏常出现的场景包括: 同一个合约中,不同特定作用范围的变量。 继承关系的多个合约中,不同合约中具有相同名称的变量。 在编写更复杂的合约系统时,要时刻注意上面的两种场景,可能会由于忽视并随后导致变量隐藏安全问题。对于这两种场景分别用下面的代码进行演示。 2. 演示 2:继承合约中状态变量的隐藏 可以分析下面的代码,看能否看出哪里有问题? 安全建议 变量隐藏常出现的两类场景: 同一个合约中,不同特定作用范围的变量。 继承关系的多个合约中,不同合约中具有相同名称的变量。 对于场景 1, 在开发环境中,编辑器会提示如下的影子变量的风险。
一些概念 满足“条件竞争”的发生条件 并发访问:对同一个合约发起的调用的交易可以被“并发”的发生,虽然这些交易会被放进交易池线性执行,但是这些交易的执行顺序并不能得到保证。 共享对象:对于一个合约来说,合约的Storage变量就是所有合约函数调用中都能访问的共享对象 写操作:对Storage变量的更新,就是对共享对象的写操作 智能合约的特点 矿工在交易打包前(智能合约真正执行前 ,矿工可能选择对自己有利的打包顺序,而不会带来任何的后果 如果某个重要而秘密的值通过合约的参数传递,矿工可能发起中间人攻击 普通用户可以通过提高gas price的方式,尽可能尝试改变交易顺序,发起竞争条件 漏洞合约分析 ? tokens) 函数在用于授权用户转账额度,在owner修改用户的转账额度的时候,当该操作被用户监听到的时候,可以增大gas price提前转走这比额度 漏洞预防 对于提高gas price的行为:在合约中设置最高的
文章源自【字节脉搏社区】-字节脉搏实验室 作者-毕竟话少 描述:漏洞合约中某个函数中,使用call()方法发送eth,若eth的接收者为一个合约地址,则会触发该合约的fallback()函数。 若该合约是攻击者的恶意合约,攻击者可以在fallback()函数中重新调用漏洞合约的上述函数,导致重入攻击 核心问题:重要的合约变量在“重入”的过程中没有被修改,从而绕过了限制 ? 编译完成后会出现2个合约分别为ReentrancyAttack,ReentrancyGame) 首先部署ReentrancyGame(漏洞合约),这里Account设置一个受害者账户(0xca3…a733c wei ETH,这里受害者合约ReentrancyGame就部署完成了) 攻击者合约部署ReentrancyAttack(攻击者合约),由于漏洞合约地址在提现的时候需要一定的ETH,所以这里在设置ReentrancyAttack 漏洞预防 在将 Ether 发送给外部合约时使用内置的 transfer() 函数 。transfer转账功能只发送 2300 gas 不足以使目的地址/合约调用另一份合约(即重入发送合约)。
尽管这些外部智能合约的函数可以被触发执行,但补贴给外部智能合约的2,300 gas,意味着仅仅只够记录一个event到日志中。 当你自己的函数调用外部合约时,你的变量、方法、合约接口命名应该表明和他们可能是不安全的。 如果只有管理员能够改变它的值,那么它可能是安全的,因为没有别的办法可以跨越这个限制。 对于下溢同样的道理。如果一个uint别改变后小于0,那么将会导致它下溢并且被设置成为最大值(2^256)。 ,否则任何未执行此操作的人都可能会使用旧版本的合约 2、在你替换了合约后你需要仔细考虑如何处理原合约中的数据 另外一种方法是设计一个用来转发调用请求和数据到最新版的合约: 例2: 使用DELEGATECALL 安全相关的文件和程序 当发布涉及大量资金或重要任务的合约时,必须包含适当的文档。
这次我们将了解如何访问合约中的私有数据(private 数据)。 目标合约 话不多说,直接上代码 图片 这次我们的目标合约是部署在 Ropsten 上的一个合约。 ,可任意读取的,将敏感数据记录在合约中是不安全的。 2)storage在插槽中数据从右向左排列,空间不足时,打包当前插槽,开启下一个插槽存储数据;存储定长数组(长度固定)时,数组中每一个数据占据一个插槽。 : 图片 从右往左依次为 owner = f36467c4e023c355026066b8dc51456e7b791d99 isTrue = 01 = true u16 = 1f = 31 slot2 我们从合约代码中可以看到用户的 id 和 password 是由键值对的形式存储的,下面我们来读取两个用户的 id 和 password: user1 图片 运行结果: 图片 user2 图片 运行结果