揭秘以太坊“后偷渡时代”的盗币方式
摘要: 通过智能合约进行交易,不用管交易时间,不用管交易合法性,只要能够符合智能合约的规则,就可以进行无限制的交易。在巨大的经济利益下,总会有人走上另一条道路。
以太坊,作为区块链 2.0 时代的代表,通过智能合约平台,解决比特币拓展性不足的问题,在金融行业有了巨大的应用。
通过智能合约进行交易,不用管交易时间,不用管交易是否合法,只要能够符合智能合约的规则,就可以进行无限制的交易。在巨大的经济利益下,总会有人走上另一条道路。
在2018年6月29日,以太坊黑色情人节事件(即偷渡漏洞)新型攻击手法被发现。该攻击手法在本文中亦称之为:离线攻击。在结合蜜罐数据复现该攻击手法的过程中发现,在真实场景中,还存在另外两种新型的攻击方式:重放攻击和爆破攻击,由于此类攻击方式出现在偷渡漏洞曝光后,我们将这些攻击手法统一称为后偷渡时代的盗币方式。
下面将会在介绍相关知识点后,针对偷渡漏洞及后偷渡时代的盗币方式,模拟复现盗币的实际流程,对攻击成功的关键点进行分析。
一、关键知识点
1.1 RLP 编码
RLP(递归长度前缀)从名字可以看出它的特点:一个是递归,被编码的数据是递归的结构,编码算法也是递归进行处理的;二是长度前缀,也就是RLP编码都带有一个前缀,这个前缀是跟被编码数据的长度相关的,RLP提供了一种适用于任意二进制数据数组的编码,RLP已经成为以太坊中对对象进行序列化的主要编码方式。
RLP编码会对字符串和列表进行序列化操作,具体的编码流程如下图:
在此,也以3.4.1节中eth_signTransaction接口返回的签名数据为例,解释该签名数据是如何经过tx编码后得到的。
根据RLP编码的规则,我们对tx字段当作一个列表按顺序进行编码(hash 除外)。由于长度必定大于55字节,所以采用最后一种编码方式。
暂且先抛开前两位,对所有项进行RLP编码,结果如下:
合并起来就是:
一共是214位,长度是107比特,也就意味着第二位是0x6b,第一位是0xf7+len(0x6b)=0xf8, 这也是最终raw的内容:
1.2 keystore 文件及其解密
keystore文件用于存储以太坊私钥。为了避免私钥明文存储导致泄漏的情况发生,keystore文件应运而生。让我们结合下文中的keystore文件内容来看一下私钥是被如何加密的:
在此,将结合私钥的加密过程说明各字段的意义:
加密步骤一:使用aes-128-ctr对以太坊账户的私钥进行加密
开头那里已经说到,keystore文件是为了避免私钥明文存储导致泄漏的情况发生而出现的,所以加密的第一步就是对以太坊账户的私钥进行加密。这里使用了aes-128-ctr方式进行加密。设置解密密钥和初始化向量iv就可以对以太坊账户的私钥进行加密,得到加密后的密文。
keystore文件中的cipher、cipherparams、ciphertext参数与该加密步骤有关:
加密步骤二:利用kdf算法计算解密密钥
经过加密步骤一,以太坊账户的私钥已经被成功加密。我们只需要记住解密密钥就可以进行解密,但这里又出现了一个新的问题,解密密钥长达32位且毫无规律可言。所以以太坊又使用了一个密钥导出函数(kdf)计算解密密钥。在这个keystore文件中,根据kdf参数可以知道使用的是scrypt算法。最终实现的效果就是:对我们设置的密码与kdfparams中的参数进行scrypt计算,就会得到加密步骤 1中设置的解密密钥.
keystore文件中的kdf、kdfparams参数与该加密步骤有关:
加密步骤三:验证用户密码的正确性
假设用户输入了正确的密码,只需要通过步骤一二进行解密就可以得到正确的私钥。但我们不能保证用户每次输入的密码都是正确的。所以引入了验算的操作。验算的操作十分简单,取步骤二解密出的密钥的第十七到三十二位和ciphertext进行拼接,计算出该字符串的sha3_256的值。如果和mac的内容相同,则说明密码正确。
keystore文件中的mac参数与该步骤有关:
综上所述,要从keystore文件中解密出私钥,所需的步骤是:
流程图如下:
1.3 以太坊交易的流程
根据源码以及网上已有的资料总结了以太坊的交易流程如下:
1.用户发起转账请求。
2.以太坊对转账信息进行签名
3.校验签名后的信息并将信息加入交易缓存池 (txpool)
4.从交易缓存池中提取交易信息进行广播
对本文来说,步骤2:以太坊对转账信息进行签名对于理解3.4节利用离线漏洞进行攻击十分重要。
从上文中我们可以知道,私钥已经被加密在keystore文件中,所以在步骤2进行签名操作之前,需要将私钥解密出来。在以太坊的操作中有专门的接口用于解锁账户:personal.unlockAccount
在解锁对应的账户后,我们将可以进行转账操作。在用私钥进行签名前,存在一些初始化操作:
这里可以注意一点:Transaction结构体中是不存在from字段的。这里不添加from字段和后面的签名算法有着密切的关系。
使用私钥对交易信息进行签名主要分为两步:
对构造的列表进行RLP编码,然后通过sha3_256计算出编码后字符串的hash值。
由于以太坊的地址是公钥去除第一个比特后经过sha3_256加密的后40位,所以在交易信息中不包含from的情况下,我们依旧可以知道这笔交易来自于哪个地址。这也是前文说到Transaction结构体中不存在from的原因。
在签名完成后,将会被添加进交易缓存池(txpool),在这个操作中,from将会被还原出来,并进行一定的校验操作。同时也考虑到交易缓存池的各种极端情况,例如:在交易缓存池已满的情况下,会将金额最低的交易从缓存池中移除。
最终,交易缓存池中存储的交易会进行广播,网络中各节点收到该交易后都会将该交易存入交易缓存池。当某节点挖到新的区块时,将会从交易缓存池中按照gasPrice高低排序交易并打包进区块。
所谓磨刀不误砍柴功,只有清楚地掌握了关键知识点,才能在理解下面的漏洞原理时游刃有余。
(作者:区块链安全档案,内容来自链得得内容开放平台“得得号”;本文仅代表作者观点,不代表链得得官方立场)
评论(0)
Oh! no
您是否确认要删除该条评论吗?