近期,一名英国的15岁黑客Saleem Rashid爆出,Ledger Nano S这款比特币硬件钱包有严重的安全性漏洞,它可能会被黑客控制,成为黑客安插在你身边的“间谍”,偷走你的比特币。
什么是Ledger Nano S?这可是硬件钱包市场上的明星产品。
此后,Rashid将他的破解教程发布在个人博客之中,经区块链大本营整理如下。害人之心不可有,防人之心不可无。希望这篇文章,能让你多一些警惕吧。
作者 | Saleem Rashid
编译 | Guoxi
编辑 | 小西
在这篇文章中,我将讨论我在Ledger硬件钱包中发现的一个漏洞。Ledger公司使用自己开发的体系架构来解决比特币硬件钱包安全性上的限制,因此,这个安全体系难免会有一些漏洞。
Ledger Nano S比特币硬件钱包
因为这个漏洞,Ledger硬件钱包变得极其不安全。黑客不仅可以在用户拿到Ledger硬件钱包之前黑掉它,还以物理方式甚至在某些场景下可以远程从硬件钱包中窃取用户的私钥,也就意味着,黑客可以轻而易举地偷走你的比特币。
那么,黑客到底是怎么实现的呢?
如何偷走比特币
1.在设置种子之前进行物理访问
本文中我们将用到供应链攻击,软件供应链是指由软件源码编写,源码编译,软件分发,软件下载,软件更新环节组成的流水线。软件供应链攻击则是在软件供应链中的各个环节利用不同的技术对软件进行攻击。使用供应链攻击并不需要目标计算机上的恶意软件,甚至不需要用户对交易确认。我已经在Ledger的Nano S型比特币硬件钱包上实现了这种攻击,此外,为了维护系统的安全性,我在几个月前就将源码发给了Ledger,以便Ledger修复此漏洞。
从上面的视频中可以看出,我们可以轻而易举地执行供应链攻击修改生成的用于恢复的种子。由于所有的私钥都来自于恢复种子,所以,黑客可以盗取所有加载到硬件钱包上的数字资产。
2.安装后的物理访问
这通常被称为邪恶女佣攻击。攻击后你可以提取到硬件钱包上的PIN,恢复种子和任何使用的BIP-39口令。
如前所述,这并不需要计算机上的恶意软件,也不需要用户确认任何交易。它只需要黑客安装一个自定义的MCU(Microcontroller Unit,微控制单元,又称微控制器或者单片机,下文使用微控制器)固件,用户下次使用比特币硬件钱包时,私钥就会在他们不知情的情况下泄露出去。
3.恶意软件(带一些社交工程学)
这种攻击方式会要求用户在中病毒的计算机上升级MCU固件。这可以通过显示一条系统错误信息误导用户,要求用户按住左键并重新连接比特币硬件钱包(以进入MCU的引导加载程序)来实现。然后恶意软件可以用恶意代码更新MCU固件,从而允许恶意软件控制比特币硬件钱包的显示屏和确认按钮。
这种攻击以发生过多起,常常是在官方进行固件更新时出现。
概念验证
如果你不想错过创建一个漏洞的机会,你可以来Github上找到我的概念证明。
如果你按照说明进行操作并把它安装在运行固件版本为1.3.1及以下的Ledger Nano S比特币硬件钱包上,你可以实现刚才视频中的攻击。但是,因为这只是为了教育目的,我故意让你复原出的攻击不可靠。
比特币硬件钱包的前世今生
像比特币这样的加密货币使用公钥密码学(又称非对称密码学,是使用一对公钥和私钥的密码学)来保障资金安全,只有你拥有私钥,才能使用这笔资金。
这给用户造成了一个问题,用户应该如何保护自己的私钥?通常,人们在记忆密码方面的表现都十分糟糕,即使安全专家也不例外。
为了解决这个问题,出现了一种新的设备叫做“比特币硬件钱包”。顾名思义,这种硬件设备可以存储用户的私钥以防范恶意软件,这种设备一般都可以通过USB端口连接到电脑上,但是并不会在电脑上泄露私钥,就像硬件安全模块(hardware security module,HSM,可以理解为银行卡配套的U盾)一样。
然而,获取私钥并不是黑客窃取你心爱的比特币的唯一方式,攻击比特币硬件钱包的黑客可以轻而易举地更改你交易的对象和交易的金额,从而把你的钱转到他的账户上。这是秘密完成的,许多用户都没有意识到自己受到了黑客的攻击,发现时已为时已晚,自己的比特币就这么丢失了。
因此,一个比特币硬件钱包应该有以下几个功能,从而和笨拙的硬件安全模块区分开来。
- 用于可视化验证交易信息的可信的显示屏
- 设备上的按钮,用来确认或拒绝签署交易
比特币硬件钱包也需要防范各种各样的攻击:
- 远程攻击(即黑客通过计算机上的恶意软件窃取用户私钥)
- 供应链攻击(即黑客篡改比特币硬件钱包以至于用户一开始就收到了一台黑客控制的比特币硬件钱包)
- 未经授权的物理访问(如果黑客获得了物理访问的权限,比如窃取了你的比特币硬件钱包,可能会危害你的资金安全)
我们可以进一步将最后一个攻击的程序分为两步:窃取比特币硬件钱包和实行邪恶女巫攻击,如果黑客可以窃取设备,那么他会有更长的时间来执行攻击,甚至可能使用到实验室中昂贵但高性能的破解设备。但是,在此期间用户可能会意识到比特币硬件钱包的丢失并将钱转出。
安全功能,比如未存储在比特币硬件钱包中的密码数据可以防止攻击者窃取你的资金,因为仅仅一个比特币硬件钱包并不包含恢复用户私钥所必要的完整信息。
另一方面,在邪恶女仆攻击中,黑客只能在有限的时间里执行攻击,而且没有了实验室中高性能设备的加持。但是这种攻击方式可能更加危险,因为它可用于多种场景中:
- 顾名思义,一个邪恶的女仆可能会在你的酒店房间清洁时入侵你的比特币硬件钱包。
- 当你在机场安检时,你的比特币硬件钱包可能会短时间被带走。
- 你能会把比特币硬件钱包委托给你的亲属或律师。
还有一种场景,我们要关注供应链攻击的可能。即:当你从经销商或第三方购买比特币硬件钱包时,你拿到的设备是否可信?正如我最开始说的那样,你的比特币硬件钱包可能已经遭受了攻击。
入侵比特币硬件钱包
2014年9月,Ledger发布了HW.1比特币硬件钱包。这款钱包基于微控制器ST23YT66,含有一张智能卡,支持USB连接。不幸的是,这个设计有严重的局限性:这款钱包没有一个可信任的显示或按钮,这使得钱包用起来很危险。
2016年7月,Ledger宣布推出名为Nano S的新款比特币钱包,这款钱包基于安全元件(Secure Element,通常以芯片形式提供。为防止外部恶意解析攻击,保护数据安全,在芯片中具有加密/解密逻辑电路。)ST31H320,含有确认按钮,可信任的显示屏,支持USB连接。
2017年11月,我决定仔细研究Nano S的安全性。
来看看Nano S的双芯片架构。 尽管ST31H320没有可用的公共数据表,仅仅查看数据摘要我们发现此款安全元件并不支持显示!实际上,它甚至不支持USB连接,它支持的唯一接口是低吞吐量的UART(Universal Asynchronous Receiver/Transmitter,通用异步收发传输器,是一种异步收发传输器,是电脑硬件的一部分)。
什么鬼?那显示屏是怎么工作的呢?
碰巧,Ledger开发了一个新的架构来解决这个问题,Nano S增加了一个非安全的微控制器STM32F042K6,由它来充当安全元件的代理。该微控制器驱动显示器,按钮和USB接口。两芯片各有分工,安全元件存储私钥,非安全的微控制器充当安全元件的接口。
为了描述简便,我们将把ST31H320安全元件称为SE,将STM32F042K6微控制器称为MCU。架构如下图所示。
Ledger Nano S的架构
长话短说,安全元件只能与微控制器直接通信,但是,微控制器可以代表安全元件与外设进行通信。
安全元件的一个重要特性就是我们可以执行密码学验证证明它是否正在运行Ledger官方固件,这实际上也是Ledger的一个卖点:实际上,Ledger认为这个安全功能十分强大,以至于Ledger比特币硬件钱包都不需要贴防开封标签,正如商品随附的说明中所述:
其他公司的硬件钱包都贴了防开封标签
商品随附的说明
(你是否发现,我们的产品上并贴没有防开封标签。别担心,Ledger的密码机制会在每次开机时检查固件的完整性,安全元件芯片可以防止各种入侵和物理破坏,我们的产品十分安全)
Ledger的首席技术官甚至告诉用户Ledger比特币硬件钱包十分安全,不用担心购买的来源,可以放心大胆地从第三方平台如eBay上购买Ledger比特币硬件钱包。
这带来了一个很关键的问题,相信你也想到了,安全元件上的软件被证明是安全的,但是微控制器并不是一个安全的芯片,并且,如我们下面的教程所示,微控制器的固件可以被黑客篡改。
这里存在的问题是:要实现Ledger的安全保证,必须把信任链锚定在安全元件中,这意味着安全元件必须要验证不安全的微控制器上的固件。
如何篡改硬件?
虽然本文将着重介绍软件篡改,但是需要注意的是,如果没有软件漏洞,你仍然可以通过篡改硬件来入侵设备。
注意到这点很重要,为了使这些比特币硬件钱包安全,必须完整地验证设备硬件。
由于Ledger的比特币硬件钱包及包装都没有做防开封措施,因此黑客可以轻而易举地篡改设备,我不禁要再重复一遍:如果你不验证物理硬件,那么你的资产处于危险之中!
当有人未经你授权使用了你的设备时,一定要再次验证,否则你很容易受到邪恶女佣攻击。
Ledger提供了验证物理硬件的说明,但我注意到其中的两个问题。
- 网上图片的清晰度各不相同,Ledger需要提供能清晰显示每个组件的高分辨率图像。
- 设备的背面完全没有显示。
验证设备的背面是十分重要的,因为这是微控制器的JTAG头(一个调试接口)所在的地方。
即使解决了这两个问题,我认为如果黑客使用了一个具有额外内存但引脚数与STM32F042K6相同的微控制器假冒STM32F042K6,还是可以黑掉比特币硬件钱包。
这里我们论证了很多硬件上黑掉比特币硬件钱包的可能性,现在我们回到软件破解比特币硬件钱包上来。
Ledger的防范措施——验证微控制器固件
假如你已经仔细检查了硬件,并且确实没有更改,如果攻击者只是修改微控制器的固件会发生什么?
Ledger考虑到了这种攻击,为了防止出现这种情况,微控制器固件要经安全元件验证。
但事实证明,在非安全的微控制器上验证固件并不是那么简单,安全元件只是一个智能卡,这意味着与微控制器通信的唯一方法就是通过一个低吞吐量的UART,又不能直接访问微控制器上的RAM或内存,安全元件如何验证其固件?
Ledger的解决方案是:安全元件要求微控制器传递其内存的全部内容,如下所述。
安全元件验证过程
乍一看这似乎有问题,原则上,我们是在要求一个(很可能已经被篡改了的)微控制器证明自己正在运行Ledger的官方固件。但是,如果微控制器已经被篡改了,它依然可以发送Ledger的官方固件,怎样才能确保它发送的是自己现在正在运行的固件呢?这是Ledger面临的挑战。
Ledger采用的解决方案基于这样一个事实,即微控制器的内存大小是有限的。如果要让微控制器运行恶意固件,黑客还需要存储一份Ledger官方固件以便于应对安全元件的检查。因此,Ledger的解决方案是限制内存大小,是这种攻击行为变得困难。
具体而言,通过验证整个内存(并用随机数据填充空白区域),Ledger试图修复这种存有恶意固件但是能通过安全元件检查的漏洞。
这是一个很了不起的想法,也许想法可能会实现。但是,我完全不同意这个解决方案。
我的独家攻击方式
虽然可以采用一些直接的方法攻击这种架构,例如可以通过电脑的USB端口为比特币钱包软件植入恶意代码,但尝试独立开发一种攻击方式(比如使用供应链攻击来攻破比特币硬件钱包)显得更有趣些。
我最开始使用的方法是压缩代码,综合考虑执行时间,内存使用量和代码大小,使用诸如DEFLATE或LZMA之类的压缩算法是行不通的。因为如果用户花了20秒才启动了钱包,那么他一定会考虑是否发生了异常。
更不用说,虽然压缩整个内存的结果令人满意,微控制器的结果也让我欣喜若狂,但我不想更换已经存在内存中的微控制器的引导程序,因为有两种方法都可以用来在比特币硬件钱包中安装新固件。
- 使用JTAG,这个调试接口是为嵌入式固件开发人员上传新固件设计的。
- 使用引导程序,通常Ledger的用户都是用这种方法来升级固件,你可以在Github中找到Ledger为此设计的Python工具。
我使用了第二种方法,因为我不喜欢焊接东西。如果我在更换引导程序时出错,这个方法就会失效,除非使用JTAG接口修复,否则设备也会变砖。
因此,更换引导程序并不是最佳选择,我们需要排除压缩这个选项。
但还有另一种方法。在编译C程序时,工具链(编译程序的软件套件)会执行许多魔术一样的操作,从而保证编译的成功。例如,许多处理器并没有关于大数除法的指令,编译器通过插入除法操作的软件来解决这个问题。另一个例子是关于对函数中定义的变量声明初始值。当函数被调用时,编译器会在最开始插入额外的代码将该初始值复制到堆栈中。
编译器为执行这些任务而插入的额外函数被称为“编译器内联函数”。由于微控制器同时具有引导程序和固件,并且他们是完全独立的程序,所以这些内联函数将在内存中出现两次(每个程序中只出现一次)。
这样做的结果就是我们可以插入我们的恶意代码来取代编译器内联函数例程的一个冗余副本(特别是,固件中的副本),因此我们保存了引导程序的完整副本。
由于引导程序中的固有内容与固件中的内容完全相同,因此当安全元件向微控制器询问其内存内容时,我们可以通过剔除恶意代码并从引导程序中发送该段代码,从而“拼凑”出正确的映像,当固件需要使用固有内容时,我们可以跳转到引导程序中的固有内容。
在从源代码构建引导程序和固件后,你可以通过这个命令查询到目标。
代码语言:javascript复制nm -S --size-sort -t d bin/token | grep -i " t "
这里命令包含了一些在引导程序和固件中相同的有趣符号,不要惊讶,这三个符号都是编译器的内联函数。
代码语言:javascript复制134228637 00000124 T memcpy
134228761 00000140 T memset
134228357 00000266 T __udivsi3
要使用我们隐藏起来的恶意代码,我们必须挂钩(hook,可以理解为是一种通过更改程序的数据结构或代码结构从而改变程序运行路线的一种方法)到其他函数。我们通过在我们想要定位的函数中插入有我们恶意代码的分支来实现这一点。我们需要挂钩到发送内存内容给安全元件检查的函数,从而让它发送正确的引导函数而不是我们的恶意代码。
我也会选择挂钩到屏幕显示函数,从而我们可以实现各种有趣且令人兴奋的功能。我稍后将要讲述这个漏洞。
用这两个挂钩和__udivsi3做为我们的攻击向量(attack vector,指的是黑客用来攻击计算机或者网络服务器的一种手段),我们使用的漏洞有点像这样:
作者使用的漏洞示意图
这种方法可以释放258个字节的有效载荷,那么即使我们将memcpy函数和memset函数放入载荷中,我们也必须对代码占用的空间进行优化。
执行攻击
我们的有效载荷需要两个部分:
1.修改发送给安全元件内存内容的代码,用以欺骗验证过程。
2.对键盘生成器和密钥生成后门的攻击,对我而言,我更偏向于添加后门。
我们利用的漏洞并不能骗过安全元件,那么我们该如何添加后门呢?
Ledger的安全元件固件含有一个管理设置的用户界面程序,供配置信息的进程(生成恢复种子的地方)调用。
如果能修改这个用户界面,我们就可以在配置信息的进程中篡改恢复种子,这种操作十分简单,因为用户界面是开源的,并且在Ledger的架构设计中,你是可以修改它的。
在正常情况下,设备会显示一个“用户界面不是官方的”的警告,细心的用户会注意到这个警告。
但回想一下,我刚才说过我们还可以篡改显示器控制函数,这样我们就可以轻而易举地隐藏这个警告。
为了更好地讲解原理,我并不会介绍黑客常用的一些手段,比如控制设备产生一个看起来是随机的,但完全可预测的恢复种子。我会讲一些更具体的操作。
如果你熟悉C语言,你会注意到我把随机数生成函数换成了一个信息熵为0的随机数生成函数。
正如你在开始视频中看到的那样,它会生成一个恢复种子,其中前23个字被丢弃(最后一个字不同,因为它是校验和)。
由于私钥来源于恢复种子,那么只要你控制了恢复种子,你就掌控了比特币硬件钱包所生成的所有比特币账户。
如果我们把上述内容放在一起,我们会得到下面这个我认为很简洁的攻击。
作者使用的攻击方法示意图
当然,由于安全元件误以为微控制器正在运行官方固件,检查是通过的。正如我之前提到的,这个过程完全不需要篡改硬件。
由于黑客控制了可信任的显示和按钮,从比特币硬件钱包中发现并删除我们的恶意代码十分困难。
Ledger该如何修复漏洞
Ledger设计的体系架构带来很大的问题,只有改变体系架构,才能修复这个漏洞。
Ledger试图采用多种阻断措施来阻止黑客使用此漏洞攻击。
首先,Ledger优化并重新设计了微控制器的固件。具体来说,新的固件调用引导程序中的函数,而不是之前的直接复制,虽然这样可以防范特定的攻击方式,但据我所知,这个改动并不是天衣无缝的,还有很多攻击方法可以攻破微控制器。
其次,在安全固件要求检查微控制器的内存内容时,会为其定时。这是为了防止恶意代码使用压缩算法而设计的。它还可以防止计算机通过USB接口提供代码。
但是,值得注意的是,安全固件运行的频率为28MHz,而它要监控的对象——微控制器运行速度高达80MHz,这引发一个问题,一个较慢的芯片是否能对一个较快的芯片准确计时,以防止它执行额外的代码,尤其是考虑到他们之间仅靠慢速的UART通信。
Ledger拒绝向我提供更新的固件,所以我不能去验证这些阻断措施如何解决问题,但是这里有一个很重要的问题。
是否真的可能通过使用计时策略和“难以进行压缩”的固件组合来确保模型中的安全性呢?
小插曲:我与Ledger的互动
在计划披露此漏洞之前,我曾和ledger的首席执行官进行过一些交流。你可以在这里找到我们交流的归档副本。
在这些评论中,我和Ledger的CEO争辩这些攻击是否至关重要,一些来自Ledger的评论十分主观,也有一些很客观,下面我将讨论一些评论。
我第一个想谈到的评论是,使用这个漏洞需要满足一系列苛刻的看似不可能的条件。
Saleem(作者本人)报告的漏洞需要在设置恢复种子前物理访问比特币硬件钱包,安装一个篡改后的微控制器固件,还需要在用户的计算机上安装恶意软件并由用户确认交易。
我很困惑这条评论来自哪里?从后来与Ledger的联系中,我被告知,当他们在Reddit上发表这些评论时,CEO对漏洞根本不知情。
正如我在文章开头中所说的那样,有三种方法可以利用这个漏洞,没有哪种方法需要满足那些极其苛刻的条件。
我之前提到的恶意软件攻击很好的引出了我和Ledger的CEO交流的过程。
我们并没有把这个漏洞认定为“重要安全更新”,并且决定对他的观点不予理睬时,Saleem明显感到不安。
实际上,当你解决严重的安全问题时,你有以下两种选择:
- 对漏洞不做披露,直接发布安全性更新。
这是一种避免引起黑客关注的有效方法,尤其是Ledger现在面对的产品并没有开源的情况。
但这有个缺点,大多数用户不会去更新。就拿windows 10来说,有多少人千方百计地去关闭自动更新,更何况是更新比特币硬件钱包。
- 提醒用户安全性问题,并强制用户更新。
这通常用于开源软件,或者是当开发商发现严重漏洞已经危害到系统安全时。
然而,这样做也有缺点,因为开发商对漏洞的预警会引起黑客的关注。因此,用户必须立即更新与黑客争分夺秒以抢占“先机”。
而Ledger使用了并不稳妥的做法,它集合了这两种方法的缺点。Ledger把注意力集中在开发修复漏洞的固件安全性更新,但是他们并不提醒用户更新,用户也就失去了与黑客竞争的“先机”。
Ledger的做法给了黑客充足的时间来研究并利用漏洞,从而增加了用户被恶意攻击的风险。
我的担忧并不是多余的,我已经联系了多位独立的白帽,他们都从Ledger发布的固件更新说明中实行逆向工程,发现了这个漏洞。
附录:漏洞披露时间表
2017年11月11日:我正式向Ledger的CEO报告漏洞,然而Ledger方面并没有采纳我的报告。
2017年11月14日:我用代码实现了用篡改的微控制器固件和用户界面来实现供应链攻击,并将源码发给了Ledger的CEO。
2017年12月30日:通过篡改Ledger Nano S比特币硬件钱包的固件,我黑掉了Nano S。
2018年3月6日:Ledger发布Nano S的固件更新。
2018年3月20日:我正式发布本文,披露漏洞。
截至发文时,Ledger Blue的固件更新还没有发布。