斯坦福大学区块链期末考试题

相信大家如果有区块链交流群的话可能会看见最近都在转发这个消息:

作为一名正在学习区块链技术的苦逼,自然是不会错过这么好的一个教材案例(毕竟这可是斯坦福大学的材料呢!!)

课程大纲和材料大家感兴趣可以自己去感受感受 链接我放在这了:


https://cs251.stanford.edu/syllabus.html

今天的重点其实是这样一道题 在第二个链接斯坦福大学期末考试的卷子里面

链接在这:


https://cs251.stanford.edu/hw/final2021.pdf

当然需要大家有一定的区块链和solidity知识基础才可以看懂我们在讲什么

那么我们来看看题目:

扫描二维码关注公众号,回复: 15497838 查看本文章

这道题讲的是:这是一个ERC721代币标准发行总量为16384个NFT的智能合约,用户通过调用mint函数一次性可以铸造不超过20个NFT,并且所有的内部变量已经在构造函数里面正常初始化了(不与展示)

然后我们再来看看问题:

A) 假设已经铸造了16370个NFT,那么totalSupply()=16370。解释恶意合同如何导致超过16384个的NFT被铸造。攻击者可以造出的NFT的最大数量是多少?

提示:如果在呼叫地址收到的OnERC721是恶意的,会发生什么?仔细观察铸币循环,并考虑重新铸造缺陷

B) 假设totalSupply()的当前值为16370,为实现(a)部分攻击的恶意Solidity合约编写代码。

C) 你会在上一页的代码中添加或更改哪一行代码

为了防止你的攻击?请注意,单笔交易不应产生超过20个NFT。

大致意思就是这个合约里面存在一个漏洞,攻击者可以利用漏洞来铸造出超出总发行量数量的NFT。

看到这里留一些时间给大家自己研究研究代码~

(既然都翻到这了想必大家都想知道答案了吧)

那么首先我们对原代码进行一个解读:

到这里我们可以知道要想调用函数铸造NFT得先通过前面的几个require检测,那么我们如果正常调用合约肯定是没有办法造出超过发行量上限的NFT的,注意我们在A问里面已经告诉了我们提示,假设我们铸造的地址本身是一个合约,这个合约里面又写入了恶意代码会怎么样呢?接下来我来给大家讲解解题思路:

首先我们要知道我们一次性只能铸造最多20个NFT,那么我们需要利用漏洞攻击必须要距离总发行量还差20个NFT之内的数量下才可以恶意攻击合约,根据代码的顺序,只要通过前面的require检测就可以开始铸造,我们只需要设计一套恶意代码(只要给合约地址铸造NFT就会触发重复调用mint(铸造)的代码)并且每一个地址都是这样的恶意合约地址。

打个比方,我在距离总发行量还差20个NFT的同时输入20个地址铸造NFT,合约就会传入20个数组,这20个数组都是可以通过前置的require条件的因为这20个铸造完总发行量正好会达到规定的16384个,那么在第一个恶意合约地址被铸造NFT的时候就会触发恶意代码并且重复调用mint函数并额外输入19个地址(原恶意合约地址+19个额外地址=20个剩余名额),那么第二个恶意合约地址就会触发额外输入18个地址(因为前面已经存在两个铸造的地址)以此类推,当20个地址全是恶意合约地址的时候,攻击者最多可以额外铸造19+18+17+16+15+14+13+12+11+10+9+8+7+6+5+4+3+2+1个NFT就是190个NFT,可以这么做的原理是利用了区块链的一个特点就是出块机制。

简单来说就是,调用智能合约功能的时候所有的参数和智能合约的状态都会打包成一个事务,当一个区块没有被打包完成出块时,这个区块里面发生的所有事务都还没有变成已经发生的“事实“,意思就是当区块没有出块时,这最后20个NFT是没有被实质性铸造出来的,所以当同时有很多个铸造20个NFT的事务同时出现的时候,这些事务都是可以全部通过前置的require检测的,这个漏洞导致了攻击者可以超出总发行量的数量来铸造NFT。

我们回到A问,假设已经铸造了16370个NFT,那么还剩余14个可以被铸造的NFT名额,利用我们上面的办法我们可以额外铸造13+12+11+10+9+8+7+6+5+4+3+2+1=91个NFT。

B问的恶意代码实现这里就不给大家做展示了,原理就是给把要铸造的地址做成恶意合约,当给合约铸造NFT的时候触发重复调用mint。

那么来到C问,既然我们知道了漏洞原理,我们如何防止这个合约被恶意攻击呢,其实非常简单,我们只需要在for循环后面加上一行:

require(totalSupply <= 16384);

意思是:在每个NFT被铸造之后检查NFT现在的发行量有没有超过16384个,有了这个后置require检查逻辑的话,使用恶意合约地址代码攻击将会失效,因为即使同时接收了多个铸造NFT的事务,当NFT铸造超过16384的时候整个事务就会失败无法出块变成“事实“。

区块链的世界充满无限的想象和创新,如果大家有全新的解题思路欢迎大家评论和留言,这里特别感谢我的导师:学开叶跟  (也是我导师的微信公众号,想学习更多区块链知识可以关注他)

猜你喜欢

转载自blog.csdn.net/wanzhexin/article/details/123487316