34

黑客来袭,手把手带你深挖区块链安全漏洞

 5 years ago
source link: http://www.huoxing24.com/newsdetail/20180804151109665772.html?amp%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

AfmEVbE.jpg!web

目前,区块链漏洞安全问题频发。  

区块链行业正面临着私钥生成与保护、共识过程中心化、智能合约代码漏洞、签名过程算法漏洞、系统实现代码漏洞等安全问题,对于以上问题,开发者该如何应对及避免漏洞频发呢?

以下为吴家志在CSDN主办,区块链大本营、柏链道捷、极客帮创投协办的 技术沙龙 上的发言内容,区块链大本营在不改变原意的情况下作了精心整理。

nqIjmyM.jpg!web

我先自我介绍一下,我叫吴家志,目前在PeckShield担任研发副总。我们是今年年初转到区块链领域的,其实创业初期我们有做过一些其他的尝试,之前我的工作比较偏向操作系统安全方面,主要在安卓方向,像360 C0RE Team、360超级ROOT都是我在 360期间开发出来的产品。

FBJzueV.jpg!web

目前, 区块链发展的趋势是怎样的 ?可以看一下数据,蓝线代表创建智能合约数量的趋势。

可以看出,去年9月份,智能合约数量出现了大幅下滑,年底各种ICO的出现,使智能合约数量有了很大的上升,今年2月份又出现了明显的下降,过去的两到三个月也都在下降,不过7月份开始又往上涨了,这其中的原因,在场的大家都知道,我就不说了。

而且,至少2017年下半年开始到今年年初,由于区块链各行业DApp不断落地,行业形势看起来一片大好。

区块链这么火,投资人会投入大量资金去买币、炒币...

但在我们安全研究人员眼里来看,它其实是黑客非常感兴趣的目标。

yqmQzmI.jpg!web

2014年的Mt.Gox的事件 开始,一直到今年这个时间,出现了很多区块链安全事件。比如今年4月份有关智能合约漏洞的 美链(BEC) 事件,5月份的 EDU ,到近期的交易所被黑,各类安全事件很多很多。

这种安全问题,它造成的结果是非常严重的, 你的钱是真的不见了 。不像是手机里面的照片、隐私被窃这种,这根本不是一个级别的。

今天我主要讲两个主题, 智能合约安全公链安全

FnYz63I.jpg!web

深入浅出:Fomo 3D漏洞

先讲一下智能合约相关的安全问题,近期F3D十分火爆,它有很多有趣的东西,就在6天前,我们就有一个比较 新的研究 ……

微博: https://weibo.com/ttarticle/p/show?id=2309404265433178991610

这个故事是这样的,大概7月 23日晚上 8点多,我在微博上发现了一条关于F3D的信息, Geth客户端开发团队的 team leader、以太坊核心成员 Peter  发现了一个F3D的airdrop()问题,这引起了我的兴趣,然后我们就去分析。

rUBFnmR.jpg!web

neiiAnr.jpg!web

这个事情很有趣,先看右边蓝色框内,它就是F3D的智能合约之一,它其实有很多合约,今天我只讲其中一个。

其中有一个环节做airdrop(),你可以理解为它利用了 彩票抽奖 的机制,假设你投注F3D,不管你买了多少Key,买完之后它就有一个小概率事件,会让你中奖,然后你就会有一个额外的激励。我觉得这个设计也挺合理的,它可以活跃用户参与。

0.1个ETH是F3D最低的奖金,有人刻意用最低的投入去薅羊毛,他只要操作个钱,就有机会中奖。最后智能合约里面的withdraw()函数把钱取出来。

Bjeyuqi.jpg!web

先看一下function airdrop()这个函数,有个名为seed的变量,seed是随机数中很重要的一个概念, 计算机世界中不存在一个绝对的随机数 ,你只能通过seed去生成一个相对的随机数。

一旦你可以通过某种方法预测seed值,这个随机其实就会 从小概率事件可能变成一个大概率事件

比如说我刚开始学编程的时候,一开始学C,我用random()函数获取随机数,我那时候还不知道seed,我就会传空值或者传零进去,然后我发现每次跑都会是同一个结果。

这个黑客找到了一个方式, 在每次投注的时候,预测说这里一定会开奖,百分之百会开奖 。确定之后他再投这个钱,所以他每次都可以从里面拿钱出来。

说一下这个东西是怎么被预测的?其实它的实现是这样的,可以看到seed运算里面有这么几个关键点,比如说timestamp、difficulty、coinbase、gaslimit和number。

还有一个比较特别的,就是airDropTracker_,事实上这些都是合约里面的一个值,你可以随时把它读出来,所以你可以认为前面提到的全部都是已知的,唯一你不能预测的,就是msg.sender。

当时Peter认为F3D团队假设认为msg.sender的随机性是足够的,其实 msg.sender就是你进到合约时的钱包地址,F3D团队认为你不可能生成大量的钱包去尝试,然后让seed变成可预测的, 但并不是只能从钱包进来,也可以从另外一个合约进来 ,这个其实就是关键。

jYZFbuF.jpg!web

这就又涉及到一个算法,有一个叫isHuman()的函数判断,判断是真人钱包还是其他合约,但问题是这个判断有一个错误,就是Extcodesize()。

你可以用智能合约不停地刷airdrop(),这很像一个挖矿的过程,因为智能合约生成的新合约地址是可预测的,所以你就可以一直不停的算,直到算出一个seed结果满足return(true) 时,就可以保证开奖。

一旦智能合约在constructor()里面去调isHuman()判断时,它就会误判,然后造成人为开奖的结果。

AviIRn3.jpg!web

所以,就会出现这样一个的攻击模式——首先可以生成多个合约,然后就一直算,直到算到某一个可以搭配当下airDropTracker_的合约X时,就可以保证开奖,然后再根据合约X去投注,就可以不断把财经池里面的财经全部都拿走。

但其实对F3D来说,这也不是一个太大的问题。因为 被攻击的财经池只是F3D整个奖金环节中的很小一块

所以,它就好比你玩某一个游戏,有一个外挂,你的攻击力每次都加9,保证你可以把人砍死,大概是这样,有点类似破坏游戏平衡吧,但其实对整个游戏的影响不会太大,比如说把所有人的个人资产都拿走。

其他智能合约相关漏洞

接下来讲一些其他有关智能合约安全的问题。

m2EB32N.jpg!web

有一类问题是跟allowance有关的,比如ERC20里面有一个标准的API叫transferFrom(),它允许某一个人把你的钱转走,但前提是事先已经声明好的,在哪里去声明?就是在allowed[]这个数组里。

e26FNvJ.jpg!web

这里有一个问题, 虽然它可以允许你把钱转走,但是却无法判断你要转走多少钱 ,它其实是仅仅把这个allowance剪掉了,这是代码上的一个bug,EDU问题就属于这种类型。

这是我做的一个实验,我隐去了一些信息。

NBRfymf.jpg!web

最上面那个0xd开头的值是我的一个钱包地址,然后To指向是受我攻击的合约的地址,攻击完成后,我把0xa地址其中的一个EDU,就是好多0后面有1个的那个,转到了0x6这个地址,其实0x6也是我的钱包地址。

Input Data这一块是一些攻击的细节,其实这个构造起来非常简单,你只要去调transferFrom()函数,然后你就传入from、to和value。所以,我偷了一个EDU到我的钱包,这个攻击就是这样的。

3aquqi6.jpg!web

接下来,以batchTransfer()为例,讲一下overflow相关的漏洞,它的攻击是这样完成的。

iaMveqj.jpg!web

在调用batchTransfer()函数时,有两个可以传入的参数,一个是receivers,一个是value。

receivers是一个数组,它传入了40这个数,这个数值表示偏移量,是需要传给智能合约的。然后下面还有2或者8开头的。

这个逻辑是这样的,在batchTransfer()的实现上面,就是把8开头后面全部都是0的这个值,同时转给两个人

如果按一般的逻辑去理解,账号里必须有足够的钱才能够转过去。但问题是,在它实现检查时,它的实现方法是直接算两个数的乘积。

用0去乘,结果是很明显的,就算用最大的字节去乘,乘完之后它也会变成0。

所以,你可以在没有任何钱的情况下把这么多钱转给那两个人,也就是上面红色框部分,你会看到这个地方两个transfer都是这么大量的Token,美链事件就是这样,通过这种方式可以 无中生有造出大量的假币 ,然后再把假币充到OKEx里面,然后就可以进行砸盘等各种操作。

RBb6Nzy.jpg!web

另外一个案例和transfer还蛮像的,但稍微复杂一点,两个address跟value都是数组。

它们溢出的方式一样,就是说把这些值加起来或者乘起来,然后造成的结果也是一样的,就是很大量的假币就充进你钱包地址。

到这里,我大概简单讲了讲智能合约方面的安全问题,其中一个是F3D薅羊毛的最新研究,还有一些过去我们发现的其他问题。

公链安全

今天的第二个主题,我讲一下关于Infrastructure方面的安全问题,就是所谓的公链安全。

mIRfIbZ.jpg!web

PeckShield在以太坊公链上做了很多研究,EOS相关的也有一些。

讲到公链问题其实你可以这样理解,比如说你用一个360手机卫士,可以理解为有一个客户端在手机上运行,然后还有各种服务端,你要发送各种请求,然后它会推送一些信息给你。

而在区块链里面,你可以理解为只有客户端没有服务端,至少以太坊上是这样子的,每一个节点基本上长的都是一模一样的。

所以,那时候我们开始进入区块链行业、研究主链安全时, 我们其实就是去看所有客户端的代码,看它实现的逻辑有没有什么错误

i6zaqeE.jpg!web

这边是一个统计,Ethereum Nodes这个网站可以统计以太坊上都运行了哪些客户端,比如说有Geth、C++和Parity,还有Python。所以, 用的比较多的是Geth和Parity ,今天的研究主要在Geth,因为它是官方的且用户量大,对Parity也有一些研究。

ZfaiUnF.jpg!web

首先讲Geth这一块,其实谈到任何的安全问题,我们都需要先理解这样一个事情,就比如说Geth是一个盒子,我们用什么方式可以攻破它?就是所谓的 Attack Surface(攻击面) 的问题。

比如说可以通过一个 智能合约 去攻击它,那它可能就是EVM方面的问题。

还可以通过一个 RPC接口 ,它就可以类比成以前那种Web安全相关的这种问题。

还有一种,通过 协议栈 攻击,这两个其实是有点不一样的。因为区块链里面的每一个客户端之间,它们会互相去同步,或者互相分享信息,所以协议栈的问题是最底层、也比较关键的问题,一旦出问题的话,整个系统可能就不运行了。所以,接下来我主要在协议栈这一方面进行一些探讨。

aemEJ3i.jpg!web

这是以太坊的协议栈,大概是这样,很多部分可能你们以前没有听到,像ETH、LES和Whisper是你们比较熟知的,就是以太坊的协议。然后跟它并列的还有一些其他的,它的底层其实是包含RLPx、ÐΞVp2p的。

假设说你运行过Parity或者Geth,你要同步一个full node其,实很花时间,我那时候刚开始弄花了可能有小一个月,就看你的带宽怎么样了;还有就是硬盘,我发现机械式硬盘基本没戏,一定要SSD才有可能进行同步。

与ETH并列的协议LES,它是 一个比较轻的协议 ,你在同步时,你不需要将所有的信息都同步,你可能只会同步一些metadata。

所以,在运行Geth时,你可以去指定运行LES mode这种模式。

7zANbiu.jpg!web

接下来,详细介绍一下我们之前发现的关于LES的安全问题。

简单的说,就是一个 越界读 的问题,问题出在上面这一行代码,就在query.Skip这里。

我们可以自己去写一个类似于Geth的客户端,我只要知道你Geth的IP就ok。比如说有一个矿池,矿池总要有一个节点去同步到链上,我一旦知道这个IP是什么,我就可以伪造这个东西,然后让你崩溃。

jI73Uj2.jpg!web

那么,如何让它崩溃的?我 把Skip值设成-1 (在协议栈上你可以自由设置),-1+1就是0,就等于说我可以尝试让你去分配一个长度为0的数组,然后我又可以去读这个数组的Skip值为-1的位置,那一定不再是你的位置了,它已经超过了你可以控制的内存范围,所以它就必然会崩溃。

byyIBfa.jpg!web

接下来,演示一下这个 EPoD Demo ,问题出现在1810版本之前,也包括1810这个版本。

在拍摄视频时,我用的是 官网上面的1810版本 ,对比过MD5,它是没有经过任何修改的;还需要处于 离线环境 ,避免遭受外界攻击,保证所受攻击都来自本机;运行Geth的 LES mode

然后监听从本机发出来的30303端口,在运行攻击代码后, EXP后面的地址(即本机地址)是127.0.0.1,端口是30303,此时的Geth差不多就已经崩了。

index out of range,崩的理由就是这样,一个越界读。它在处理某一个这种LESMessages的时候,造成了一个越界读。TCpdump就是我攻击的钱包,我们把这个漏洞叫EPoD,我只要知道你的IP,发一个包,Geth就会崩溃,大概就是这样。

还有一些攻击,我应该会在9月份举办的ISC上讲到。

比如说你新成立一个X交易所,然后有一个成立很久的Y交易所,你觉得它的交易量很大,想让它变小,你就可以去攻击Y交易所。

一旦你知道了Y交易所的IP以及它同步的node,就可以把信息扩散出去,就会忙死一片了。

像刚刚讲的矿池, 矿池最基本的一个事情就是算力,每个矿池之间都在竞争算力,那我一旦可以让某些矿池瘫痪,这个矿池后面的算力也就没了 ,这也是非常严重的。

但是通常我知道,矿池在使用Geth的同时,也会使用Parity,两个客户端会实时进行同步。一旦我们发现Geth和Parity同时存在问题的时候,就十分有趣了。

还有就是所谓的Boot Node,这个玩过的人可能会知道,一开始同步的时候你需要知道从哪边开始同步,从哪边开始就是所谓的Boot Node。

所以, 当你瘫痪掉以太坊所有的Boot Node时,新的Geth就没有办法去同步 ,因为它根本没有办法启动。

一旦找到这种涉及公链安全而且又是协议栈的问题,就可能会遭受这些攻击的影响。

所以,如果Geth低于1810版本就赶紧升级吧。

来源: 区块链大本营


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK