欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

解析OpenSSL程序概念及震驚業(yè)界的“心臟出血”漏洞

freebuf   發(fā)布時(shí)間:2015-11-10 10:42:34   作者:佚名   我要評(píng)論
這篇文章主要介紹了OpenSSL程序的概念及震驚業(yè)界的“心臟出血”漏洞,OpenSSL由于在銀行網(wǎng)站等多個(gè)重要方面的應(yīng)用使得heartbleed漏洞的影響出奇之大,需要的朋友可以參考下

OpenSSL的各種概念解析:

  公鑰/私鑰/簽名/驗(yàn)證簽名/加密/解密/非對(duì)稱(chēng)加密

  我們一般的加密是用一個(gè)密碼加密文件,然后解密也用同樣的密碼.這很好理解,這個(gè)是對(duì)稱(chēng)加密.而有些加密時(shí),加密用的一個(gè)密碼,而解密用另外一組密碼,這個(gè)叫非對(duì)稱(chēng)加密,意思就是加密解密的密碼不一樣.初次接觸的人恐怕無(wú)論如何都理解不了.其實(shí)這是數(shù)學(xué)上的一個(gè)素?cái)?shù)積求因子的原理的應(yīng)用,如果你一定要搞懂,百度有大把大把的資料可以看,其結(jié)果就是用這一組密鑰中的一個(gè)來(lái)加密數(shù)據(jù),可以用另一個(gè)解開(kāi).是的沒(méi)錯(cuò),公鑰和私鑰都可以用來(lái)加密數(shù)據(jù),相反用另一個(gè)解開(kāi),公鑰加密數(shù)據(jù),然后私鑰解密的情況被稱(chēng)為加密解密,私鑰加密數(shù)據(jù),公鑰解密一般被稱(chēng)為簽名和驗(yàn)證簽名.

  因?yàn)楣€加密的數(shù)據(jù)只有它相對(duì)應(yīng)的私鑰可以解開(kāi),所以你可以把公鑰給人和人,讓他加密他想要傳送給你的數(shù)據(jù),這個(gè)數(shù)據(jù)只有到了有私鑰的你這里,才可以解開(kāi)成有用的數(shù)據(jù),其他人就是得到了,也看懂內(nèi)容.同理,如果你用你的私鑰對(duì)數(shù)據(jù)進(jìn)行簽名,那這個(gè)數(shù)據(jù)就只有配對(duì)的公鑰可以解開(kāi),有這個(gè)私鑰的只有你,所以如果配對(duì)的公鑰解開(kāi)了數(shù)據(jù),就說(shuō)明這數(shù)據(jù)是你發(fā)的,相反,則不是.這個(gè)被稱(chēng)為簽名.

  實(shí)際應(yīng)用中,一般都是和對(duì)方交換公鑰,然后你要發(fā)給對(duì)方的數(shù)據(jù),用他的公鑰加密,他得到后用他的私鑰解密,他要發(fā)給你的數(shù)據(jù),用你的公鑰加密,你得到后用你的私鑰解密,這樣最大程度保證了安全性.

  RSA/DSA/SHA/MD5

  非對(duì)稱(chēng)加密的算法有很多,比較著名的有RSA/DSA ,不同的是RSA可以用于加/解密,也可以用于簽名驗(yàn)簽,DSA則只能用于簽名.至于SHA則是一種和md5相同的算法,它不是用于加密解密或者簽名的,它被稱(chēng)為摘要算法.就是通過(guò)一種算法,依據(jù)數(shù)據(jù)內(nèi)容生成一種固定長(zhǎng)度的摘要,這串摘要值與原數(shù)據(jù)存在對(duì)應(yīng)關(guān)系,就是原數(shù)據(jù)會(huì)生成這個(gè)摘要,但是,這個(gè)摘要是不能還原成原數(shù)據(jù)的,嗯....,正常情況下是這樣的,這個(gè)算法起的作用就是,如果你把原數(shù)據(jù)修改一點(diǎn)點(diǎn),那么生成的摘要都會(huì)不同,傳輸過(guò)程中把原數(shù)據(jù)給你再給你一個(gè)摘要,你把得到的原數(shù)據(jù)同樣做一次摘要算法,與給你的摘要相比較就可以知道這個(gè)數(shù)據(jù)有沒(méi)有在傳輸過(guò)程中被修改了.

  實(shí)際應(yīng)用過(guò)程中,因?yàn)樾枰用艿臄?shù)據(jù)可能會(huì)很大,進(jìn)行加密費(fèi)時(shí)費(fèi)力,所以一般都會(huì)把原數(shù)據(jù)先進(jìn)行摘要,然后對(duì)這個(gè)摘要值進(jìn)行加密,將原數(shù)據(jù)的明文和加密后的摘要值一起傳給你.這樣你解開(kāi)加密后的摘要值,再和你得到的數(shù)據(jù)進(jìn)行的摘要值對(duì)應(yīng)一下就可以知道數(shù)據(jù)有沒(méi)有被修改了,而且,因?yàn)樗借€只有你有,只有你能解密摘要值,所以別人就算把原數(shù)據(jù)做了修改,然后生成一個(gè)假的摘要給你也是不行的,你這邊用密鑰也根本解不開(kāi).

   CA/PEM/DER/X509/PKCS

  一般的公鑰不會(huì)用明文傳輸給別人的,正常情況下都會(huì)生成一個(gè)文件,這個(gè)文件就是公鑰文件,然后這個(gè)文件可以交給其他人用于加密,但是傳輸過(guò)程中如果有人惡意破壞,將你的公鑰換成了他的公鑰,然后得到公鑰的一方加密數(shù)據(jù),不是他就可以用他自己的密鑰解密看到數(shù)據(jù)了嗎,為了解決這個(gè)問(wèn)題,需要一個(gè)公證方來(lái)做這個(gè)事,任何人都可以找它來(lái)確認(rèn)公鑰是誰(shuí)發(fā)的.這就是CA,CA確認(rèn)公鑰的原理也很簡(jiǎn)單,它將它自己的公鑰發(fā)布給所有人,然后一個(gè)想要發(fā)布自己公鑰的人可以將自己的公鑰和一些身份信息發(fā)給CA,CA用自己的密鑰進(jìn)行加密,這里也可以稱(chēng)為簽名.然后這個(gè)包含了你的公鑰和你的信息的文件就可以稱(chēng)為證書(shū)文件了.這樣一來(lái)所有得到一些公鑰文件的人,通過(guò)CA的公鑰解密了文件,如果正常解密那么機(jī)密后里面的信息一定是真的,因?yàn)榧用芊街豢赡苁荂A,其他人沒(méi)它的密鑰啊.這樣你解開(kāi)公鑰文件,看看里面的信息就知道這個(gè)是不是那個(gè)你需要用來(lái)加密的公鑰了.

  實(shí)際應(yīng)用中,一般人都不會(huì)找CA去簽名,因?yàn)槟鞘鞘斟X(qián)的,所以可以自己做一個(gè)自簽名的證書(shū)文件,就是自己生成一對(duì)密鑰,然后再用自己生成的另外一對(duì)密鑰對(duì)這對(duì)密鑰進(jìn)行簽名,這個(gè)只用于真正需要簽名證書(shū)的人,普通的加密解密數(shù)據(jù),直接用公鑰和私鑰來(lái)做就可以了.

  密鑰文件的格式用OpenSSL生成的就只有PEM和DER兩種格式,PEM的是將密鑰用base64編碼表示出來(lái)的,直接打開(kāi)你能看到一串的英文字母,DER格式是二進(jìn)制的密鑰文件,直接打開(kāi),你可以看到........你什么也看不懂!.X509是通用的證書(shū)文件格式定義.pkcs的一系列標(biāo)準(zhǔn)是指定的存放密鑰的文件標(biāo)準(zhǔn),你只要知道PEM DER X509 PKCS這幾種格式是可以互相轉(zhuǎn)化的.


心臟出血的OpenSSL
去年,OpenSSL爆出史上最嚴(yán)重的安全漏洞,此漏洞在黑客社區(qū)中被命名為“心臟出血”漏洞。360網(wǎng)站衛(wèi)士安全團(tuán)隊(duì)對(duì)該漏洞分析發(fā)現(xiàn),該漏洞不僅是涉及到https開(kāi)頭的網(wǎng)址,還包含間接使用了OpenSSL代碼的產(chǎn)品和服務(wù),比如,VPN、郵件系統(tǒng)、FTP工具等產(chǎn)品和服務(wù),甚至可能會(huì)涉及到其他一些安全設(shè)施的源代碼。

受影響版本

OpenSSL1.0.1、1.0.1a 、1.0.1b 、1.0.1c 、1.0.1d 、1.0.1e、1.0.1f、Beta 1 of OpenSSL 1.0.2等版本。

漏洞描述

OpenSSL在實(shí)現(xiàn)TLS和DTLS的心跳處理邏輯時(shí),存在編碼缺陷。OpenSSL的心跳處理邏輯沒(méi)有檢測(cè)心跳包中的長(zhǎng)度字段是否和后續(xù)的數(shù)據(jù)字段相符合,攻擊者可以利用這點(diǎn),構(gòu)造異常的數(shù)據(jù)包,來(lái)獲取心跳數(shù)據(jù)所在的內(nèi)存區(qū)域的后續(xù)數(shù)據(jù)。這些數(shù)據(jù)中可能包含了證書(shū)私鑰、用戶(hù)名、用戶(hù)密碼、用戶(hù)郵箱等敏感信息。該漏洞允許攻擊者,從內(nèi)存中讀取多達(dá)64KB的數(shù)據(jù)。

前幾日的漏洞分析文章主要聚焦在開(kāi)啟HTTPS的網(wǎng)站上,普通網(wǎng)民可能認(rèn)為只有網(wǎng)站自身業(yè)務(wù)會(huì)受到這個(gè)漏洞的影響。從360網(wǎng)站衛(wèi)士Openssl心血漏洞在線(xiàn)檢測(cè)平臺(tái)(wangzhan.#/heartbleed)的監(jiān)控?cái)?shù)據(jù)得知,心血漏洞的輻射范圍已經(jīng)從開(kāi)啟HTTPS的網(wǎng)站延伸到了VPN系統(tǒng)和郵件系統(tǒng),目前共發(fā)現(xiàn)國(guó)內(nèi)共有251個(gè)VPN系統(tǒng)和725個(gè)郵件系統(tǒng)同樣存在漏洞,其中不乏很多政府網(wǎng)站、重點(diǎn)高校和相關(guān)安全廠(chǎng)商。

為了更好讓大家明白,Openssl心血漏洞到底是哪個(gè)環(huán)節(jié)出了問(wèn)題,我們利用OpenSSL lib庫(kù)編寫(xiě)了一個(gè)不依賴(lài)與任何業(yè)務(wù)的獨(dú)立server程序,來(lái)一步步實(shí)際調(diào)試一遍代碼,以此證明不僅是https的網(wǎng)站有問(wèn)題,只要使用了存在該漏洞的OpenSSL libssl.so庫(kù)的應(yīng)用程序都存在安全漏洞!

測(cè)試環(huán)境

OS:CentOS release 6.4 (Final)
OpenSSL: Version 1.0.1f(沒(méi)有打開(kāi)OPENSSL_NO_HEARTBEATS編譯選項(xiàng))
編寫(xiě)Server程序:監(jiān)聽(tīng)端口9876
漏洞測(cè)試

利用網(wǎng)上python驗(yàn)證腳本(https://gist.github.com/RixTox/10222402)進(jìn)行測(cè)試

構(gòu)造異常heartbeat數(shù)據(jù)包,主要添加異常的length字段值。

測(cè)試一:
20151110105142784.png (240×220)

藍(lán)色的01表示的是心跳包的類(lèi)型為request方向。對(duì)應(yīng)源代碼中就是#define TLS1_HB_REQUEST 1

紅色的20 00表示的心跳請(qǐng)求包的length字段,占兩個(gè)字節(jié),對(duì)應(yīng)的長(zhǎng)度值為8192。

HeartBeat Response包


復(fù)制代碼
代碼如下:
[root@server test]# python ssltest.py 127.0.0.1 -p 9876 > 1</p> <p>Sending heartbeat request…</p> <p>… received message: type = 24, ver = 0302, length = 8211</p> <p>Received heartbeat response:</p> <p>WARNING: server returned more data than it should – server is vulnerable!</p> <p>Received heartbeat response:

20151110105207514.png (529×170)

藍(lán)色的02表示的是心跳包的類(lèi)型為response方向。

對(duì)應(yīng)源代碼中就是#define TLS1_HB_RESPONSE 2

紅色的20 00表示的心跳響應(yīng)包的length字段,占兩個(gè)字節(jié),對(duì)應(yīng)的長(zhǎng)度值為8192。和request包的length值一樣。

綠色部分就是非法獲取到的越界數(shù)據(jù)(可能包含用戶(hù)名、密碼、郵件、內(nèi)網(wǎng)IP等敏感信息)。

測(cè)試二:

在測(cè)試一的基礎(chǔ)上,修改了request心跳包的length字段的值,從20 00 修改到 30 00

HeartBeat Requst包
20151110105228092.png (215×177)

30 00兩個(gè)字節(jié)對(duì)應(yīng)的長(zhǎng)度為12288(8192+4096)

HeartBeat Response包

復(fù)制代碼
代碼如下:

[root@server test]# python ssltest.py 127.0.0.1 -p 9876 > 1</p> <p>Sending heartbeat request…</p> <p>… received message: type = 24, ver = 0302, length = 12307</p> <p>Received heartbeat response:</p> <p>WARNING: server returned more data than it should – server is vulnerable!</p> <p>Received heartbeat response:</p> <p>0000: 02 30 00 D8 03 02 53 43 5B 90 9D 9B 72 0B BC 0C .0….SC[...r...</p> <p>0010: BC 2B 92 A8 48 97 CF BD 39 04 CC 16 0A 85 03 90 .+..H...9.......</p> <p>0020: 9F 77 04 33 D4 DE 00 00 66 C0 14 C0 0A C0 22 C0 .w.3....f.....".</p> <p>0030: 21 00 39 00 38 00 88 00 87 C0 0F C0 05 00 35 00 !.9.8.........5.

兩個(gè)測(cè)試用例中,response的length長(zhǎng)度值總是比request的長(zhǎng)度多出來(lái)了19個(gè)byte,為什么?

因?yàn)?,TLS和DTLS在處理類(lèi)型為T(mén)LS1_HB_REQUEST的心跳請(qǐng)求包邏輯中,在從堆空間上申請(qǐng)內(nèi)存大小時(shí),有4部分決定type+length+request的數(shù)據(jù)長(zhǎng)度+pad,其中type,length,pad字段分為占1byte,2byte,16byte,所以response的數(shù)據(jù)總是比request的多出來(lái)19byte。

源碼分析

概要說(shuō)明

該漏洞主要是內(nèi)存泄露問(wèn)題,而根本上是因?yàn)镺penSSL在處理心跳請(qǐng)求包時(shí),沒(méi)有對(duì)length字段(占2byte,可以標(biāo)識(shí)的數(shù)據(jù)長(zhǎng)度為64KB)和后續(xù)的data字段做合規(guī)檢測(cè)。生成心跳響應(yīng)包時(shí),直接用了length對(duì)應(yīng)的長(zhǎng)度,從堆空間申請(qǐng)了內(nèi)存,既便是真正的請(qǐng)求data數(shù)據(jù)遠(yuǎn)遠(yuǎn)小于length標(biāo)識(shí)的長(zhǎng)度。

相關(guān)解析源碼說(shuō)明

存在該漏洞的源文件有兩個(gè)ssl/d1_both.c和ssl/t1_lib.c。

心跳處理邏輯分別是dtls1_process_heartbeat和tls1_process_heartbeat兩個(gè)函數(shù)。

dtls1_process_heartbeat函數(shù)處理邏輯:

Step1.獲取心跳請(qǐng)求包對(duì)應(yīng)的SSLv3記錄中數(shù)據(jù)指針字段,指向request的請(qǐng)求數(shù)據(jù)部分。

復(fù)制代碼
代碼如下:

unsigned char *p = &s->s3->rrec.data[0];

record記錄的數(shù)據(jù)格式應(yīng)該包含了三個(gè)字段:type, length, data;分別占1byte,2byte,length的實(shí)際值。

Step2.

復(fù)制代碼
代碼如下:

/* Read type and payload length first */
hbtype = *p++;
n2s(p, payload);
pl = p;

做了兩件事,獲取了type類(lèi)型以及l(fā)ength字段的值(存放到payload中),然后將pl指向真正的data數(shù)據(jù)。

Step3.

復(fù)制代碼
代碼如下:

/* 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;

悲劇開(kāi)始上演了。沒(méi)有判斷請(qǐng)求記錄中的真正數(shù)據(jù)長(zhǎng)度,直接用length字段的值來(lái)申請(qǐng)空間。對(duì)應(yīng)于測(cè)試一中的異常數(shù)據(jù)包的話(huà),buffer申請(qǐng)的內(nèi)存大小就是8211byte。但是實(shí)際應(yīng)該申請(qǐng)的大小僅僅就幾個(gè)字節(jié)。

Step4.

復(fù)制代碼
代碼如下:

/* Enter response type, length and copy payload */
*bp++ = TLS1_HB_RESPONSE;
s2n(payload, bp);
memcpy(bp, pl, payload);
bp += payload;

悲劇形成了。填充響應(yīng)記錄,第一個(gè)字節(jié)填充類(lèi)型,第二、三個(gè)字節(jié)填充request記錄中l(wèi)ength的值,緊接著,將request的data填充為響應(yīng)的data數(shù)據(jù)。異常情況下,payload對(duì)應(yīng)的長(zhǎng)度遠(yuǎn)遠(yuǎn)大于真正應(yīng)該使用的合法的data數(shù)據(jù)長(zhǎng)度,這樣,就導(dǎo)致了非法越界訪(fǎng)問(wèn)相鄰內(nèi)存空間的數(shù)據(jù)。

tls1_process_heartbeat函數(shù)的處理邏輯和dtls1_process_heartbeat一樣,此處就不再做詳細(xì)分析了。

附:ssl_server.c

編譯方式(請(qǐng)根據(jù)實(shí)際環(huán)境自行修改相關(guān)路徑)


復(fù)制代碼
代碼如下:
gcc -g -o ssl_server ssl_server.c -I/root/openssl_101f_prex/include/ -L/root/openssl_101f_prex/lib/ -lssl

該代碼是文中用于調(diào)試存在漏洞的libssl.so庫(kù)的server端,供對(duì)該漏洞感興趣的安全研究人員、安全愛(ài)好者們自行后續(xù)調(diào)試。希望這段獨(dú)立的代碼能讓大家意識(shí)到這個(gè)漏洞持續(xù)的高等級(jí)威脅:截至目前,心血漏洞僅僅是剛開(kāi)始出血,避免這個(gè)漏洞引起互聯(lián)網(wǎng)業(yè)務(wù)大血崩此刻就要開(kāi)始更多的行動(dòng)了!

C/C++ Code復(fù)制內(nèi)容到剪貼板
  1. #include <stdio.h>   
  2. #include <stdlib.h>   
  3. #include <string.h>   
  4. #include <netinet/in.h>   
  5. #include <sys/types.h>   
  6. #include <sys/socket.h>   
  7. #include “openssl/bio.h”   
  8. #include “openssl/rsa.h”   
  9. #include “openssl/crypto.h”   
  10. #include “openssl/x509.h”   
  11. #include “openssl/pem.h”   
  12. #include “openssl/ssl.h”   
  13. #include “openssl/err.h”   
  14. #define server_cert “./server.crt”   
  15. #define server_key “./server.key”   
  16. #define ca_cert “./ca.crt”   
  17. #define PORT 9876   
  18. #define CHK_NULL(x) if ((x)==NULL) exit (1)   
  19. #define CHK_ERR(err,s) if ((err)==-1) { perror(s); exit(1); }   
  20. #define CHK_SSL(err) if ((err)==-1) { ERR_print_errors_fp(stderr); exit(2); }   
  21.   
  22.   
  23. int main ()   
  24. {   
  25. int err;   
  26. int listen_sd = -1;   
  27. int sd = -1;   
  28. struct sockaddr_in sa_serv;   
  29. struct sockaddr_in sa_cli;   
  30. int client_len;   
  31. SSL_CTX* ctx = NULL;   
  32. SSL* ssl = NULL;   
  33. X509* client_cert = NULL;   
  34. char* str = NULL;   
  35. char buf [4096];   
  36. SSL_METHOD *meth = NULL;   
  37.   
  38. SSL_library_init();   
  39. SSL_load_error_strings();   
  40. ERR_load_BIO_strings();   
  41. OpenSSL_add_all_algorithms();   
  42. meth = (SSL_METHOD *)SSLv23_server_method();   
  43. ctx = SSL_CTX_new(meth);   
  44. if (NULL == ctx) {   
  45. goto out;   
  46. }   
  47. //SSL_CTX_set_verify(ctx,SSL_VERIFY_PEER,NULL);   
  48. //SSL_CTX_load_verify_locations(ctx,ca_cert,NULL);   
  49. if (SSL_CTX_use_certificate_file(ctx, server_cert, SSL_FILETYPE_PEM) <= 0) {   
  50. goto out;   
  51. }   
  52. if (SSL_CTX_use_PrivateKey_file(ctx, server_key, SSL_FILETYPE_PEM) <= 0) {   
  53. goto out;   
  54. }   
  55. if (!SSL_CTX_check_private_key(ctx)) {   
  56. printf(“Private key does not match the certificate public key\n”);   
  57. goto out;   
  58. }   
  59. listen_sd = socket(AF_INET, SOCK_STREAM, 0);   
  60. if (-1 == listen_sd) {   
  61. goto out;   
  62. }   
  63. memset (&sa_serv, ‘\0′, sizeof(sa_serv));   
  64. sa_serv.sin_family = AF_INET;   
  65. sa_serv.sin_addr.s_addr = INADDR_ANY;   
  66. sa_serv.sin_port = htons(PORT);   
  67. err = bind(listen_sd, (struct sockaddr*) &sa_serv, sizeof(sa_serv));   
  68. if (-1 == err) {   
  69. goto out;   
  70. }   
  71. err = listen(listen_sd, 5);   
  72. if (-1 == err) {   
  73. goto out;   
  74. }   
  75. client_len = sizeof(sa_cli);   
  76. sd = accept(listen_sd, (struct sockaddr*)&sa_cli, &client_len);   
  77. if (-1 == err) {   
  78. goto out;   
  79. }   
  80. printf (“Connection from %d, port %d\n”,sa_cli.sin_addr.s_addr, sa_cli.sin_port);   
  81. ssl = SSL_new(ctx);   
  82. if (NULL == ssl) {   
  83. goto out;   
  84. }   
  85. SSL_set_fd(ssl, sd);   
  86. err = SSL_accept(ssl);   
  87. if (NULL == ssl) {   
  88. goto out;   
  89. }   
  90. /*  
  91. printf (“SSL connection using %s\n”, SSL_get_cipher(ssl));  
  92. client_cert = SSL_get_peer_certificate(ssl);  
  93. if (client_cert != NULL) {  
  94. printf (“Client certificate:\n”);  
  95. str = X509_NAME_oneline (X509_get_subject_name (client_cert), 0, 0);  
  96. CHK_NULL(str);  
  97. printf (“\t subject: %s\n”, str);  
  98. Free (str);  
  99. str = X509_NAME_oneline (X509_get_issuer_name (client_cert), 0, 0);  
  100. CHK_NULL(str);  
  101. printf (“\t issuer: %s\n”, str);  
  102. Free (str);  
  103. X509_free (client_cert);  
  104. }  
  105. else  
  106. printf (“Client does not have certificate.\n”);  
  107. */  
  108. err = SSL_read(ssl, buf, sizeof(buf) – 1);   
  109. if (err == -1) {   
  110. goto out;   
  111. }   
  112. buf[err] = ‘\0′;   
  113. printf (“Got %d chars:’%s’\n”, err, buf);   
  114. err = SSL_write(ssl, “I hear you.”, strlen(“I hear you.”));   
  115. CHK_SSL(err);   
  116.   
  117. out:   
  118. if (-1 != sd) {   
  119. close(sd);   
  120. }   
  121. if (-1 != listen_sd) {   
  122. close(listen_sd);   
  123. }   
  124.   
  125. if (ssl) {   
  126. SSL_free(ssl);   
  127. }   
  128. if (ctx) {   
  129. SSL_CTX_free(ctx);   
  130. }   
  131. return 0;   
  132. }  

相關(guān)文章

最新評(píng)論