oyente-ccs2016-智能合约安全论论文精读

整理文档很辛苦,赏杯茶钱您下走!

免费阅读已结束,点击下载阅读编辑剩下 ...

阅读已结束,您可以下载文档离线阅读编辑

资源描述

MakingSmartContractsSmarterCCS2016Abstract&contributionBackgroundSecuritybugsEthererumBetterdesignOyenteDesign目录Abstract•在Ethereum智能合约中记录了几类新的安全漏洞•对Ethereum智能合约的语义进行了形式化,并提出了一些建议,作为文档中bug的解决方案。•对于为现有的Ethereum系统编写智能合约的开发人员,我们构建了一个名为Oyente的符号执行工具来查找潜在的安全bug。•在现有的19366份以太坊合同中,Oyente认为其中有8833份是易受攻击的,包括2016年6月导致6000万美元损失的TheDAO漏洞。(确认在以太坊中可以攻击)Background•去中心化数字货币在一组点对点网络节点之间维护一个共享的分布式账本。节点之间运行一种对等的共识协议。分布式账本被称为区块链,并被所有的节点复制。分布式账本被组织成按时间排序的块的哈希链,其中每个块都有一组事实,如下图所示。•在每轮共识中,每个节点都提出自己的块来更新区块链。节点可以选择一个新事务序列来包含在建议的块中,在所有节点中概率性地选出一位领导节点。•然后,领导节点向所有其他节点广播其提议的区块,如果提议的区块遵守某种预先定义的有效性约束,比如那些确保减轻双重支出攻击的约束,那么所有的节点都会更新他们的账簿,以包括新的区块。Background•一个区块链状态σ是一个从地址映射到账户,比如一个账户的地址为γ,则其账户对应的状态为σ[γ]。•Ethereum的账户包括普通账户和合约账户(以公钥地址标识),普通账户只包括余额;合约账户则包括余额、智能合约可执行代码、持久化存储变量。可以通过向每个地址发送参数调用智能合约。•从概念上讲,Ethereum可以看作是一个基于事务的状态机,它的状态在每个事务之后更新。通过事务T有效的从σ过渡到σ0。Background–SmartContract•智能合约是存储在区块链中的自治代理,用于向区块链创建事务。一旦成功创建,智能合约将通过合约地址进行标识;•每个契约拥有一定数量的虚拟货币(以太),有自己的私有存储变量,并与其预定义的可执行代码相关联。•合约状态由两个主要部分组成:私有存储和它所持有的虚拟货币的数量(称为余额)。合约代码可以像传统命令式程序那样操作变量。•Ethereum合约的代码是一种低级的、基于堆栈的字节码语言,称为Ethereum虚拟机(EVM)代码。用户使用高级编程语言定义契约,例如,solidity(类似javascript的语言),然后将其编译成EVM代码。•调用一个合同地址γ,用户发送向合同地址发送事务。事务通常包括:合约在虚拟机中执行产生所需的付款和调用的输入数据。Background–Gassystem•智能契约是一种分布式执行代码的机制。为了保证计算工作量的公平补偿,Ethereum向Leader节点支付一定比例的计算费用。•具体来说,Ethereum字节码中的每个指令都有预先指定的气体量。当用户发送事务来调用契约时,必须指定愿意为执行提供多少gas(称为gasLimit)以及每个gas单元的价格(称为gasPrice)。•如果一个Leader节点将交易包含在他的提议区块中,那么他将收到交易费,这笔交易费等于交易实际消耗的天然气量乘以天然气价格。如果某些执行需要比gasLimit更多的气体,则会异常终止执行,如果执行并没有发生,σ状态恢复到初始状态。但是,在这种中止的情况下,发送方仍然必须向Leader节点支付所有的gasLimit,作为对抗资源耗尽攻击的对策。SecurityBugs事务依赖性•一个块包含一组事务,因此每个epoch中会多次更新区块链状态。考虑这样一个场景,区块链在σ状态和新的块包括两个事务(例如,Ti,Tj)调用相同的合约。在这种情况下,用户不确定在执行各自的调用时合约处于哪个状态。•例如,Ti执行合约时,可能要求在σ(α)或σ’(α)状态,【σ→Tj→σ’(α)】,依赖事务Ti和Tj之间的秩序。因此,用户可能打算调用的契约状态与相应执行时的实际状态之间存在差异。只有挖掘块的矿工才能决定这些事务的顺序,从而决定更新的顺序。因此,合约的最终状态取决于Leader节点如何对调用它的事务进行排序。我们将这种合约称为事务排序依赖(或TOD)合约。•比如:Ti执行合约时要求在σ’(α),就需要先执行Tj。•如果存在并发调用,即使是对契约的良性调用也可能会给用户带来意想不到的结果。其次,恶意用户可以利用TOD合同获取更多的利润,甚至盗取用户的钱财。事务依赖性-并发调用•考虑两个事务到和Tu发送到Puzzle大致在同一时间。To来自合同所有者更新奖励,Tu来自用户提交有效解决方案领取奖励。由于To和Tu几乎同时广播到网络,下一个块很可能包含这两个事务。•两个事务的顺序决定了用户从解决方案中获得多少奖励。用户希望在提交解决方案时得到他所观察到的奖励,但是如果先执行,他可能会得到不同的奖励。•在另外合同中,卖家经常更新价格,用户发送订单购买某些商品(右图)。根据交易订单的不同,用户的购买请求可能会通过,也可能不会通过。更糟糕的是,当买家发出购买请求时,他们可能不得不支付比观察到的价格高得多的价格。事务依赖性-恶意使用恶意所有者可以利用对事务排序的依赖来获得财务优势。注意,当事务Tu被广播时和它被包含在一个块中时之间有一个时间间隔。在Ethereum,找到新方块的时间大约是12秒。因此,拼图契约的恶意所有者可以继续监听网络,以查看是否存在向其契约提交解决方案的事务。如果是,他发送他的交易,以更新的奖励,使它小到零。在一定的机会下,To和Tu都被包含在新的块中,而他的To被放置(这样执行)在Tu之前。因此,所有者可以享受免费解决他的难题。时间戳依赖当挖掘一个块时,矿工必须为块设置时间戳(图2)。但是,矿工可以将这个值改变大约900秒,而其他矿工仍然接受块。具体地说,在接收到一个新块并检查其他有效性检查之后,采矿者将检查块时间戳是否大于前一个块的时间戳,并且与本地系统上的时间戳之间的时间间隔不超过900秒。因此,对手可以选择不同的块时间戳来操作依赖于时间戳的契约的结果矿机可以将块时间戳设置为一个特定的值,该值将影响与时间戳相关的条件的值,并对矿机有利。例如,在theRun契约中,前一个块的哈希值和块号是已知的,其他的契约变量,如最后一次支付,有助于随机种子的产生,也都是已知的。因此,采矿者可以预先计算并选择时间戳,这样函数random就会产生对他有利的结果。结果,对手可能会完全偏向随机种子的结果为任意值,从而将头奖授予任何他喜欢的玩家。因此,对于任何能够操纵块时间戳的对手,theRun都是脆弱的。未处理异常•在Ethereum中,有几种方法可以让一个契约调用另一个契约,例如,通过send指令或者直接调用一个契约的函数(例如,aContract.someFunction())。如果在被调用契约中引发异常(例如,没有足够的气体,超过调用堆栈限制),则被调用契约终止,恢复其状态并返回false。但是,根据调用的方式,被调用契约中的异常可能会传播到调用者,也可能不会传播到调用者。例如,如果调用是通过send指令进行的,那么调用方契约应该显式地检查返回值,以验证调用是否正确执行。这种不一致的异常传播策略导致许多情况下无法正确处理异常。可重入漏洞•第11行将内部变量userbalance所指示的取款程序的当前余额发送到希望取款的合同地址。•然而,变量userbalance只有在调用之后才会被归零,这意味着记录用户余额的契约的持久存储还没有被更改。•第11行调用的被调用契约使用其默认函数,可以调用withdrawBalance,直到该契约耗尽gas或者ether(以先出现的为准)。OYENTELoremipsumdolorsitamet,consecteturadipiscingelit.Integermollisvehiculaligulautfaucibusgermor,Curabiturvestibulumconsequaturnaetvehicula.符号执行(如果条件是M^(N12),那么最终的属性值R=0,M^(N12)表达的是,M是非零值且N要小于12,Q为任意值的情况下,得到R=0。)如果把结果条件(R=3)更改为漏洞条件,理论上也是能够进行漏洞挖掘了。OYENTE•我们的分析工具基于符号执行。•符号执行将程序变量的值表示为输入符号值的符号表达式。每个符号路径都有一个路径条件,该条件是通过累积那些输入必须满足的约束来建立的符号输入的公式,以便执行遵循该路径。•如果一个路径的条件是不可满足的,那么这个路径就是不可行的。否则,路径是可行的。它回答契约是否有任何安全问题(例如,事务依赖、时间戳依赖、错误处理的异常),向用户输出有问题的符号路径。它接受两个输入,包括要分析的契约字节码和当前的Ethereum全局状态(私有变量持久存储)。OYENTE•Ethereum全局状态提供契约变量的初始值(或当前值)•所有其他变量包括值、消息调用的数据都被视为输入符号值•它由四个主要组件组成,即CFGBuilder、Explorer、CoreAnalysis和Validator。•CFGBuilder构造契约的控制流图,其中节点是基本执行块,边表示块之间的执行跳转。•Explorer是我们的主要模块,它象征性地执行契约。•然后将Explorer的输出提供给CoreAnalysis,在那里我们实现了针对第3节中确定的漏洞的逻辑。•最后,验证器在向用户报告之前过滤掉一些误报。OYENTE•CFGBuilder构建一个骨架控制流图,其中包含作为节点的所有基本代码块,以及一些表示跳转的边缘,这些跳转的目标可以通过局部调查相应的源节点来确定。然而,有些边在这个阶段不能被静态地确定,因此它们是在后面阶段的符号执行过程中动态地构造的。•Explorer从框架CFG的入口节点开始。在任何时候,Explorer都可能执行许多符号状态。Explorer的核心是一个解释器循环,它让一个状态运行,然后在该状态的上下文中象征性地执行一条指令。此循环继续,直到没有剩余的状态,或者达到用户定义的超时为止。OYENTE•到了第二个codeanalysis,这一部分其实是这个Oyente最为核心的一个部分,就是它将刚刚输出的explorer这种路径把它转化,至始至终只包含Ether的一些路径,进行一些漏洞验证,而他目前只提供包括TOD、Timestampdependence、Mishandledexceptions这三种验证。•最后系统为了保证误报率和漏报率,采用了微软的Z3Bit-VectorSolver开源的验证器,然后来进行整体架构的一个封装。OYENTE事务依赖(TOD):Explorer为每个跟踪返回一组跟踪和相应的ether流。因此,我们的分析检查两个不同的轨迹是否有不同的ether流。如果一个合约有这样的跟踪,Oyente将其报告为TOD合约。时间戳依赖检测。我们使用一个特殊的符号变量来表示块时间戳。注意,在执行期间,块时间戳保持不变。因此,给定跟踪的路径条件,我们检查是否包含这个符号变量。如果一个契约的任何跟踪都依赖于这个符号变量,那么它就被标记为与时间戳相关。处理异常。检测错误处理的异常非常简单。回想一下,如果一个被调用者产生一个异常,它将0推给调用者的操作数堆栈。因此,我们只需要在每次调用后检查契约是否执行ISZERO指令(该指令检查堆栈的顶值是否为0)。如果没有,则忽略调用中发生的任何异常。因此,我们将此类契约标记为处理异常错误的契约。可重入性检测。我们利用路径条件来检查可重入性漏洞。在遇到的每个调用中,我们在执行调用之前获取执行的路径条件。然后,我们用更新的变量(例如,存储值)检查这种条件是否仍然适用(例如,存储值)。,如果可以再次执行该调用)。如果是这样,我们认为这是一个漏洞,

1 / 24
下载文档,编辑使用

©2015-2020 m.777doc.com 三七文档.

备案号:鲁ICP备2024069028号-1 客服联系 QQ:2149211541

×
保存成功