云服务器价格_云数据库_云主机【优惠】最新活动-搜集站云资讯

游戏服务器_数据库知识点_9元

小七 141 0

寻找主要嫌疑犯:心血如何泄露私钥

在CloudFlare发起"心血挑战"的几个小时内,真相就暴露了。Heartbleed不仅泄漏了私有会话信息(如cookies和SSL应该保护的其他数据),而且HTTPS web服务器的皇冠宝石也容易受到攻击:可以通过Heartbleed消息访问私有SSL密钥。

主要嫌疑犯

当我们启动这个挑战时,我们不确定是否可以访问私钥,但是已经开始了撤销和重新创建我们管理的所有SSL私钥的过程。当挑战在几个小时内被击败时,很明显,找到RSA私钥核心的质数是相当容易的。大多数获得质询服务器的私人SSL密钥的人都是通过搜索返回的结果来查找质数的。质数本身的测试非常简单(虽然很慢):找到一个数,看看它是否有除数。因为素数的长度(以位为单位)是已知的,所以只需要找到1024位的所有块,然后看看它们是否真的是质数。找到一个素数就足以破坏私有SSL密钥。我们想回答的问题是:"为什么在令人心痛的结果中很容易找到质数?"为了得到答案,我插入了一个易受攻击的OpenSSL(1.0.1f)版本,并开始搜索素数以及它们在内存中的最终位置。奇怪的是,OpenSSL似乎是为了清除不再使用的素数(和其他敏感值)的内存。怎么回事?但首先要绕道进入RSA算法,以及如何有效地实现它。RSA与蒙哥马利还原RSA密码方案的全部细节可以在这里读到,但是,简短的版本是选择两个大素数(几乎总是称为p和q)并对其保密。这两个数的乘积称为模数,通常称为N(N=pxq)。公开N是安全的(它是所谓的公钥的一部分),因为(数学家和计算机科学家)认为从N中计算p和q是困难的(也就是说,只要p和q非常大,因数N就很难)。因此,当浏览器连接到使用SSL的站点时,它会从站点获取公钥,站点将p和q保密。但是站点需要p和q来加密数据,因此它们通常(但不总是)保存在处理web站点的服务器的内存中。在Heartbleed攻击中,可以在从易受攻击的服务器返回的包含内存块的Heartbleed数据包中找到p或q之一。因为N是公共的,一旦有了p或q,另一个可以很容易地用N除以找到的素数。注意,在一次心血攻击中,一名研究人员使用了铜匠的攻击。这种攻击是一种复杂的数学攻击,这意味着如果你只找到一个质数的一部分,就有可能把N分解成p和q。请看这里的细节。在实际应用中,RSA所使用的数学运算速度相当慢,人们发明了各种各样的方案来加快它的速度。其中一个是OpenSSL使用的,称为Montgomery Reduction。在RSA的内部深处,必须执行的基本运算是模N的乘法运算。如果你不熟悉"模N"这个词,它只意味着"除以N取余数"。例如,这里是13×29模11(13×29除以11,取余数):13 x 29模数11=377模11=3(377/11=34余数3)对于计算机来说,这是一个非常昂贵的操作(在RSA中,它是反复执行的),因为它涉及乘法和除法(如果你记得在学校里的长除法,你就会记得它是多么的费力:与加法或减法相比,计算机发现它同样困难)。1985年,数学家彼得蒙哥马利(petermontgomery)指出,可以很快地执行"乘法模N",如下所示。在每个步骤中执行以下操作:左数乘以右数,加到一个临时变量(通常称为累加器);累加器除以10,小数舍弃;如果左边的数字中还有数字,那么把数字r加到累加器上,其中rx11加上当前累加器中的任何一个都可以被10整除。如果有一个数字,请转到下一个数字例如,13 x 29 mod 11可以这样计算:蓄能器087增加3 x 298除以1010加2,因为2 x 11+8=30(可被10整除)39增加1 x 293除以10答案是3,在累加器中。这里重要的是,只执行了"简单"的计算:用一个位数进行小的乘法,再除以10。在计算机实现中,所有这些都是用2除10的二进制数来完成的。除以2是非常非常容易在计算机上实现的。在OpenSSL的保护下为了理解在OpenSSL中如何使用素数,我将代码插入到输出关于OpenSSL分配的所有内存的信息,并突出显示用于素数的内存块。然后我用一个小程序处理这些信息,生成一张记忆图片。下面是OpenSSL在nginx1.5.13内部运行时使用的内存状态。绿色块是正在使用的内存,黑色区域是未使用的,两个红色条是构成RSA密钥一部分的两个素数p和q。图片的每一行是1024字节。图为总共约280KB的内存在使用中。素数存储在一个单独的位置(深入研究OpenSSL的源代码这是在ssl_rsa.c中的ssl_set_pkey函数中加载时素数的位置)。

开始

相比之下,NGINX/OpenSSL处理其第一个请求时发生了一些有趣的事情。第二个素数的副本已经出现了。OpenSSL现在使用了更多的内存,内存中有两条长长的红线(两个完整的素数)以及一些被部分覆盖的素数片段(这些片段容易受到铜匠的攻击)。

一个请求

再深入研究代码,就可以发现,这两个新素数是p和q的副本,它们是为bn峎mont.c.的蒙哥马利约化代码而制作的。这些素数片段是p和q在计算中使用的地方遗留下来的。在十个相同的请求之后,内存布局有了一些改变。素数的碎片已经被覆盖,但是蒙哥马利还原副本仍然存在。一些新的碎片出现了。

十个请求

在通过web服务器运行一个更真实的模拟负载后,内存增长了,大部分素数片段都被覆盖了,剩下的原始素数和蒙哥马利还原素数留在内存中。

加载

为了了解OpenSSL是如何复制素数的,这里有一个稍微不同的可视化。它以红色显示存储素数的所有内存(不管它后来是否被重写)。如您所见,OpenSSL正在其内存空间中复制素数。

加载覆盖

这就是令人痛心的地方:有两个素数永远不会移动的拷贝(它们装载的原始位置和Montgomery reduction副本的位置),OpenSSL内存中有许多prime的临时副本。OpenSSL修补程序通过应用以下补丁,可以清理OpenSSL的内存,使prime的副本不留在内存中:diff-ur openssl-1.0.1g/crypto/bn/bn_lib.c openssl-1.0.1g-sanitise/crypto/bn/bn_lib.c---openssl-1.0.1g/crypto/bn/bn_-lib.c 2014-03-17 09:14:20.000000000-0700+++openssl-1.0.1g-sanitise/crypto/bn/bn_lib.c 2014-04-19 07:57:53.489932751-0700@@-431,7+431,13@@{BN_gulong*a=BN_展开_内部(b,单词);如果(!a) 返回空值;-如果(b->d)OPENSSL_空闲(b->d);++如果(b->d!=空)+ {+OPENSSL_clean(b->d,b->dmax*sizeof(b->d[0]);+OPENSSL_免费(b->d);+ }+b->d=a;b->dmax=字;}这个补丁修复了一个问题,即bn_lib.c中的bn_expand2函数释放了可能包含质数的内存,而不首先擦除它。该补丁添加了一个对OPENSSL_cleane函数的调用,该函数在释放数字之前将其安全地从内存中删除。修补程序确保内存被清理干净。它于4月19日被发送到OpenSSL团队,由rubinxu独立发现。这个特殊的函数是素数留在空闲内存中的原因。每当OpenSSL需要调整存储在其特殊BIGNUM结构中的一个数字时,它将释放现在太小的BIGNUM而不清除内存。仅仅这一点还不足以阻止心血获得质数,因为内存中还有其他副本。在测试中,我发现蒙哥马利还原素数特别容易使用心血信息提取。为了防止它们被创建,可以通过删除eng_rsax.c中的RSA_FLAG_CACHE_PRIVATE来禁用Montgomery参数的缓存(RSA_eay.c中也有类似的标志)。蒙哥马利代码也不能清除它释放的内存。下面的补丁纠正了这个问题。diff-ur openssl-1.0.1g/crypto/bn/bn_mont.c openssl-1.0.1g-sanitise/crypto/bn/bn_mont.c---openssl-1.0.1g/crypto/bn/bn_mont.c 2014-03-17 09:14:20.000000000-0700+++openssl-1.0.1g-sanitise/crypto/bn/bn_mont.c 2014-04-24 17:57:31.44531646-0700@@-345,9+345,9@@if(mont==NULL)返回;-BN_免费(&(mont->RR));-BN_免费(&(mont->N));-BN_免费(&(mont->Ni));+BN_clear_免费(&(mont->RR));+