前言:以太坊网络上备受瞩目的、号称永不结束的资金盘游戏Fomo3D的第一轮在8月22日戛然结束,出乎大多数人的意外。最终大奖由地址 0xa169 获得,奖金总额达到了 10469个以太坊。那么这个玩家是靠运气获得了最后一把钥匙,进而获得大奖的吗?显然不是。这是黑客精心设计并且经过反复测试的特殊攻击所取得的结果。这名大奖获得者巧妙利用了以太坊的技术弱点,采取了独特的狙击手段,使得连续多个区块中矿工打包入区块内的交易数量骤减,虽然在理论上并不能保证100%成功,但却起到了大概率提高胜率的作用。
攻击过程
下面让我们复盘一下当天黑客进行攻击的全过程:
➊在区块高度6191896,攻击者0xa169 的购买钥匙的交易被区块打包。
➋在区块高度 6191897 到 6191902,攻击者开始使用垃圾合约来填充区块,gasPrice被设置为20G wei左右的平均水平。不得不佩服黑客的耐心,以潜伏的方式对网络中的交易进行监测,结果是之后的6 个区块的时间内并没有其他人参与购买 key,竞争者很少。
➌从区块高度6191903 开始,攻击者将合约调用交易的 gasprice 突然提高到了 190 GWei,远高于平均水平,后续交易更是设置了 500 GWei的超高 gasprice,开始了真正的攻击。直到 6191908 区块,这 6 个区块中每个区块都只包含了不到10笔交易,可用 gas 完全被这些高 gasprice 的无效交易所占用,以太坊网络此时已经被堵塞。
➍在区块高度 6191909,游戏宣告结束,网络状况恢复正常。
图中标红区块为攻击集中发生区块
黑客的整个攻击过程计划地非常缜密、高效、也很有耐心,一方面使用高的 gasprice 来吸引矿工打包该笔交易,又通过在以太坊虚拟机执行层面耗费大量的 gas 牢牢占据区块,实现堵塞整个 ETH 网络的目标,从而在短时间内阻止了其他玩家的钥匙交易的成功确认。
当然攻击者的计划并非万无一失,曾经有一个 gasprice 高达 5559 GWei购买钥匙的交易闯入了区块6191907中。但很可惜的是这个交易的 gaslimit仅设置了 379000,gas limit不足导致发生了 out of gas的错误导致交易失败,白白浪费了 2.1 Eth 的手续费,最终也和大奖失之交臂。
唯一突破黑客封锁
写入区块的超高gas price交易
攻击原理分析
交易可选择性
➊手续费竞争
在以太坊中,矿工会从选取那些 gasprice 明显高于其他交易的交易来优先打包执行,即为交易的可选择性。基于手续费竞争的原理,就允许了黑客通过人为调高包含了无效合约调用交易的 gasprice,在短时间内用这些无意义的交易占用区块的可用 gas,以使其他正常交易无法被打包进区块。
➋gas limit
以太坊中的区块可包含的交易数是由区块的 gaslimit 来控制的。区块内能包含的交易数量,是看这些交易执行所消耗的总 gas 是否达到这个区块的 gaslimit。目前区块的 gaslimit 上限一般是 800 万 gas。
以太坊上每笔交易也有 gas Limit 概念,交易发起者自行设定,代表该笔交易可最多消耗的 gas 上限,实际 gas 消耗以交易具体执行消耗为准。
➌无效指令
你可能要问攻击者是如何顺利地通过少量交易就占用整个区块的 gas limit?那就不得不提以太坊的智能合约Solidity 中三个指令可以撤销合约执行中的所有状态修改并导致合约执行异常停止的指令,分别是require、revert 和 assert。根据 EVM 的指令设计,调用require 和 revert 实际上最终都是使用了 EVM 操作码 0xfd, 在程序停止执行时会进行回滚并返还交易执行所剩余的 gas。而调用assert,则在条件满足时会使用 EVM 操作码 0xfe无效指令,从而消耗交易附带的所有可用 gas。而耗光区块的gas limit正是攻击者乐于看到的结果,所以我们看到在游戏结束前的十几个区块中存在很多由0xfe无效指令导致的Bad Instruction 失败交易,均是由于assert指令触发所导致的。
图灵完备智能合约
以太坊提出的图灵完备智能合约概念与比特币简单脚本系统相比有很多优势,但也存在很大的安全风险,以太坊上线运行三年来,智能合约导致的安全事故屡出不穷。
➊无法预测gas使用量
上述失败的攻击者无法有效预测gas limit的原因正是由于fomo3d项目本身仅仅只是部分开源。其主合约0x9da1虽然开源,但查看其代码发现仍有三个子合约并未对外开源。
➋反编译
而以太坊Solidity语言目前并无任何的反编译工具,所以无法通过代码有效地预测或者验证执行结果,只能通过跟踪调用数据来反推。而缺乏形式化验证也使得合约的安全性也无法得到充分的保证,而正是以太坊代码层面的图灵完备使得可以实现种类更多、条款更复杂的合约,当然的代价是复杂的合约内容使其变得更加难以分析,反倒给黑客发起攻击提供了便利,由此也让我们看到了限制代码复杂度和功能性的必要性。
对公链项目设计的启示
➊设计更加合理的手续费模型,而非以太坊仅仅通过EVM执行操作来收取gas。
➋取消0xfe等无效指令,gas消耗以实际使用为限,不允许滥用gas来堵塞区块。
➌限制高gas消耗的指令在同一交易中可使用的次数,矿工可通过静态代码检查来屏蔽该类交易。
➍采取措施限制未开源的智能合约上链。对未开源的智能合约以及对其进行调用的合约进行显式标记,并且提供有效的智能合约反编译工具。
➎简化智能合约指令集。取消跳转指令,并限制一般性循环指令的使用。同时鼓励使用可预测的循环指令,从而起到便于对合约进行静态检查的目的。
从Fomo3d的大热到被黑客攻破的遇冷,让我们看到了以太坊作为区块链交易载体以及目前运行的智能合约的局限性。POW的共识算法导致了目前以太坊的交易吞吐量和可扩展性十分有限,也就使得攻击者可以很轻易地便将网络堵塞,而智能合约的复杂性又使得其安全性不能得到完全的保障,使得黑客有了可趁之机。
而Penta作为下一代公链基础设施,正试图解决以太坊存在的种种问题,在区块链的性能、可扩展性以及安全性方面不断改进和完善,比如DSC共识算法,PSG分片模型以及PDW智能合约引擎等等,通过多种途径共同营造一个更加高效、公平、安全的区块链生态网络。
閱讀更多 Penta公鏈中文社區 的文章