关于OpenSSL“心脏出血”漏洞的分析

当我分析GnuTLS的漏洞的时候,我曾经说过,那不会是我们看到的最后一个TLS栈上的严重bug。然而我没想到这次OpenSSL的bug会如此严重。

[[111228]]

OpenSSL“心脏出血”漏洞是一个非常严重的问题。这个漏洞使攻击者能够从内存中读取最多64 KB的数据。一些安全研究员表示:

无需任何特权信息或身份验证,我们就可以从我们自己的(测试机上)偷来X.509证书的私钥、用户名与密码、聊天工具的消息、电子邮件以及重要的商业文档和通信等数据。

这一切是如何发生的呢?让我们一起从代码中一探究竟吧。

0x01 Bug

请看ssl/dl_both.c,漏洞的补丁从这行语句开始:

  1. int              
  2. dtls1_process_heartbeat(SSL *s)  
  3.     {            
  4.     unsigned char *p = &s->s3->rrec.data[0], *pl;  
  5.     unsigned short hbtype;  
  6.     unsigned int payload;  
  7.     unsigned int padding = 16; /* Use minimum padding */ 

一上来我们就拿到了一个指向一条SSLv3记录中数据的指针。结构体SSL3_RECORD的定义如下(译者注:结构体SSL3_RECORD不是SSLv3记录的实际存储格式。一条SSLv3记录所遵循的存储格式请参见下文分析):

  1. typedef struct ssl3_record_st  
  2.     {  
  3.         int type;               /* type of record */ 
  4.         unsigned int length;    /* How many bytes available */ 
  5.         unsigned int off;       /* read/write offset into 'buf' */ 
  6.         unsigned char *data;    /* pointer to the record data */ 
  7.         unsigned char *input;   /* where the decode bytes are */ 
  8.         unsigned char *comp;    /* only used with decompression - malloc()ed */ 
  9.         unsigned long epoch;    /* epoch number, needed by DTLS1 */ 
  10.         unsigned char seq_num[8]; /* sequence number, needed by DTLS1 */ 
  11.     } SSL3_RECORD; 

每条SSLv3记录中包含一个类型域(type)、一个长度域(length)和一个指向记录数据的指针(data)。我们回头去看dtls1_process_heartbeat:

  1. /* Read type and payload length first */ 
  2. hbtype = *p++;  
  3. n2s(p, payload);  
  4. pl = p; 

SSLv3记录的第一个字节标明了心跳包的类型。宏n2s从指针p指向的数组中取出前两个字节,并把它们存入变量payload中——这实际上是心跳包载荷的长度域(length)。注意程序并没有检查这条SSLv3记录的实际长度。变量pl则指向由访问者提供的心跳包数据。

这个函数的后面进行了以下工作:

  1. unsigned char *buffer, *bp;  
  2. int r;  
  3.    
  4. /* Allocate memory for the response, size is 1 byte  
  5.  * message type, plus 2 bytes payload length, plus  
  6.  * payload, plus padding  
  7.  */ 
  8. buffer = OPENSSL_malloc(1 + 2 + payload + padding);  
  9. bp = buffer; 

所以程序将分配一段由访问者指定大小的内存区域,这段内存区域最大为 (65535 + 1 + 2 + 16) 个字节。变量bp是用来访问这段内存区域的指针。

  1. /* Enter response type, length and copy payload */ 
  2. *bp++ = TLS1_HB_RESPONSE;  
  3. s2n(payload, bp);  
  4. memcpy(bp, pl, payload); 

宏s2n与宏n2s干的事情正好相反:s2n读入一个16 bit长的值,然后将它存成双字节值,所以s2n会将与请求的心跳包载荷长度相同的长度值存入变量payload。然后程序从pl处开始复制payload个字节到新分配的bp数组中——pl指向了用户提供的心跳包数据。最后,程序将所有数据发回给用户。那么Bug在哪里呢?

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

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

很明显,SSLv3记录附近有不少东西。

说实话,我对发现了OpenSSL“心脏出血”漏洞的那些人的声明感到吃惊。当我听到他们的声明时,我认为64 KB数据根本不足以推算出像私钥一类的数据。至少在x86上,堆是向高地址增长的,所以我认为对指针pl的读取只能读到新分配的内存区域,例如指针bp指向的区域。存储私钥和其它信息的内存区域的分配早于对指针pl指向的内存区域的分配,所以攻击者是无法读到那些敏感数据的。当然,考虑到现代malloc的各种神奇实现,我的推断并不总是成立的。

当然,你也没办法读取其它进程的数据,所以“重要的商业文档”必须位于当前进程的内存区域中、小于64 KB,并且刚好位于指针pl指向的内存块附近。

研究者声称他们成功恢复了密钥,我希望能看到PoC。如果你找到了PoC,请联系我。

0x01b 漏洞修补

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

  1. /* Read type and payload length first */ 
  2. if (1 + 2 + 16 > s->s3->rrec.length)  
  3.     return 0; /* silently discard */ 
  4. hbtype = *p++;  
  5. n2s(p, payload);  
  6. if (1 + 2 + payload + 16 > s->s3->rrec.length)  
  7.     return 0; /* silently discard per RFC 6520 sec. 4 */ 
  8. pl = p; 

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

0x02 前车之鉴

我们能从这个漏洞中学到什么呢?

我是C的粉丝。这是我最早接触的编程语言,也是我在工作中使用的第一门得心应手的语言。但是和之前相比,现在我更清楚地看到了C语言的局限性。

从GnuTLS漏洞和这个漏洞出发,我认为我们应当做到下面三条:

花钱请人对像OpenSSL这样的关键安全基础设施进行安全审计;

为这些库写大量的单元测试和综合测试;

开始在更安全的语言中编写替代品。

考虑到使用C语言进行安全编程的困难性,我不认为还有什么其他的解决方案。我会试着做这些,你呢?

作者简介:Sean是一位关于如何把事儿干好的软件工程师。现在他在Squadron工作。Squadron是一个专为SaaS应用程序准备的配置与发布管理工具。

测试版本的结果以及检测工具:

OpenSSL 1.0.1 through 1.0.1f (inclusive) are vulnerable

OpenSSL 1.0.1g is NOT vulnerable

OpenSSL 1.0.0 branch is NOT vulnerable

OpenSSL 0.9.8 branch is NOT vulnerable

http://filippo.io/Heartbleed/

原文地址:http://blog.existentialize.com/diagnosis-of-the-openssl-heartbleed-bug.html

文章来源网络,作者:管理,如若转载,请注明出处:https://shuyeidc.com/wp/148431.html<

(0)
管理的头像管理
上一篇2025-03-12 03:51
下一篇 2025-03-12 03:52

相关推荐

  • jsp空间购买和交换数据空间怎么买,有哪些注意事项?

    购买JSP空间时,是否考虑过数据交换空间的性能?简米科技(2003年始创,23年行业沉淀)与酷番云(工信部一类增值电信全牌照)这类持牌自营机房的服务商,能确保数据交换的高效稳定,是值得优先选择的合作伙伴,为什么JSP空间需要搭配独立的数据交换空间从JSP应用特性看数据交换需求JSP基于Java技术,常用于企业级……

    2026-08-11
    0
  • 建网站用香港空间效果怎么样,香港空间稳定吗?

    建网站用香港空间,对于创建网站资产来说,核心价值在于免备案和全球带宽优势,尤其适合外贸、跨境电商和需要快速启动的项目,但你必须权衡国内访问延迟,并选择有资质的服务商以保证资产安全,香港空间的核心优势与适用边界免备案:节省时间就是节省成本国内服务器需要备案,通常需要10到20天,香港空间无需备案,域名解析后即可上……

    2026-08-11
    0
  • Java连接云数据库的方法是什么,如何操作

    Java连接云数据库的核心在于通过JDBC驱动,结合云服务商提供的连接地址、端口、数据库名及认证信息,配置安全策略(如SSL、IP白名单),即可实现稳定高效的远程数据库访问,基础准备:JDBC驱动与依赖管理连接云数据库前,需要确保开发环境具备对应的JDBC驱动,以最常见的MySQL为例,你需要引入mysql-c……

    2026-08-11
    0
  • 建网站公安联网备案必须使用数据码吗,备案流程是什么

    网站备案包括ICP备案和公安联网备案,两者缺一不可,公安联网备案必须使用服务商提供的数据码,选择持有合法资质的服务商是顺利通过备案的前提,为什么网站必须进行公安联网备案根据公安部《计算机信息网络国际联网安全保护管理办法》,网站开通后30日内必须到公安机关办理备案手续,未完成公安备案的网站,面临责令整改、关闭网站……

    2026-08-10
    0
  • 建一个企业网站大概需要多少钱?,怎么收费?

    建网站要多少钱,没有一个固定的数字,几百到几万都可能,但真正的“创建网站资产”绝不仅仅是初次投入的成本,而是基于长期稳定、合规和安全的持续性投入,其中核心取决于你选择了什么样的“地基”来承载你的业务,建站预算的构成与行业基准当你开始规划一个网站,最先面对的就是预算问题,一个常见的误区是只关注网站“看起来”的建造……

    2026-08-10
    0

发表回复

您的邮箱地址不会被公开。必填项已用 * 标注