Solidity合约安全漏洞分析教程【Mythril】

Stella981
• 阅读 1389

在这个教程中,我们将学习Mythril的安装与使用方法,了解Mythril的工作原理,掌握如何利用Ether Thief和Suicide模块分析合约的安全漏洞,以及如何配置Mythril安全分析的交易数量参数和执行超时参数。

用自己熟悉的语言学习以太坊DApp开发:Java | Php | Python | .Net / C# | Golang | Node.JS | Flutter / Dart

1、安装Mythril安全分析工具

执行如下命令安装Mythril:

$ pip install mythril

使用如下命令检查安装是否成功,确保版本不低于0.21.7:

$ myth version
Mythril version v0.21.15

Mythril最基本的安全分析命令是myth analyze,例如:

$ myth analyze <Solidity file>
$ myth analyze -a <contract address>

没有其他参数的话,myth analyze命令将执行适合大多数情况的通用分析。

2、Mythril工作原理

Mythril通过在一个特制的以太坊虚拟机里运行智能合约字节码来检查合约的安全问题,它使用符号执行技术来检查程序可能的状态,分析过程包含以下步骤:

1、获取合约字节码 2、初始化合约账户的状态 3、利用n个交易来探索合约的状态空间,n默认为2,但可以设置为任意值 4、当发现不希望的状态时,证明或否定其在特定假设下的可到达性

当发现一个漏洞状态时,我们可以计算到达该状态所需的交易。这不仅有助于确定问题的根源,而且也可以用于漏洞利用。

3、Mythril的基本使用方法

现在让我们用Mythril分析一个智能合约。TOkenSale是一个简单的用于买卖token的智能合约,下面是其源代码: Solidity合约安全漏洞分析教程【Mythril】 分析solidity源码要比分析链上的合约实例简单一些:在提供源码的情况下,Mythril可以展示其发现的bug所对应的代码位置。下载TokenSale 并将其另存为tokensale.sol,然后运行如下命令分析该合约的安全问题:

$ myth analyze -m ether_thief tokensale.sol

-m参数用来声明一组要执行的Mythril分析模块, 彼此之间用逗号隔开。下面让我们先了解一下Ether Thief模块。

4、使用Ether Thief模块检测合约的以太币泄露问题

正如其名称所示,Ether Thief模块检查从合约中提取以太币的交易序列,它搜索满足以下条件的状态:

  • 可以从合约提取的非零数量的以太币
  • 从合约提取以太币的账号不是合约的创建账号
  • 从合约提取的以太币数量超过了该账号之前存入合约的数量

这是一个发现合约存在以太币泄露问题的好办法。现在让我们用 Ether Thief模块分析一下TokenSale合约:

$ myth analyze -m ether_thief tokensale.sol==== Unprotected Ether Withdrawal ====
SWC ID: 105
Severity: High
Contract: TokenSaleChallenge
Function name: sell(uint256)
PC address: 696
Estimated Gas Usage: 6373 - 27034
Anyone can withdraw ETH from the contract account.

Arbitrary senders other than the contract creator can withdraw ETH 
from the contract account without previously having sent an 
equivalent amount of ETH to it. This is likely to be a vulnerability.
--------------------
In file: tokensale.sol:25

msg.sender.transfer(numTokens * PRICE_PER_TOKEN)

--------------------

Transaction Sequence:

Caller: [CREATOR], data: [CONTRACT CREATION], value: 0xde0b6b3a7640000
Caller: [ATTACKER], data: 0xd96a094ab000000000000000000000000000000000000000000000000000000000000000, value: 0x0
Caller: [ATTACKER], data: 0xe4849b323000180504000000000300013b45000000380000000002c00000020400801080, value: 0x0

Mythtril报告说在withdrawal函数中发现了一个问题,但是根源还不清楚。如果你还没找出bug在哪里,可以再仔细检查下TokenSale的代码并尝试找出攻击。

可能你已经推断出来,上面的代码中存在整数溢出问题。要利用这个漏洞,我们需要向buy()函数传入一个特定的值 —— 好消息是,Mythril已经自动帮我们计算了这个值!看一下上面的执行结果中transaction Sequence部分的输出:

Transaction Sequence:Caller: [CREATOR], data: [CONTRACT CREATION], value: 0xde0b6b3a7640000
Caller: [ATTACKER], data: 0xd96a094a2000000000000000000000000000000000000000000000000000000000000000, value: 0x0
Caller: [ATTACKER], data: 0xe4849b323000180504000000000300013b45000000380000000002c00000020400801080, value: 0x0

这一部分列出了3个交易:1个合约创建交易(由合约的creator发送)和2个攻击者发送的交易。交易的value字段的值标明没有以太币从攻击者转入合约。让我们仔细看一下data字段:

Solidity合约安全漏洞分析教程【Mythril】

第一个交易包含4字节的函数签名以及看起来没什么危害的一个额外的字节—— 0x20 —— 表示uint256类型的num_tokens参数的最左端字节,因此最终传入num_tokens的值是:

buy(0x2000000000000000000000000000000000000000000000000000000000000000)

现在让我们看一下这个输入值对第16行require语句的影响:

require(msg.value == numTokens * PRICE_PER_TOKEN);

PRICE_PER_TOKEN 被设置为1 Ether,对应1e18 wei,将这个数量与上面Mythril给出的值相乘就会产生整数溢出。更确切地说,uint256(1e18) * uint256(numTokens) 的结果为0 。

因此require语句就会通过,然后海量的token就记在交易发送方的名下了,即时他们没有发送任何以太币。

在第2个交易中,不合法的token被出售以换回以太币,即调用sell(uint256)。由于Mythril符号化表示合约账户余额,它为numTokens输出一个非常大的随机值。在现实中,攻击者将会利用与账户实际以太币余额匹配的值。

5、配置Mythril安全分析的交易数量

在使用Mythril时需要了解的一个重要概念,就是交易数量。这个变量用来指定进行符号化执行的交易的数量。默认值2对于检测许多常见bug都足够了,例如整数溢出、未初始化的存储变量以及错误命令的构造函数等。然而,只有2个交易深度还无法发现那些在更多交易下才会显现的bug。

因为每个交易都可以有多个有效的最终状态,那么当交易数量增加后,潜在的状态空间数量(理论上)将指数级增长。幸运的是,Mythril还是很聪明的,它通过分析程序执行路径之间的关系可以缩小后续交易的搜索空间,这意味着你可以在合理的时间框架内执行多个交易。

下面让我们看另一个例子,看看你是否能找出其中的安全问题,注意 合约名字:

Solidity合约安全漏洞分析教程【Mythril】 这个合约有一个后门,它允许任何知道密码的人成为合约的owner —— 我们知道,私有状态变量并不是真的秘密,和公开状态变量的区别在于,solc不会为私有变量生成访问函数。

另一个流行的Mythril模块是Suicide,这个模块检查那些由合约创建者之外的账号发送的可能杀掉合约的交易。运行Mythril分析上面的killme合约,就可以”意外地“杀掉合约:

$ myth analyze killme.sol
The analysis was completed successfully. No issues were detected.

Mythril看起来忽略了合约存在的漏洞,原因是至少需要3个交易才能杀掉合约:发送方必须向activePassword(bytes11 password)方法传入正确的密码,然后调用pwnContract()成为owner,最后调用kill()触发合约自毁。

现在让我们看看如果用-t参数增加交易数量后会得到什么结果:

$ myth analyze killme.sol -t3

==== Unprotected Selfdestruct ====

SWC ID: 106
Severity: High
Contract: Killme
Function name: kill()
PC address: 371
Estimated Gas Usage: 613 - 1038

The contract can be killed by anyone.
Anyone can kill this contract and withdraw its balance to an arbitrary address.
--------------------
In file: killme.sol:19

selfdestruct(msg.sender)
--------------------
Transaction Sequence:

Caller: [CREATOR], data: [CONTRACT CREATION], value: 0x0
Caller: [ATTACKER], data: 0xa6e0e35e63727970746f6b69747479747474747474747474747474747474747474747474, value: 0x0
Caller: [ATTACKER], data: 0x2eb00c1b, value: 0x0
Caller: [ATTACKER], data: 0x41c0e1b5, value: 0x0

这次检测出了合约中的问题,我们得到了包含3个交易的序列。查看交易的data可以了解被调用的函数名以及参数:

Solidity合约安全漏洞分析教程【Mythril】

注意:交易1中的字节序列0x747474(…) 是用于补齐uint256参数的随机数据,这部分数据可以是任意值。

6、设置Mythril安全分析的执行超时

默认情况下,Mythril会尝试执行-t参数指定数量的交易。然而,有时我们希望能指定执行时间的上限。如果增加--execution-timeout参数,Mythril就会在超过指定事件后终止,并返回在此期间发现的所有问题。

注意你可以在任何时候使用CTRL+C来中断分析任务的执行,这时Mythril也会返回此前已经发现的漏洞。例如,可以用Mythril分析Parity的WalletLibrary并设定最多分析10分钟:

$ myth analyze --execution-timeout 600 -t2 -mether_thief,suicide -c [WALLETLIBRARY-BYTECOE]

==== Unprotected Ether Withdrawal ====
SWC ID: 105
Severity: High
Contract: MAIN
Function name: execute(address,uint256,bytes)
PC address: 4384
Estimated Gas Usage: 9518 - 32483
Anyone can withdraw ETH from the contract account.

Arbitrary senders other than the contract creator can withdraw ETH 
from the contract account without previously having sent an 
equivalent amount of ETH to it. This is likely to be a vulnerability.
--------------------
Transaction Sequence:

Caller: [CREATOR], data: [CONTRACT CREATION], value: 0x0
Caller: [ATTACKER], data: 0xe46dcfeb4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080, value: 0x0
Caller: [ATTACKER], data: 0xb61d27f6000000000000000000000000deadbeefdeadbeefdeadbeefdeadbeefdeadbeef000000000000000000010000000000000000000000000000000000000000000108, value: 0x0

real    10m3.260s
user    9m11.115s
sys     0m7.727s

原文链接:Mythril教程 — 汇智网

点赞
收藏
评论区
推荐文章
可莉 可莉
3年前
10个开源的Python区块链项目
Python不是主流的区块链底层平台开发语言,但是在DApp开发、区块链仿真与数据分析、智能合约安全分析等领域,Python依然是不错的选择。本文介绍了10个最流行的Python区块链项并提供了相应的源代码下载地址。<!more区块链开发教程链接:以太坊(https://www.oschina.net/action/GoToLink
Stella981 Stella981
3年前
Defi数据引擎The Graph调用方法【含源码】
当你尝试访问以太坊智能合约以及DApp产生的区块链数据时,可能会发现很难将数据转换为一种可读的格式。TheGraph提供了一种用于查询以太坊和IPFS网络数据的索引协议,任何人都可以基于其提供的开放API创建并发布索引数据,即subgraph,这使得区块链数据更容易访问。在这个教程中,我们将学习如何使用TheGraph来查询Aave协议数据,使用的技术
Stella981 Stella981
3年前
ERC20接入Uniswap教程【DeFi】
Uniswap是基于以太坊的去中心化数字加密货币交易协议,它为代币持有者提供了简洁的接口来将一种ERC20代币兑换为另一种,并且交易所需的gas成本很低。区块链开发者可以自己的ERC20代币接入Uniswap以增强其流动性。在这个教程中,我们将学习如何将一个ERC20代币接入Uniswap协议,并且在教程的最后提供完整的实现源代码。用自己熟悉的语言学
Stella981 Stella981
3年前
EIP712实现无Gas以太坊交易【含源码】
每个人都在讨论无gas以太坊交易,因为没有人喜欢支付gas费用。但是以太坊网络能够精准地运转恰恰是因为交易需要手续费。那么如何实现无gas交易呢?让我们一起学习无gas以太坊交易的魔法!在这篇文章中,我们将学习如何实现无gas交易模式。你会发现虽然在以太坊上没有免费的午餐,但可以用有趣的方式来转移gas成本。利用本文中学到的知识,你的DApp用户就可以省
Wesley13 Wesley13
3年前
37个常见的智能合约安全问题【以太坊】
SWCRegistry是以太坊安全人员和开发人员的必备知识库。它是SmartContractSecurity提供的以太坊智能合约安全漏洞分类及测试用例集,其中包含了37种以太坊Solidity智能合约开发中常见的安全问题的描述及后果,例如重入、溢出等,同时也给出了CWE漏洞分类、解决方案和作为示例的合约程序代码。用自己熟悉的语言学习以太坊DA
Stella981 Stella981
3年前
DeFi研究资源大全,超过100个!
本文为DeFiPulse提供的去中心化金融DeFi协议及应用大全的中文翻译版,内容涵盖借贷产品、DeFi交易、去中心化支付、DeFi钱包、用户接口、DeFi基础设施、数据分析等11个分类,是区块链开发人员及金融从业者研究去中心化金融的必备资源。用自己熟悉的语言学习以太坊DApp开发:Java(https://www.oschina.
Stella981 Stella981
3年前
EthSnarks以太坊混币器【零知识证明】
Miximus是一个用于以太坊区块链的去中心化混币器和匿名转账应用,由EthSnarks作者开发,用于展示零知识证明在以太坊上的实用性。本文介绍Miximus以太坊混币应用的安装使用方法、工作原理和实现细节。用自己熟悉的语言学习以太坊DApp开发:Java(https://www.oschina.net/action/GoToLink?urlh
Stella981 Stella981
3年前
DeFi Compound开发REST API
在这个教程中,我们将学习如何为DeFi协议Compound的智能合约创建一个可以通过HTTP访问的API开发接口,并学习如何使用Infura作为以太坊网络和应用之间的桥梁。Compound是一个基于以太坊的数字资产借贷利率协议。Infura(https://www.oschina.net/action/GoToLink?urlhttp%3A%2F%
Stella981 Stella981
3年前
Solidity内联汇编简明指南
在用Solidity开发以太坊智能合约时,使用汇编可以直接与EVM交互,降低gas开销成本,更精细的控制智能合约的行为,因此值得Solidity开发者学习并加以利用。本文是Solidity汇编开发的简明教程,旨在帮助你快速熟悉如何在Solidity智能合约代码中嵌入汇编代码。以太坊教程链接:Dapp入门(https://www.oschina.n
Stella981 Stella981
3年前
Chainlink区块链Oracle网络使用指南
Chainlink是一个去中心化的预言机网络,它可以让区块链中的智能合约安全地访问外部世界的数据。在这个教程中,我们将探索chainlink预言机网络的搭建,并学习如何使用预置或自定义的适配器实现智能合约与外部世界数据的桥接。以太坊教程链接:Dapp入门(https://www.oschina.net/action/GoToLink?urlh