简单复盘一下昨晚的Atem Mint事件。
官方twitter已经把昨晚的全部消息都删除了(web2的东西,删除了就没有链上记录了)。
我全程都是在RobotDao群里参与的Atem事件,并没有加官方discord/twitter,没有参与mint,数据都是从链上获取还原事件过程,所以可能会有所遗漏。
北京时间晚上10点:官网显示开始mint的时间
正式开始mint前(北京时间晚上9点25),官方自己开始成功mint了几个
之后科学家调用合约,开始mint,并且都给了0.069ETH的mint费用,全部mint失败
很多RobotDao群友连接不上官网的小狐狸钱包(前端bug应该是),消息开始在群里发酵(当时群友们正在fomo振华Doge暴富事件)
官方发twitter说服务器因用户过多超载,暂停mint15分钟(目前已经看不到了,官方删除了当晚所有推文)
之后大家都发现,完全没法mint,开始骚乱
0x2a99ae1d91654c4ea571d44f60661cca3ae22498地址当时是owner,调用了pause方法,暂停了合约mint。此时,其实都还没有到官方宣布开始mint的时间
后来,很多人继续fomo,直接调用合约,免费mint,但是全部失败(因为已经pause了)
晚上10点,0xbc34381a8dbba4e1c524189187a0f2b72d053138调用了两次transfer,企图转移合约所有权,但是都因为out of gas失败了
晚上10:23,streetsoul.eth调用了transfer,成功将合约所有权转移到0xC71DA7095111d8D1F7CCB7e58624d66a447d1Fd2
晚上10点23,官方发推说由于机器人攻击,北京时间11点重新开放。实际上,由于合约bug,当时合约所有权已经被转移了。官方已经毫无办法了。只能说被机器人攻击
大家发现了Atem的mint合约白名单是这么写的,大家开始意识到,事情并不简单。Atem合约可能是刚刚学习了3天solidity代码的人写的。

天天研究合约和脚本的RobotDao群里,家人们看到上面的合约,都充满了欢乐的气氛。
北京时间晚10:53,官方发推说5分钟内再次上线。但是从链上信息我们知道,官方已经无能为力了。在10点41分,0x0bf8422f0a124e664f4ac2ec42cfe50afe8b8906调用pause合约,想重启mint,失败了。因为owner此时已经被转移了。
在晚上11点15分,官方多次调用pause方法想重启,都失败了。他们可能当时都不知道到底发生了什么。早在一个小时前,官方就已经失去合约控制权了。
大家fomo了还是继续在不停的调用mint方法,全部失败。损失了很多gas fee,但是fomo起来拦不住。discord里官方直接把发消息速度降低到5min一条,装鸵鸟。
北京时间晚上11:19,goodproject.eth也调用了transfer方法,将合约owner转移了。
官方继续契而不舍的调用pause方法,企图开始mint。他们难道没有发现,owner已经转移了很多次了么?
高潮开始:我们的RobotDao创始人脚哥script.money,发现了漏洞并帮忙官方调用pause,让大家终于可以开始mint了。
"https://etherscan.io/tx/0x33bccbd5e6840fe165427584d779d94bd7d68dda420f42dac9ec64c0517ee8fc"

合约bug:问题出在transfer转移合约owner上,这里的判断条件写错了。
require(msg.sender != _owner, "Ownable: it is for owner");
关键是,这个是这个方法,是开源协议Ownable.sol里的代码。原版协议里,这个是没问题的!

之前我都只是看热闹,现在看了这个漏洞后,我起了兴趣。我去看了源码,研究哪些地方可以搞事情的。
首先看owner能不能转移资金。当时合约里有一些ETH,但是居然是写死的转移地址。只能转移给creatorAddress,并且owner也不能更改。
address public constant creatorAddress = 0x2a99AE1d91654c4Ea571d44F60661cCA3AE22498; function withdrawAll() public payable onlyOwner { uint256 balance = address(this).balance; require(balance > 0); _widthdraw(creatorAddress, address(this).balance); }看看能不能burn或mint token。owner并不能。
最后发现了,owner有权限随时修改tokenURI。这可有的玩了。
function setBaseURI(string memory baseURI) public onlyOwner { baseTokenURI = baseURI; }
于是我立马去调用transfer,把控制权转移给了我,将tokenURI改成了baidu.com。

之后就掀起了随意修改tokenURI浪潮,Atem变成了可变jpg的NFT了。
于是,大家都变成了拥有Bored Ape,拥有Azuki的大佬了。


而官方在做什么呢?
官方什么都没做,直接从Discord消失了,twitter也没有任何回应,今天甚至把昨天的所有消息删除了。
6个小时后,才在twitter上发布了一个消息。
复盘了整个事件,我产生了以下一些想法和建议。
无论项目方曾经在web2上有多牛逼,以前的背景多厉害,到了web3如果不是native的玩家,遇上问题不知道采取web3的解决办法,还是用web2的思路。有钱有背景,还需要虚心学习。
web3所有数据属于玩家,数据公开可查,务必重视安全啊。就算是3天速成的solidity,至少要多进行单元测试啊。玩家可都是真金白银支持你的啊。
项目方需要重视用户的看法,因为所有数据都链上可查,合约有漏洞,所有人都能看到,直接跟用户开诚布公的说,然后协商/投票,用web3的方法解决。
多好的一个探索,之前都没有出现过这种任何人都可以做管理员/更改tokenURI的NFT,昨晚大家也玩的很开心,完全可以作为一个现象级的事情。出圈机会被浪费了。
可以找我们社群RobotDao进行代码审计啊。我们这有合约科学家,有脚本科学家,有前端后端应有尽有。汇集了脚哥/激光猫/所长/凉粉小刀哥/神鱼/熊猫哥等各路大佬。掌握前沿技术/薅羊毛/NFT/各种链,欢迎加入。
