您的位置  > 互联网

Bug请看ssl/.c,漏洞的补丁

请查看 ssl/.c。 该漏洞的补丁以这一行开头:

整数

吃(SSL*s)

char*p = &s->s3->rrec.data[0], *pl;

;

;

= 16; /* 使用 */

一旦我们起床,我们就会得到一个指向 SSLv3 记录中数据的指针。 该结构体的定义如下(译者注:该结构体并不是SSLv3记录的实际存储格式,SSLv3记录后面的存储格式请看下面的分析):

10

11

; /* 类型 */

;/* 有多少字节 */

; /* 读/写到 'buf' */

char*data;/* 转为数据*/

字符*输入; /* 字节所在的位置 */

char*comp;/* 仅与 - ()ed 一起使用 */

;/* 纪元 , 由 DTLS1 */

[8]; /* , 通过 DTLS1 */

};

每个SSLv3记录都包含一个类型字段(type)、一个长度字段()和一个指向记录数据的指针(data)。 我们回去吃饭吧:

/* 读取类型和第一个 */

=*p++;

n2s(p, );

pl = p;

SSLv3记录的第一个字节表示心跳包的类型。 宏n2s从指针p指向的数组中取出前两个字节并将它们存储在一个变量中——这实际上是心跳包有效负载的长度字段()。 请注意,程序不会检查此 SSLv3 记录的实际长度。 变量pl指向访客提供的心跳包数据。

该函数背后完成了以下工作:

字符*,*bp;

内部;

/* 对于 ,大小为 1 字节

* 类型,加2个字节,加

*, 加

*/

= (1 + 2 + + );

基点 = ;

因此,程序会分配访问者指定大小的内存区域。 该内存区域的最大大小为(65535 + 1 + 2 + 16)字节。 变量bp是用于访问该内存区域的指针。

/* 输入类型,然后复制 */

*bp++=;

s2n(, bp);

(bp, pl, );

宏 s2n 和宏 n2s 的作用恰恰相反:s2n 读取一个 16 位长值,然后将其存储为一个两字节值,因此 s2n 将在变量中存储与请求的心跳包有效负载长度相同的长度值。 然后程序将从pl开始的字节复制到新分配的bp数组中——pl指向用户提供的心跳包数据。 最后,程序将所有数据发送回用户。 那么bug在哪里呢?

0x01a 用户可以控制变量和pl

如果用户在心跳包中没有提供足够的数据,会出现什么问题? 例如,pl指向的数据实际上只有一个字节,那么这条SSLv3记录之后的数据——无论数据是什么——都会被复制出来。

很明显,距离 SSLv3 记录还有相当多的距离。

老实说,我对那些发现 漏洞的人的说法感到惊讶。 当我听到他们的公告时,我认为 64 KB 的数据根本不足以推断出私钥之类的东西。 至少在x86上,堆向更高的地址增长,所以我认为从指针pl读取只能读到新分配的内存区域,例如指针bp指向的区域。 存储私钥等信息的内存区域的分配早于指针pl指向的内存区域,因此攻击者无法读取那些敏感数据。 当然,考虑到现代魔法的各种实现方式,我的推论并不总是正确的。

当然,你无法读取其他进程的数据,所以“重要业务文档”必须位于当前进程的内存区域,小于64 KB,并且正好位于指针pl指向的内存块附近。

研究人员声称他们成功恢复了密钥,我希望看到一个 PoC。 如果您找到 PoC,请与我联系。

0x01b漏洞补丁

修复代码中最重要的部分如下:

/* 读取类型和第一个 */

if(1 + 2 + 16 > s->s3->rrec.)

; /* */

=*p++;

n2s(p, );

if(1 + 2 + + 16 > s->s3->rrec.)

; /* 根据 RFC 6520 秒。 4 */

pl = p;

这段代码做了两件事:首先,第一行语句丢弃长度为0的心跳包,然后第二步检查以确保心跳包足够长。 就是这么简单。