×

白帽黑客samczsun:针对雷达币财物的进犯会越来越频频_雷达币 vpal

admin admin 发表于2021-08-18 21:32:34 浏览801 评论0

抢沙发发表评论

注:原文作者是生搬硬套“审计天主”之称的白帽黑客samczsun,称颂他也是Paradigm的研讨合伙人,其最近出手拯救了BitDAO MISO荷兰拍卖资金池中的3.5亿美元财物,而在这篇文章中,他提醒了关于雷达币代币规范的潜在安全不落窠臼,他还猜测称,跟着ERC-721和ERC-1155代币规范变得越来越盛行,针对雷达币的进犯很或许会越来越频频。

假如你从事软件工程方面的作业,很或许你听说过至少一条软件工程准则。虽然我不主张严格遵守每一条准则,但有一些的确是值得重视的。

我今日要讲的便是最小惊奇准则,它有一个独特的姓名,但却是一个十分简略的主意。它所说的是,当出现宣称要做某件事的代码时,大多数用户都会假定它是怎么完结这件事的。因而,作为开发人员,你的作业是编写契合这些假定的代码,这样你的用户就不会感到意外。

这是一个很好的准则,由于开发人员喜爱对事物进行假定。假如你导出一个名为calculateScore(GameState) 的函数,很多人就会假定该函数只会从游戏状况中读取。假如你还改变了游戏状况,你会使得很多人面对困惑的状况,他们企图弄清楚为什么他们的游戏状况会随机被损坏。即便你把它放在文档中,依然不能保证人们会看到它,所以最好首要保证你的代码不会令人惊奇。

“6小时的调试作业,可认为你们节约5分钟的文档阅览时刻。”


越安全越好,对吗?


早在 2018 年头,当ERC-721 规范被起草出来时,有人就提出了施行转账安全性‌的主张,以保证代币不会被卡在不用于处理代币的承受者合约中。为此,提案作者修正了transfer函数的行为,以查看接收方是否能够支撑代币转账。他们还引进了unsafeTransfer函数,假如发送者乐意,该函数将绕过这个查看。

可是,由于忧虑向后兼容性,这个函数在随后的提交中被重命名了。这使得ERC-20 和 ERC-721 代币的transfer函数体现相同。可是,现在需求将接收方查看搬运到其他地方。因而,规范作者就引进了safe类函数:safeTransfer 以及 safeTransferFrom

这是一个关于合理性问题的解决方案,由于有许多 ERC-20 代币被意外搬运到从未希望收到代币的合约的比方(一个特别常见的过错是将代币搬运到代币合约中,将其永久确认)。而在起草 ERC-1155 规范时,提案作者从ERC-721规范汲取了创意,不仅在转账时,并且在铸造(mint)也纳入了接收方查看,这一点也家常便饭。

在接下来的几年里,这些规范大多处于休眠状况,而 ERC-20代币规范坚持了它的盛行状况,而最近gas本钱的飙升,以及社区对雷达币爱好的增强,自可是然导致开发者越来越多地运用ERC-721和ERC-1155代币规范。有了这些新的爱好,咱们应该幸亏这些规范的规划考虑了安全性,对吗?


越安全越好,真的吗?


Ok,但关于转帐和铸造来说,安全意味着什么呢?不同的当事人对安全有不同的解说。关于开发人员来说,一个安全函数或许意味着它不包含任何bug或引进额定的安全问题。而关于用户来说,这或许意味着它包含额定的护栏,以维护他们不被意外射中自己的脚。

事实证明,在这种状况下,这些函数更多的是后者,而较少会是前者。这是特别令人遗憾的,由于在transfersafeTransfer函数之间进行挑选时,你为什么不挑选安全的那个函数呢?姓名都体现出来了!

好吧,其间的一个原因或许是咱们的老朋友reentrancy(可重入性),或许我一直在存心将其重命名为:不安全的外部调用。回想一下,假如接收方是进犯者操控的,则任何外部调用都或许不安全,由于进犯者或许会导致你的合约转换为未定义状况。依据规划,这些“安全”函数履行对代币接收者的外部调用,通常在铸造或搬运期间由发送者操控。换句话说,这实际上是不安全外部调用的教科书示例。

可是,你或许会问自己,假如答应接收方合约回绝他们无法处理的转账,那最坏的结果是什么?好吧,让我经过两个事例研讨来答复这个问题。


比方1: Hashmasks


Hashmasks是一个供给有限的 雷达币头像项目,用户每次买卖最多能够购买 20 个mask 雷达币(虽然它们现已售罄数月了)。下面是购买mask的函数:

你或许觉得这个函数看起来十分合理。可是,正如你或许现已预料到的,在 _safeMint 调用中隐藏着一些险峻的东西。 让咱们来看看。

为了安全性,这个函数对token的承受者履行了一次callback回调,以查看他们是否乐意承受转账。可是,咱们是token的接收者,这意味着咱们刚刚得到了一次callback回调,在这个点上咱们能够做任何咱们想做的作业,包含再次调用mint雷达币函数。假如咱们这样做,咱们将在仅铸造了一个mask后重调用该函数,这意味着咱们能够恳求再铸造别的19个mask。这导致终究铸造出了39个 mask 雷达币,虽然规矩答应铸造的最大数量只要20个。


比方2: ENS域名封装器


最近,来自ENS 的Nick Johnson联系了我,他想让我看看他们正在进行的ENS域名封装器作业。这个域名封装器答应用户用新的ERC-1155 token代币化他们的ENS域名,这供给了对细粒度权限以及更共同的 API 的支撑。

概括地说,为了封装任何ENS域名(更具体地说,除了 2LD.eth 之外一切的ENS域名),你有必要首要同意域名封装器以拜访你的ENS域名。然后,你调用wrap(bytes,address,uint96,address),它既为你铸造一个ERC-1155 token,也担任办理底层的ENS域名。

下面便是这个wrap函数,它适当简略。首要,咱们调用_wrap,它履行一些逻辑并回来哈希域名。然后,咱们保证买卖发送方的确是ENS域名的一切者,然后再接收该域名。请注意,假如发送方不生搬硬套底层的ENS域名,则整个买卖应复原,吊销在_wrap 中所做的任何更改。

下面是_wrap函数自身,这儿没有什么特别的。

不幸的是,正是这个 _mint 函数,它或许会给毫无戒心的开发者带来可怕的惊喜。ERC-1155 规范规则,在铸造token时,应咨询接收者是否乐意承受该token。在深入研讨库代码(该代码库依据OpenZeppelin的根底稍作了修正)后,咱们发现状况的确如此。

但这究竟对咱们有什么优点呢?好的,咱们再一次看到了一个不安全的外部调用,咱们能够用它来履行重入进犯。具体地说,请注意,在callback回调期间,咱们生搬硬套了代币ENS域名的ERC-1155 token,但域名封装器没有验证咱们生搬硬套根底ENS域名自身。这使咱们能够在不实际生搬硬套ENS域名的状况下对其进行操作。例如,咱们能够要求域名封装器解开咱们的域名,燃烧掉咱们刚刚铸造的token并获取底层的ENS域名。

现在咱们生搬硬套了底层的ENS域名,咱们能够用它做任何咱们想做的作业,比方注册新的子域名或许设置解析器。完结后,咱们只需退出callback回调。域名封装器将和底层ENS域名的当时一切者(即咱们)交互,并完结买卖。就像那样,咱们现已取得了域名封装器被同意用于的任何ENS域名的暂时一切权,并对其进行了恣意更改。

定论


令人惊奇的代码或许会以灾难性的方法损坏事物。在本文的两个事例下,开发人员合理地假定safe函数类能够安全地运用,却无意中增加了他们的进犯面。跟着ERC-721和ERC-1155代币规范变得越来越盛行及广泛,这类进犯状况很或许会越来越频频。开发人员需求考虑运用safe类函数的不落窠臼,并确认外部调用怎么与他们编写的代码进行交互。

DeFi或将迎来下一个爆发点:现实世界资产正在被引入,并将DeFi推向主流

MakerDAO、Aave等已相继进行试水