惊魂33天:The DAO被盗 | 区块链安全经典案例
imToken 是一款全球领先的区块链数字资产管理工具[ZB],帮助你安全管理BTC, ETH, ATOM, EOS, TRX, CKB, BCH, LTC, DOT, KSM, FIL, XTZ 资产,同时支持去中心化币币兑换功能 ...
在不了解它的时候,我总以为The DAO是一个很宏大的设计,现在看下来,主要是给一帮股东用来投票和分红的。
怕什么来什么
众筹结束当天,5月27日,Dino Mark、Vlad 、Emin Gün Sirer就写了篇论文6,分析了The DAO存在的若干个漏洞(不含导致DAO被盗的递归调用漏洞),并强烈呼吁人们暂停在DAO中发起项目提议。而当时,有50多个项目提议正在等待token持有者对它们进行投票。
注意其中的Emin Gün Sirer,后面还会提到他,当时他是康奈尔大学的计算机教授。他曾在贝尔实验室和工作过,后来选择进入学术领域。他同时是一位典型的极客,不仅从事加密货币、区块链、分布式系统的相关研究,更积极参与这些领域的实践。早在2002年,他就推出了名为Karma的虚拟货币系统,但彼时美国非常在意恐怖主义融资,Karma遇到种种监管障碍,所以最终未获成功。他不仅发表了众多关于加密货币体系的学术论文,还联合创立了IC3(The For & )组织 ,旨在聚集更多高校研究人员推进的发展,他是共识协议的发明人。
据彭博社采访他的记者 说,“Gün的黑发很短,看起来比45岁小10岁”。
Emin Gün Sirer
6月5日,以太坊开发人员 在上(用户名:)指出了一种对智能合约的攻击模式,即递归调用缺陷(也称重入漏洞),并于6月10日在以太坊基金会的博客予以了发布7。
6月9日,区块链基金会创始人Peter 发表博客,指出这个漏洞实在是太可怕、太可怕了(a , )。
Peter
6月12日,社区成员发现,The DAO存在递归调用漏洞8。
很快,几乎是同一天,以太坊前CCO,Slock.it联合创始人,The DAO创建人之一 Tual宣布,虽然The DAO存在递归调用缺陷,但“由于DAO的分红账户()里还没有钱,所以没有资金受到威胁”9。因为这个漏洞在实施分红时才会被调用的,而DAO才刚开始,一个项目都没有投出去,没有什么回报,更不要说分红了(所有回报都要经过投票才能进入分红账户)。
6月14日,在上,The DAO开发者之一 针对提出的问题给出了修复补丁PR,并得到了 的采纳和merge(形成DAO1.1),但是还没有部署。
即便部署,也需要在DAO中投票,需要有53%以上的票数同意,才能将合约以及其上的数据迁移到新地址上。按照前面的介绍,这种转移合约的投票期最少要7天。
6月16日,康奈尔大学的两名研究生在IC3的博客上再次提醒The DAO要注意递归调用漏洞10。
6月17日,The DAO遭受攻击,在6个小时内,360万以太币(当时价值约为5000万美元)被转移到黑客拆分出来的子DAO上。
黑客正是利用The DAO代码中的递归调用漏洞,不停地从The DAO账户上转移ETH,那里当时有将近1200万个ETH。
也就是说,专家们刚刚发现问题,还没有搞得很明白,攻击者就已经利用得手了。
这些人虽然都指出The DAO有问题,但没有一个真正发现漏洞到底在哪一行代码,包括并没有部署的DAO1.1,其实也并没有补对地方。
只有Gün在6月13日,和他学生Daina邮件交流时,才提及DAO.sol的第666行可能有问题,但也不是很确定,Gün说“可能这是个大麻烦”,Daina则回复“我觉得没问题”。于是,他们没有再追究下去,也没有公开这个怀疑。
Gün其实说对了,就是第666行有问题。
即便不是第666行,也是第667行。
Gün怀疑的第666行
紧急反击
这天早上,在德国米特韦达,被他兄弟Simon电话叫醒,说DAO被黑了。平日里每天早上都很忙碌,因为那时他有5个孩子(从2岁到9岁)需要照料,他和妻子要给他们做早饭并送上学,但这次不同了,匆忙对妻子说,“你来管孩子,我今天有紧急的事”。
几个小时后,住在里约热内卢的以太坊钱包首席用户体验设计师Alex Van de Sande得知此事。当他弄明白手机为什么快要被Skype信息爆掉的时候,他转向他的妻子说:“还记得我告诉你那一大堆无人能偷走的钱吗?” 她点了点头,“它被黑掉了”。
他的第一个想法是把他的DAO代币拿出来。他拥有大约10万个,当时的价值约为15000美元。但很快他就意识到,不应该放弃DAO,而应该努力拯救它。
Alex Van de Sande
在之后的几周里几乎是全天候工作,token持有者纷纷问他该怎么做,他必须要想出办法,让投资者拿回他们的钱。
好在,攻击者并不能立刻拿走他偷的ETH,子DAO和父DAO有相同的结构、规则和漏洞,这个子DAO刚刚建立,它现在面临的是27天的筹资期( Phase),在这个阶段,没有任何人可以挪动资金(多亏了这个设计!)。
这就有时间抢救DAO。
6月17日,V神( )在以太坊基金会的博客上发布了“重要更新”声明11,称DAO受到攻击,他给出一个解决方案:
“我们已经提出了一个软件分叉,这个分叉不需要回滚,不会‘反转’任何交易或块,只是让任何试图减少DAO及其子DAO余额的交易无效。这样,攻击者即便在27天后,也无法取走资金。这将给我们采取进一步措施提供充足时间,包括让代币持有人有能力收回他们的ETH。”
“矿工和矿池应保持正常运转,如果同意以太坊生态系统的这一道路,待软分叉代码就绪后,下载代码并运行它。DAO代币持有者和以太坊用户应警惕而冷静,交易所则尽可以恢复ETH交易。”
换句话说,这个软分叉方案将在以太坊代码中建立一个黑名单,防止坏人领走它盗取的东西。
软分叉只是抛弃指定交易,它不改变以太坊上已经发生的交易,也不回滚任何数据,只需要矿工们更新软件就可以了(前提是大多数矿工们都同意)。其他人如果不更新软件,也不影响正常使用以太坊,升级的节点和未升级的节点是兼容的。
很快,当天,的客户端就实现了软分叉,以太坊基金会的的Geth则在第二天完成更新。
这篇文章一出,攻击者就停了下来,不再继续盗取资金。他已经攻击了6个小时,偷走了3,641,694个ETH,占据了The DAO总资金的1/3,而The DAO里面的ETH,则占据了那时所有ETH的15%。
Alex Van de Sande 回忆他当时的想法:“我们甚至不明白这个人为什么停了下来。”12
黑客在那6个小时内,利用两个合约账号,调用主DAO的函数,每个地址调用大约250次,几乎每次调用都会使得递归执行30次,平均每次递归调用大概盗走7000多的ETH13,这样,总共盗走了360多万的以太坊。
事情刚开始的时候,没人知道攻击者是怎么做到的,尤其是攻击者为什么能重复发起那么多次攻击,因为执行完一次递归后他的token就会被清零,但他却执行了500多次!
在上,人们激烈讨论了5,6个小时后,终于想明白攻击者是怎么搞的,这才有了后面的白帽子反击。当天晚上,Emin Gün Sirer的研究生Phil Daian就写了一篇详细分析攻击者手法的文章14。
这篇文章最后,Daian向他的导师Gün喊话:“Gün,我们已经离得太近了——但很遗憾还不够:)。”
而Gün则在后来的一次采访中说:“如果当时Daian回复邮件确认是漏洞,我就会告诉大家”。
白帽子的行动
6月21日,DAO的账户再次出现转移,采用同样的攻击手法,更多的钱进入到另外两个子DAO,分别取走了727.7万和35.3万个ETH15。
人们惊呼,攻击又开始了!
几个小时后,Sande在推特上宣布:“DAO正在安全转移资金,不要惊慌。”
Sande在推特上宣布白帽子行动
这是由两、三人组成的“罗宾汉小组”(Robin Hood Group)干的,其中一人是Griff Green,来自slock.it,同时是The DAO的主要开发人员之一,正是他第一个将袭击消息转发给的兄弟Simon的(Simon也是Slock.it的联合创始人)。
虽然人们不清楚这个小组里都有谁,但人们信任Sande,这些白帽子正使用攻击者的手法将剩余资金转移到他们拆分的子DAO里。与此相对应,黑客控制的DAO被称为“The Dark DAO”,简称。
但攻击者确实很聪明,他总是跟随新的split提议并投YES,他总能进入新split出来的DAO,以试图在新DAO里再发起攻击。
另外一组白帽黑客则试图通过给打款以成为里面的成员,毕竟这个正处于筹资期!一旦成为的一员,他们就可以用同样的攻击手法拆分。
由于DAO的这个漏洞存在,如果不去管它,可能就会不停有这样的攻击和反击,DAO会不断分裂下去,白帽、黑帽不断加入,而且也不知道谁是好人谁是坏人,DAO会成为黑客们的乐园,而大部分原始代币持有人则可能一无所获。
如果DAO因此失败,整个以太坊网络都会遭殃。
第二天,ETH的价格应声下跌,暴跌约30%,从20多美元跌至13美元以下。
攻击原理是怎么样的
对于非技术读者而言,了解这个漏洞,只需要理解这个场景就可以了:
一名银行储户,同时也是一名黑客,对着一台自动取款机开展攻击,他的银行卡上有1万元,他插入卡片,要求自动取款机吐出1万元。
取款机的取款功能是这样设计的:
1. 读取储户余额;
2. 等待储户输入取现金额;
3. 如果取现金额<=余额,吐钱;
4. 更新储户余额(也即减去取现金额)。
如果黑客有能力在第3步(也即吐钱)后,通过奇怪的方式重新开始第1步,黑客就实现了重入攻击。
因为这时取款机还没有执行第4步,那么黑客的卡上始终有1万元,他就可以一次又一次地取现1万元。
取款机如何修改这个bug:
1. 读取储户余额;
2. 等待储户输入取现金额;
3. 如果取现金额<=余额,更新储户余额(也即减去取现金额);
4. 吐钱;如果吐钱失败,恢复储户余额。
对懂一些技术的读者而言,可能最想了解的是:在智能合约中,这个递归调用漏洞到底是怎样的?
简单地说,如果合约A的funcA函数,调用合约B的funB函数,而funcB里面,又去调用A的funcA,那么就会形成一个死循环,两个函数不断地调用对方(也即递归、重入),直到最初调用时所带gas耗尽,要知道,gas本来就是为了防止死循环的。
一个重入漏洞导致ETH被盗的原理示例:
1. 有两个智能合约,一个是合约A(受害合约),一个是合约B(攻击合约)。
2. 合约A的pay函数让用户可以将其所有存款余额提走。
3. 如果写A的程序员没有经验,在pay的实现中是先付钱后更新余额,就会有问题。
4. 在Solidity语言中,如果对一个合约执行call调用而不指定函数,合约的匿名函数(fallback函数)就会被调用。
5. 攻击者可以写一个合约B。在B的fallback函数中调用A的pay。
6. 攻击者用合约B调用A的pay,A用call打钱给B,触发B的fallback再调用pay,然后A又打钱,又触发B调用pay,循环往复。
下面用最少的代码量,予以代码层面的展示。(看这个代码,有助于理解攻击者如何攻击The DAO)
A合约的片段:
function pay() public
{
\\取出调用者的地址
address addr = msg.sender;
\\获取调用者的余额
uint amount = balances[addr];
\\将余额打给调用者的地址
addr.call{value: amount}();
\\将调用者的余额归零
balances[msg.sender] = 0;
}
B合约的片段:
\\计划重入30次
unit times = 30;
fallback() external payable
{
\\对重入次数减1
times = times - 1;
\\如果仍有次数就再执行一次
if (times > 0)
A.pay(); \\调用A的pay函数
}
B先调用A.pay(),辅以足量的gas,A的addr.call{value: }();就会执行,然后就会触发B的(),然后又执行pay(),这样B的余额清空那句就始终不能执行,直到执行30次后才走到余额归零那句,如果B本来只有10个ETH,这样就能搞到300个ETH(当然前提是A上有这么多钱)。
修补的方法也不难:
一是可以先清零,再发送;
二是可以用send函数或者transfer函数发送金额,这两种调用只会发送2300个gas,不会带更多的gas;而call不一样,call会带上所有剩余的gas,如果一开始攻击者给的gas多,就会导致多次重入;
三是可以设置互斥量,也就是加一个变量来判断是不是已经在执行中。
这三种方法,用其中一个就可以。这篇文章16有很好的介绍和示例,有兴趣可以看一看。
黑客是怎么攻击The DAO的?
具体来说,黑客发起了一个的提议,自己控制的两个合约账号都投了YES(虽然也有两个人投了NO,但是没用,具体见前面的介绍,投票结果并不影响拆分)。
拆分DAO的提议是第59号提议:标题为“, so ”,发起于2016–06–08 05:38:01 UTC,注意,发布Bug的时间是6月9日。
攻击者控制的两个合约账户(也即攻击合约):
0xc0ee9db1a9e07ca63e4ff0d5fb6f86bf68d47b89,创建于6月15日
0xf835a0247b0063c04ef22006ebe57c5f11977cc4,创建于6月15日
过了投票期7天,攻击者可以执行拆分了。黑客控制这两个合约分别执行主DAO里的函数,转移自己份额的ETH到子DAO,并在子DAO里自动获取自己应得的token,这个过程也会涉及分红的转移,而正是分红转移这块,DAO使用了能引起递归的call调用。
攻击者控制的合约里面,则肯定在函数里再次调用了,这个好戏就上演了。
黑客开始攻击的第一次交易17
攻击开始的准确时间:2016–06–17 03:34:48 UTC, block
“The Dark DAO”的地址为:0x304a554a310c7e546dfe434669c62820b7d83490
攻击者的主控账号:0x969837498944ae1dc0dcac2d0c65634c88729b2d
Tual前面说因为还没有分红金额,所以资金不会受影响,但对攻击者而言其实根本不是问题,攻击者自己可以往分红账户里面打一些ETH!
因为,账户并没有任何特殊之处,就是一个普普通通的地址,往里面打钱没有什么限制,而分红时,也仅仅是根据这个账号余额来计算的。
这充分说明,一个系统的开发者,往往不能意识到自己所写代码的问题,他们的思维容易被系统设计所束缚。
Tual只是想着目前还没有任何项目被投资,所以当然不会有回报,即便有回报,也还没有人提议分红,所有分红账户上的余额肯定为0。
也仅仅是业务逻辑层面的考虑,他没有想到攻击者自己可以将钱打入分红账户!(或者Tual想到了这点,但认为攻击者赚自己打的分红没有意义)。
攻击者,要赚的并不是自己打入的那点分红,而是能重入,能给子DAO多次赋予主DAO账户上的ETH。
在代码层面上讲,这到底是怎么做到的呢?
对于开发者出身的读者,可以看下一节,否则尽可以跳过。
代码的漏洞在哪里?
你现在仍然可以在上下载DAO 1.0版本的代码19。
在DAO.sol中,第603行到第676行,是函数的定义。(不得不说,这个函数太长了,编程高手会知道,一个函数不应该这么长20)
现在我们看一下函数的代码,不太重要的部分我用“...”略去了,里面的中文注释是我加的。
function splitDAO( uint _proposalID, address _newCurator
) noEther onlyTokenholders returns (bool _success)
{
...
// Move ether and assign new Tokens
// 根据调用者拥有token的多少,计算应该将多少ETH从主DAO打给子DAO
// 具体算法:应该转移的ETH金额:调用者token余额*主DAO的ETH金额/总共的token数
uint fundsToBeMoved =
(balances[msg.sender] * p.splitData[0].splitBalance) /
p.splitData[0].totalSupply;
// 调用子DAO的createTokenProxy函数(在TokenCreation.sol中),配上应该转移的ETH金额
// 子DAO收到ETH后,通过createTokenProxy函数生成调用者在子DAO里面的token
// *下面这句就是攻击者通过递归调用偷走大量ETH的那句!!!*
if (p.splitData[0].newDAO.createTokenProxy.value(fundsToBeMoved)(msg.sender) == false)
throw;
...
// Burn DAO Tokens
// 注意这里只是调用Transfer事件函数做了个日志,并没有真的转移token
// *如果这里的大写“T”是一个小写“t”,将调用transfer函数,代币将会清零,攻击将无法发生!!!*
// 下面这句就是Gün在6月13日曾经质疑的第666行!
Transfer(msg.sender, 0, balances[msg.sender]);
// 将调用者应得的分红转给他。*正是这句(第667行)导致了递归调用!!!*
withdrawRewardFor(msg.sender); // be nice, and get his rewards
// 下面这几句是转移后的账户清理,将调用者的token余额在主DAO里清零
totalSupply -= balances[msg.sender];
balances[msg.sender] = 0; //这个时候才开始更新账户余额,太晚了!!!
paidOut[msg.sender] = 0;
return true;
}
注意上面所示的第666行,正是Gün提出疑问的地方。
从的日志里面可以看出,这段代码是维护的21。
但这事也怪不得,毕竟,写这段代码的时候,还没人知道有递归调用漏洞,这就很难苛求他了。
现在我们继续看,真正引起递归调用的那句,是第667行,也即函数(也在DAO.sol里),这个函数是怎么写的?
function withdrawRewardFor(address _account) noEther internal returns (bool _success)
{
...
// 这句计算调用者应得的分红:调用着拥有的token*分红账户余额/总token数 - 调用者历史上已经提取过的分红
uint reward =
(balanceOf(_account) * rewardAccount.accumulatedInput()) / totalSupply - paidOut[_account];
...
// 实施分红动作,也即将钱打到调用者的地址上。*正是这句引起了递归调用!!!*
if (!rewardAccount.payOut(_account, reward))
throw;
// 将本次分红金额累计到调用者已经提取过的分红值中
paidOut[_account] += reward;
return true;
}
继续跟踪,引起递归调用的那个函数(在.sol中)是怎么实现的?
function payOut(address _recipient, uint _amount) returns (bool)
{
...
// 将ETH金额_amount打给_recipient,也就是调用splitDAO的那个地址
// ***这才是真正的引起递归调用的call语句!!!***
if (_recipient.call.value(_amount)()) {
//记录日志
PayOut(_recipient, _amount);
return true;
} else {
return false;
}
}
你看,通过我们不断深挖,终于找到了引起递归调用的元凶语句,正和我们前面介绍的原理攻击一样,调用了call来打钱!
而攻击者控制的合约账户,其函数中必然有一句!
比较老练的读者会提出这么个问题:递归调用总有结束的时候,那么,攻击者在主DAO中的就会被清零,攻击者就没有token了,那他控制的两个账户怎么都能发起500次之多的攻击呢?
这也是困惑我和当时很多黑客的问题,攻击者怎么做到的?
其实并不难,当攻击者在主DAO中的余额被清零后,他如果在主DAO里其他账户还有钱,调用给这个攻击地址转账token就好了!(这可是以1博30的盈利机会!)
但攻击者做得更巧妙,这点钱他都没有花。
从最容易理解的角度来讲:他仅仅在递归调用快结束时,将攻击账户中的TDT余额转给自己控制的另一个账户,然后让递归结束(正如前面示例中通过计次imToken官网,主动不再调用),这时,上次调用的函数终于可以执行耽搁已久的余额清零了,但攻击账户里的余额已经被转走了。
然后,这个余额再转回来,再发起一轮攻击。
“攻击者”发声
6月18日,有人自称是攻击者,并在上发声22。
文章比较长,翻译过来就是:
我仔细研究了DAO的代码,发现split功能可以获得额外奖励后,我使用了这个功能,并合法地领到了3,641,694个以太坊,我非常感谢DAO的这个奖励。我认为,The DAO的这个功能,是为了促进去中心化和鼓励创建“子DAO”。
有些人把这种“特性使用”称为"盗窃“,我感到很失望。我是在很正当地使用智能合约的这一明确编码功能,我的律师事务所已经告诉我,我的行动完全符合美国的刑法和民事法。你们可以仔细看看The DAO的条款:
“The DAO的条款完全体现在智能合约代码中,代码部署在以太坊区块链的13地址上。除了代码,任何条款解释、任何文档、任何交流,都不能修改或增加任何额外的义务或承诺。任何对条款的解释和描述,都只是出于教育目的,都不能并取代或修改区块链上的The DAO的代码;如果你认为这里提供的描述与The DAO代码的功能之间存在冲突或差异,The DAO的代码是最终的解释。”
软分叉或硬分叉相当于扣押我合法和正当的以太坊,这是智能合约合法赋予我的。搞这样的分叉,将永久地、不可逆转地毁掉所有的信心,不仅是对以太坊的信心,而且是对智能合约和区块链技术的信心。许多以太坊持有者将抛弃他们的以太坊,开发人员、研究人员和公司将离开以太坊。不要搞错了:任何分叉,不管是软的还是硬的,都会进一步损害以太坊,破坏其声誉和吸引力。
我保留对任何非法盗窃、冻结或扣押我合法以太坊的帮凶采取法律行动的权利,并积极与我的律师事务所合作。这些帮凶将很快收到停止通知。
我希望这次活动成为以太坊社区的一次有价值的学习经历,并祝愿大家好运。
发文的尾部附上了消息hash值和签名。
很多明眼人看出来这大概是伪造的,那个签名说明不了问题,没有证据表明这个发帖人拥有黑客的私钥。
不管此人是不是攻击者,这篇文章写得很好,也很有说服力:The DAO项目在上给出了官方宣言:所有条款都以代码为准,代码超越一切解释和说明。
支持The DAO的人可以说,没错,是代码说了算im钱包怎么隐藏转账记录,但代码没有让你重入啊!
黑客则可以反驳说:代码没有说不让重入!
如果坚持一切都是代码说了算,那黑客就没有做错什么。
所以,The DAO必须承认:通常都是代码说了算,但如果代码有Bug,那就不再说了算。
这个逻辑可以吗?
Gün在案发当天发表博客23,说到:
DAO没有自己的规格说明书,没有人知道DAO的程序员写代码的时候是怎么想的,如果说“代码就是最好的文档”,那就无法判断什么是黑客行为,什么不是。攻击者如果因为不小心而丢了钱,我相信开发者会毫不犹豫地挪用他的资金,并说“程序化的资金新世界就是这样运转的”,而当攻击者拿走钱时,开发者要想保持言行一致,他应该说:“干得好!”
Emin Gün Sirer
软分叉并不可行
V神提出的软分叉,想得挺好:抛弃那些减少DAO(包括子DAO)上金额的交易。
80名矿工在软分叉投票的头几天就决定支持,软分叉似乎很快就可以实现。
直到Gün于6月26日发表了一篇文章24称:软分叉会有DoS漏洞,攻击者可以使用这个漏洞发起拒绝服务攻击。人们才意识到软分叉不可行。
漏洞是这样的:因为从DAO减少金额的交易(比如含有调用.语句的交易)将被抛弃,不会出现在区块上,所以矿工无法因此收取gas;另一方面,这种交易也并不抛出异常,矿工无法通过状态回退而收取gas;这成了前所未有的一种交易情况:执行交易,无异常抛出,不计入区块,不收gas费。
软分叉引入了这种可能性:矿工干活但不收交易费!
对以太坊不怀好意的攻击者,可以因此发送大量垃圾交易:执行耗费大量计算资源但包含.的程序。这相当于可以无成本(不花gas费)对以太坊发起DoS攻击。
Emin Gün Sirer在他的文章中作了详尽的分析,说如果采用其他手段来修补这个DoS漏洞,只会让事情变得更糟。
社区不得不于6月28日叫停25了分叉。
这充分说明,一种临时性的补救,貌似容易,但会带来新的问题。
从程序设计角度来讲,任何不够干净的设计都会带来技术债务,越是这种设计外的补丁措施,越容易把你带入沟中。
看来,只能硬分叉了?
分叉路口
来一次硬分叉?
6月18日,Slock.it联合创始人 Tual在他的博客中发表“分叉路口”(A Fork in the Road)一文26,指出:
“随后的硬分叉甚至可以将所有的以太坊,包括DAO的和被盗的资金,重新回到一个智能合约中。该智能合约将包含一个单一的函数:()。这将使每个参与DAO的人都有可能提取他们的资金,因为到目前为止,DAO还没有资金发到外部,所以不会有任何损失。”
和前面说的软分叉不一样,硬分叉会将上的以太币强制转到一个新的合约上,这个合约叫“取现DAO”(),只有一个功能:取现。
这当然是非常规了,相当于出现了一只上帝之手,未经持有人许可,把钱从一个账号转移到另一个账号。
这需要所有的客户端都更新以太坊软件,如果你不升级,你就看不到这个改变。硬分叉的一个显著特征就是:新软件和升级前软件不兼容。
以太坊有过很多次硬分叉,如代号为“君士坦丁堡”、“圣彼得堡”、“柏林”、“伦敦”的硬分叉,但都是为了以太坊的完善和发展,为了拯救一个项目而硬分叉的,仅仅只有这一次,同时也是备受争议的一次。
以太坊方面认为:如果他们什么都不做,以太坊网络就会遭受挫折,可能需要数年时间才能恢复;
反对硬分叉的人则认为:但如果以太坊干预,就树立了一个危险的先例,以后有类似的事还救不救?
一名反对者说,“硬分叉是一个有效的选项,但它应该保留给需要紧急修改以太坊协议本身的情况,而不是用于上面运行的项目。以太坊基金会参与并推广DAO项目是一个错误,它只会篡夺人们对以太坊作为其他项目基础基础设施的信任。”
另一名反对者则说:“以太坊完全按照预期工作,我认为在软件在完全按预期工作时不应该更新。你要承担你投资的风险,如果中心化权威救助这样的事,那就是和加密世界对立。从某种程度上来说,这就是雷曼兄弟被允许失败的原因。交易就是交易,如果你为特定玩家改变规则,所有玩家也会想要特殊待遇。”27
The DAO大概就是金融危机里那些“大到不能倒”的银行。
经历多次激烈争吵(在、Slack频道、电子邮件和Skype上)和V神公开支持后,大多数以太坊社区支持硬分叉。
7月15日, 在slock.it的博客上,提出了硬分叉设计规范:Hard Fork ,并最终形成了EIP 77929。
简单地说,就是把主DAO、所有子DAO,以及额外账户上的ETH,都在以太坊节点软件中以硬编码方式,转移到取现合同上。然后让主DAO的token持有者可以拿走自己的投资,对于在子DAO的金额以及额外金额账户上的钱,则由主DAO的提走,然后再以合适方式归还原投资者。
硬分叉的期限是7月21日,这是黑客能够转移资金的日期,因为筹资期要27天,更新合约或再次split的投票需要7天。
抓紧时间!
以太坊软件的开发团队(包括Geth、、、Eth等)很快实现了这个规范,给出了升级后的版本,是否采用则要看矿工们的行动了。
2016年7月20日,自预先设定好的升级时间(第区块开始)开始,能看到大多数矿工和节点都转移到新版本了,硬分叉顺利实现了。
第二天,Gün回到康奈尔大学校园,和正在这里参加IC3研讨会暨加密训练营的成员们一同庆祝,V神也在这里,Gün带来了两瓶香槟,并在酒瓶上贴上了标签:"祝贺分叉成功”。( on the fork.)30
V神和Gün庆祝分叉成功
然而,旧的以太坊区块链仍然有支持者,这条链并没有断,以太坊形成了两条链,一条是以太坊官方认可的ETH链,一条为以太坊经典链 ( ),即ETC,这两条链直到今天仍然都活着。只不过ETC的价格要比ETH低很多。
2016年9月,和宣布下架DAO token的交易。31
The DAO就这么结束了。
黑客是谁,他得到了什么?
Tual在“分叉路口”那篇文章里说:
“我估计,这个世界上,能对以太坊和如此了解,而且能在漏洞发布后如此短时间完成这种攻击,大约只有100人。要知道,这个漏洞是6月9日公开的,而攻击者发起攻击,还需要经过投票期7天。”
Tual说,攻击者一定知道,虽然不一定会有硬分叉,但肯定会有软分叉,他永远不会直接享受他的攻击成果。他要么是为了从市场盈利,要么就是坚决反对DAO。
“无论哪种方式,攻击者应该是离安全建议者( )很近的人,安全建议者绝大多数都是我们信任的朋友、同事和顾问,我很确信,我们至少有一个人一定在过去的会议或聚会上碰见过攻击者。攻击者最好明白,所有交易所都在追溯过去两周内的交易,这意味着他很可能被追踪并被起诉。”
Tual在另一次采访中说:
“此人是以太坊和语言的绝对专家,他一定是全职程序员,业余爱好者是搞不出这种攻击的”。
Tual
在社交媒体上,一些人敏锐地指出,袭击前不久,上出现了300万美元的以太坊空头(short),如果这是攻击者做的,他可以趁此获得近100万美元的利润。很多人认为,既然攻击者这么聪明地实现了攻击,他一定会想到这点。
但我个人感觉,做空应该不是他干的。一些研究认为攻击者是一个团体,我也不这么认为,我直觉认为他是单人作战,而且是男性。
尽管他非常聪明,我想他没有更多时间、精力、资金再去买空,毕竟买空也需要准备和部署,而且更容易暴露出真实身份。
攻击者真不是一般人,在后面几年内,没有人知道他是谁。虽然很多人详尽分析了他所控制的账号和交易32,但并没有发现什么有用的线索。
他用来发起攻击的钱来自,这是一个加密货币兑换网站,在2018年10月1日之前,没有任何用户帐户、注册或注册流程,这使得追踪十分困难。
直到2022年2月,才有人说她找到了攻击者。《福布斯》杂志的记者Laura ,借助她的消息来源以及加密追踪公司的取证工具,指出了她认为最可疑的人:现年36岁奥地利程序设计师Toby ,DAO被盗时,在新加坡,他曾是加密借记卡项目TenX的联合创始人和CEO。
Shin猜测,曾对外警告The DAO项目含有安全漏洞,可能是因为被忽视而决定展开攻击。但向Shin否认了此事。
硬分叉以后,在以太坊经典链上,攻击者的战利品(364万ETC)仍然存在。那年夏天,攻击者将他的ETC转移到一个新地址上,10月下旬,他使用将ETC兑换成BTC,由于那时仍然不要求注册,因此即便能看见黑客的活动,也不知道他是谁。
在接下来的两个月里,黑客用此办法获得了282枚BTC。后来,大概是经常阻止他的交易,他放弃了套现,留下了340万以太经典(ETC),当时价值320万美元,现在价值超过1亿美元。
总结的教训
2016年8月24日, 在slock.it的官方博客上总结了教训34,主要有这么几点:
1、现在是区块链的早期阶段,智能合约的安全性会随着人们经验的累积而增强。
2、对“未知的未知”( )保持敬畏。在写DAO的时候,我们和社区没人知道还有这种漏洞。
3、逐步发布。DAO在推出时应该慢慢来,可以先中心化一点,然后逐步去中心化。
4、代码要尽可能简单。DAO的代码有663行(去掉注释和空行),而根据统计,每1000行代码就会有15-50个Bug。
slock.it的联合创始人:、Simon、Tual
太阳之下,没有新事
历史一再重复自己。
毫无疑问,以太坊还会有很多次硬分叉,其他区块链也一样。
“一切都是合约(代码)说了算”,还只是理想。
这说明什么?“契约精神”在大多数人心里,并不是最高准则。
如果契约中有漏洞,被人利用,涉及金额又很大,那么“契约精神”就会被抛弃。
人总是功利的。
通过审计就安全了?
程序员所能发现的,绝大多数是功能性bug。
程序员在代码审查的时候,投入最多注意力和逻辑力的,是看代码是否实现了项目的需求和设计。
而大多数安全漏洞,所需要的思维,和程序员根本不在一个层次。
The DAO程序员考虑的是,投票逻辑对不对,拆分逻辑对不对,分红是否合理,账户如何设计。
安全人员才会考虑函数重入怎么办?
即便是专业的安全人员,绝大多数情况下,也只是发现哪些已知类型的问题和漏洞。
那种隐藏很深的安全问题,只有真正的天才潜心研究,才能够发现。
所以,即便在发出严重的告警后,Tual仍然觉得资金是安全的。
即便是Gün这样的大牛,发现问题后,仍然不敢确认,还需要他的学生Daian分析一下(没有分析成功)。
即便是推出补丁,认可并合并出来的DAO1.1版,经过Daian分析,仍然不能防止被盗。
至今,The DAO在的项目首页上仍然写着:
“我们正在制作我们开发的免费开源标准DAO框架,因此任何希望建立一个透明的组织,其中治理和决策系统在以太坊区块链中不可改变地编程,任何人都可以重复使用它。我们社区的数百双眼睛和世界上最受尊敬的审计公司之一Deja Vu审查了该代码。”
只有一个感觉:打脸。
这段话是2016年4月12日写上去的。
两个月后,The DAO被盗。
后记
Slock.it在2019年6月被公司收购。
于2022年创建了一家新的公司:.,主要从事Web3产品构建。
Tual于2017年离开了Slock.it,在他创建的咨询公司.AI做总经理,主要给企业提供人工智能、机器学习、零知识证明等方面的咨询服务。
Daian现在(2022年)是康奈尔大学计算机系博士生,他主要的研究方向是加密货币及智能合约。
Gün于2021年离开了康奈尔大学,作为Ava Labs的创始人和CEO,专心致志从事区块链的开发和推广,已经成为以太坊的有力竞争者。
V神,则在紧锣密鼓地筹划以太坊的下一次硬分叉:Merge
这次即将到来的硬分叉,一样有很大的争议。
参考资料:
, , A Fund With of , but No (:///2016/05/22///-ether--.html?_r=1)
:///t/bug--in-mkr-token--also---would-allow-users-to-steal--from--by--/4947
以太坊智能合约安全漏洞(1):重入攻击 ()
@oaeee/the-rise-of-the-dark-dao-#.
高效能编码人士的7个习惯()
#id1
()
@oaeee/the--story-#.