智能合约安全审计入门篇 —— delegatecall (2)_HAC:DOGEBACK

上篇文章中我们了解了什么是delegatecall函数以及一个基础的漏洞,这篇文章的目的是加深一下大家对delegatecall的印象并带大家一起去玩点刺激的,拿下一个进阶版的漏洞合约。

这里就不再重复之前的基础知识了,不了解或者遗忘的可以再看看上一篇文章:《智能合约安全审计入门篇——delegatecall(1)》。

漏洞示例

contractLib{??uintpublicsomeNumber;??functiondoSomething(uint_num)public{????someNumber=_num;??}}contractHackMe{??addresspubliclib;??addresspublicowner;??uintpublicsomeNumber;??constructor(address_lib){????lib=_lib;????owner=msg.sender;??}??functiondoSomething(uint_num)public{????lib.delegatecall(abi.encodeWithSignature("doSomething(uint256)",_num));??}}

Trustless Market开发团队将Uniswap的智能合约部署到比特币网络上:5月11日消息,一群开发人员已将Uniswap的智能合约部署到比特币网络上,以利用BRC-20代币的兴起并开发去中心化金融 (DeFi) 生态系统。该协议称为Trustless Market,日交易量已达50万美元,吸引了2000多名用户,并让流动性提供者从网络上进行的所有swap交易中获得2%的佣金。[2023/5/11 14:57:31]

漏洞分析

这次的攻击目标依然是获得HackMe合约中的?owner?权限,我们可以看到两个合约中除了HackMe合约中的构造函数可以修改合约的?owner?其他地方并没有修改?owner?的函数。我们要如何完成攻击呢?这里需要一点小技巧,大家可以思考一下,刚好也可以验证一下自己对于之前知识的掌握程度以及自己的思维是否活跃。

智能合约钱包Argent全面开放Layer 2账户注册:3月8日消息,智能合约钱包 Argent 宣布全面开放 Layer 2 账户注册,现在任何人都可以进行访问其以太坊 zkSync 网络 Layer 2 钱包。Argent 表示,其 Layer 2 钱包支持更低的 gas 费用,更快的交易速度,并且提供质押和收益耕作服务,网络交易的碳排放量将减少 100 倍。[2022/3/8 13:44:14]

是否有想法呢?没有想法也没关系,我们一起来看攻击是如何完成的:

攻击合约

//SPDX-License-Identifier:MITpragmasolidity^0.8.13;contractAttack{??//MakesurethestoragelayoutisthesameasHackMe??//Thiswillallowustocorrectlyupdatethestatevariables??addresspubliclib;??addresspublicowner;??uintpublicsomeNumber;??HackMepublichackMe;??constructor(HackMe_hackMe){????hackMe=HackMe(_hackMe);??}??functionattack()public{????//overrideaddressoflib????hackMe.doSomething(uint(uint160(address(this))));????//passanynumberasinput,thefunctiondoSomething()belowwill????//becalled????hackMe.doSomething(1);??}??//functionsignaturemustmatchHackMe.doSomething()??functiondoSomething(uint_num)public{????owner=msg.sender;??}}

动态 | 智能合约平台RSK开启比特币和以太坊之间的互操作性桥梁:基于比特币的智能合约平台RSK的母公司推出了一个新的代币,以作为将其连接到以太坊的桥梁。位于直布罗陀的开发团队IOV Labs周三宣布,新发布的互操作性桥梁工具将允许用户跨基于RSK和以太坊的数字资产,包括ETH和ERC-20代币。当用户传输代币时,该桥梁的智能合约将锁定初始代币,并在另一个链上生成相应数量的新代币。使用该系统,基于以太坊网络的代币可以转换为基于RSK的RRC20代币,而该代币反过来又可以转换为基于以太坊的ERC777代币。(CoinDesk)[2020/2/7]

我们先看攻击流程:

1.Alice部署Lib合约;

2.Alice部署HackMe合约并在构造函数中传入Lib合约的地址;

动态 | Switcheo交易所将推出NEO V3交易智能合约:据bitcoinexchangeguide报道,Switcheo交易所宣布推出NEO V3交易智能合约。此前,该公司一直在为NEO V2交易合同开发新功能。升级计划将于2019年3月25日进行。[2019/3/23]

3.攻击者Eve部署Attack合约并在构造函数中传入HackMe合约的地址;

4.攻击者调用Attack.attack()函数将HackMe合约中的owner变为自己。

咋回事儿呢?其实这个攻击方式就是很巧妙的运用了delegatecall这个函数修改storage类型变量时的特征:delegatecall函数的执行环境是调用者的环境并且对于storage类型变量的修改是根据被调用合约变量存储的插槽位置来修改的。

行情 | PeckShield漏洞研究总监罗元琮:以太坊公链安全相较智能合约更不容忽视:在2018 ISC互联网安全大会上,区块链安全公司PeckShield漏洞研究总监罗元琮指出,公链作为基础设施,一旦遭到攻击,其影响范围和危害程度超乎想象。PeckShield在本次大会的议题中披露了若干个存在于以太坊公链上的致命漏洞,目前这些漏洞均已和以太坊基金会沟通完成修复。此次披露的“EPoD 2”具体表现为:攻击者可通过geth LES协议实现缺陷,向受影响geth节点发送恶意AnnounceMsg,致使受害节点耗尽内存而卡死,甚至可能会连带大面积硬件终端宕机。其潜在危害也可能导致以太坊网络2/3以上的节点瞬间停摆,造成难以估量的严重影响。[2018/9/6]

1.Attack.attack()函数先将自己的地址转换为uint256类型第一次调用HackMe.doSomething()函数;

2.HackMe.doSomething()函数使用delegatecall函数带着传入的Attack合约的地址调用了Lib.doSomething()函数;

3.可以看到Lib.doSomething()函数将合约中存储位置为slot0的参数改为传入的值,这样当HackMe合约使用delegatecall调用Lib.doSomething()函数时也将改变自己在slot0位置存储的变量的值,也就是将lib参数改为我们传入的Attack合约的地址。此时之前在HackMe.lib参数中存储的Lib合约的地址就被修改成我们传入的Attack合约的地址了;

4.Attack.attack()函数再次调用HackMe.doSomething()函数,由于在上一步我们已经将HackMe.lib变量修改为Attack合约的地址了,这时HackMe.doSomething()函数将不再调用之前的Lib合约而是用delegatecall去调用Attack.doSomething()函数。此时我们再来观察Attack合约的写法,发现其变量的存储位置故意和HackMe合约保持一致,并且不难发现Attack.doSomething()函数的内容也被攻击者写为owner=msg.sender,这个操作修改了合约中存储位置为slot1的变量。所以HackMe合约使用delegatecall调用Attack.doSomething()函数就会将合约中存储位置为slot1的变量owner修改为msg.sender也就是Eve的地址,至此攻击者完成了他的攻击。

修复建议

作为开发者

1.?在使用delegatecall时应注意被调用合约的地址不能是可控的;

2.?在较为复杂的合约环境下需要注意变量的声明顺序以及存储位置。因为使用delegatecall进行外部调用时会根据被调用合约的数据结构来修改本合约相应slot中存储的数据,当数据结构发生变化时这可能会造成非预期的变量覆盖。

作为审计者

1.在审计过程中遇到合约中有使用delegatecall时需要注意被调用的合约地址是否可控;

2.当被调用合约中的函数存在修改storage变量的情况时需要注意变量存储插槽的位置,避免由于数据结构不一致而导致本合约中存储的storage变量被错误的覆盖。

来源:金色财经

郑重声明: 本文版权归原作者所有, 转载文章仅为传播更多信息之目的, 如作者信息标记有误, 请第一时间联系我们修改或删除, 多谢。

金智博客

[0:15ms0-2:854ms