解析OpenSSL程序概念及震驚業(yè)界的“心臟出血”漏洞
OpenSSL的各種概念解析:
公鑰/私鑰/簽名/驗(yàn)證簽名/加密/解密/非對稱加密
我們一般的加密是用一個密碼加密文件,然后解密也用同樣的密碼.這很好理解,這個是對稱加密.而有些加密時,加密用的一個密碼,而解密用另外一組密碼,這個叫非對稱加密,意思就是加密解密的密碼不一樣.初次接觸的人恐怕無論如何都理解不了.其實(shí)這是數(shù)學(xué)上的一個素數(shù)積求因子的原理的應(yīng)用,如果你一定要搞懂,百度有大把大把的資料可以看,其結(jié)果就是用這一組密鑰中的一個來加密數(shù)據(jù),可以用另一個解開.是的沒錯,公鑰和私鑰都可以用來加密數(shù)據(jù),相反用另一個解開,公鑰加密數(shù)據(jù),然后私鑰解密的情況被稱為加密解密,私鑰加密數(shù)據(jù),公鑰解密一般被稱為簽名和驗(yàn)證簽名.
因?yàn)楣€加密的數(shù)據(jù)只有它相對應(yīng)的私鑰可以解開,所以你可以把公鑰給人和人,讓他加密他想要傳送給你的數(shù)據(jù),這個數(shù)據(jù)只有到了有私鑰的你這里,才可以解開成有用的數(shù)據(jù),其他人就是得到了,也看懂內(nèi)容.同理,如果你用你的私鑰對數(shù)據(jù)進(jìn)行簽名,那這個數(shù)據(jù)就只有配對的公鑰可以解開,有這個私鑰的只有你,所以如果配對的公鑰解開了數(shù)據(jù),就說明這數(shù)據(jù)是你發(fā)的,相反,則不是.這個被稱為簽名.
實(shí)際應(yīng)用中,一般都是和對方交換公鑰,然后你要發(fā)給對方的數(shù)據(jù),用他的公鑰加密,他得到后用他的私鑰解密,他要發(fā)給你的數(shù)據(jù),用你的公鑰加密,你得到后用你的私鑰解密,這樣最大程度保證了安全性.
RSA/DSA/SHA/MD5
非對稱加密的算法有很多,比較著名的有RSA/DSA ,不同的是RSA可以用于加/解密,也可以用于簽名驗(yàn)簽,DSA則只能用于簽名.至于SHA則是一種和md5相同的算法,它不是用于加密解密或者簽名的,它被稱為摘要算法.就是通過一種算法,依據(jù)數(shù)據(jù)內(nèi)容生成一種固定長度的摘要,這串摘要值與原數(shù)據(jù)存在對應(yīng)關(guān)系,就是原數(shù)據(jù)會生成這個摘要,但是,這個摘要是不能還原成原數(shù)據(jù)的,嗯....,正常情況下是這樣的,這個算法起的作用就是,如果你把原數(shù)據(jù)修改一點(diǎn)點(diǎn),那么生成的摘要都會不同,傳輸過程中把原數(shù)據(jù)給你再給你一個摘要,你把得到的原數(shù)據(jù)同樣做一次摘要算法,與給你的摘要相比較就可以知道這個數(shù)據(jù)有沒有在傳輸過程中被修改了.
實(shí)際應(yīng)用過程中,因?yàn)樾枰用艿臄?shù)據(jù)可能會很大,進(jìn)行加密費(fèi)時費(fèi)力,所以一般都會把原數(shù)據(jù)先進(jìn)行摘要,然后對這個摘要值進(jìn)行加密,將原數(shù)據(jù)的明文和加密后的摘要值一起傳給你.這樣你解開加密后的摘要值,再和你得到的數(shù)據(jù)進(jìn)行的摘要值對應(yīng)一下就可以知道數(shù)據(jù)有沒有被修改了,而且,因?yàn)樗借€只有你有,只有你能解密摘要值,所以別人就算把原數(shù)據(jù)做了修改,然后生成一個假的摘要給你也是不行的,你這邊用密鑰也根本解不開.
CA/PEM/DER/X509/PKCS
一般的公鑰不會用明文傳輸給別人的,正常情況下都會生成一個文件,這個文件就是公鑰文件,然后這個文件可以交給其他人用于加密,但是傳輸過程中如果有人惡意破壞,將你的公鑰換成了他的公鑰,然后得到公鑰的一方加密數(shù)據(jù),不是他就可以用他自己的密鑰解密看到數(shù)據(jù)了嗎,為了解決這個問題,需要一個公證方來做這個事,任何人都可以找它來確認(rèn)公鑰是誰發(fā)的.這就是CA,CA確認(rèn)公鑰的原理也很簡單,它將它自己的公鑰發(fā)布給所有人,然后一個想要發(fā)布自己公鑰的人可以將自己的公鑰和一些身份信息發(fā)給CA,CA用自己的密鑰進(jìn)行加密,這里也可以稱為簽名.然后這個包含了你的公鑰和你的信息的文件就可以稱為證書文件了.這樣一來所有得到一些公鑰文件的人,通過CA的公鑰解密了文件,如果正常解密那么機(jī)密后里面的信息一定是真的,因?yàn)榧用芊街豢赡苁荂A,其他人沒它的密鑰啊.這樣你解開公鑰文件,看看里面的信息就知道這個是不是那個你需要用來加密的公鑰了.
實(shí)際應(yīng)用中,一般人都不會找CA去簽名,因?yàn)槟鞘鞘斟X的,所以可以自己做一個自簽名的證書文件,就是自己生成一對密鑰,然后再用自己生成的另外一對密鑰對這對密鑰進(jìn)行簽名,這個只用于真正需要簽名證書的人,普通的加密解密數(shù)據(jù),直接用公鑰和私鑰來做就可以了.
密鑰文件的格式用OpenSSL生成的就只有PEM和DER兩種格式,PEM的是將密鑰用base64編碼表示出來的,直接打開你能看到一串的英文字母,DER格式是二進(jìn)制的密鑰文件,直接打開,你可以看到........你什么也看不懂!.X509是通用的證書文件格式定義.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)隊對該漏洞分析發(fā)現(xiàn),該漏洞不僅是涉及到https開頭的網(wǎng)址,還包含間接使用了OpenSSL代碼的產(chǎn)品和服務(wù),比如,VPN、郵件系統(tǒng)、FTP工具等產(chǎn)品和服務(wù),甚至可能會涉及到其他一些安全設(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的心跳處理邏輯時,存在編碼缺陷。OpenSSL的心跳處理邏輯沒有檢測心跳包中的長度字段是否和后續(xù)的數(shù)據(jù)字段相符合,攻擊者可以利用這點(diǎn),構(gòu)造異常的數(shù)據(jù)包,來獲取心跳數(shù)據(jù)所在的內(nèi)存區(qū)域的后續(xù)數(shù)據(jù)。這些數(shù)據(jù)中可能包含了證書私鑰、用戶名、用戶密碼、用戶郵箱等敏感信息。該漏洞允許攻擊者,從內(nèi)存中讀取多達(dá)64KB的數(shù)據(jù)。
前幾日的漏洞分析文章主要聚焦在開啟HTTPS的網(wǎng)站上,普通網(wǎng)民可能認(rèn)為只有網(wǎng)站自身業(yè)務(wù)會受到這個漏洞的影響。從360網(wǎng)站衛(wèi)士Openssl心血漏洞在線檢測平臺(wangzhan.#/heartbleed)的監(jiān)控數(shù)據(jù)得知,心血漏洞的輻射范圍已經(jīng)從開啟HTTPS的網(wǎng)站延伸到了VPN系統(tǒng)和郵件系統(tǒng),目前共發(fā)現(xiàn)國內(nèi)共有251個VPN系統(tǒng)和725個郵件系統(tǒng)同樣存在漏洞,其中不乏很多政府網(wǎng)站、重點(diǎn)高校和相關(guān)安全廠商。
為了更好讓大家明白,Openssl心血漏洞到底是哪個環(huán)節(jié)出了問題,我們利用OpenSSL lib庫編寫了一個不依賴與任何業(yè)務(wù)的獨(dú)立server程序,來一步步實(shí)際調(diào)試一遍代碼,以此證明不僅是https的網(wǎng)站有問題,只要使用了存在該漏洞的OpenSSL libssl.so庫的應(yīng)用程序都存在安全漏洞!
測試環(huán)境
OS:CentOS release 6.4 (Final)
OpenSSL: Version 1.0.1f(沒有打開OPENSSL_NO_HEARTBEATS編譯選項)
編寫Server程序:監(jiān)聽端口9876
漏洞測試
利用網(wǎng)上python驗(yàn)證腳本(https://gist.github.com/RixTox/10222402)進(jìn)行測試
構(gòu)造異常heartbeat數(shù)據(jù)包,主要添加異常的length字段值。
測試一:
藍(lán)色的01表示的是心跳包的類型為request方向。對應(yīng)源代碼中就是#define TLS1_HB_REQUEST 1
紅色的20 00表示的心跳請求包的length字段,占兩個字節(jié),對應(yīng)的長度值為8192。
HeartBeat Response包

藍(lán)色的02表示的是心跳包的類型為response方向。
對應(yīng)源代碼中就是#define TLS1_HB_RESPONSE 2
紅色的20 00表示的心跳響應(yīng)包的length字段,占兩個字節(jié),對應(yīng)的長度值為8192。和request包的length值一樣。
綠色部分就是非法獲取到的越界數(shù)據(jù)(可能包含用戶名、密碼、郵件、內(nèi)網(wǎng)IP等敏感信息)。
測試二:
在測試一的基礎(chǔ)上,修改了request心跳包的length字段的值,從20 00 修改到 30 00
HeartBeat Requst包
30 00兩個字節(jié)對應(yīng)的長度為12288(8192+4096)
HeartBeat Response包
[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.
兩個測試用例中,response的length長度值總是比request的長度多出來了19個byte,為什么?
因?yàn)?,TLS和DTLS在處理類型為TLS1_HB_REQUEST的心跳請求包邏輯中,在從堆空間上申請內(nèi)存大小時,有4部分決定type+length+request的數(shù)據(jù)長度+pad,其中type,length,pad字段分為占1byte,2byte,16byte,所以response的數(shù)據(jù)總是比request的多出來19byte。
源碼分析
概要說明
該漏洞主要是內(nèi)存泄露問題,而根本上是因?yàn)镺penSSL在處理心跳請求包時,沒有對length字段(占2byte,可以標(biāo)識的數(shù)據(jù)長度為64KB)和后續(xù)的data字段做合規(guī)檢測。生成心跳響應(yīng)包時,直接用了length對應(yīng)的長度,從堆空間申請了內(nèi)存,既便是真正的請求data數(shù)據(jù)遠(yuǎn)遠(yuǎn)小于length標(biāo)識的長度。
相關(guān)解析源碼說明
存在該漏洞的源文件有兩個ssl/d1_both.c和ssl/t1_lib.c。
心跳處理邏輯分別是dtls1_process_heartbeat和tls1_process_heartbeat兩個函數(shù)。
dtls1_process_heartbeat函數(shù)處理邏輯:
Step1.獲取心跳請求包對應(yīng)的SSLv3記錄中數(shù)據(jù)指針字段,指向request的請求數(shù)據(jù)部分。
unsigned char *p = &s->s3->rrec.data[0];
record記錄的數(shù)據(jù)格式應(yīng)該包含了三個字段:type, length, data;分別占1byte,2byte,length的實(shí)際值。
Step2.
/* Read type and payload length first */
hbtype = *p++;
n2s(p, payload);
pl = p;
做了兩件事,獲取了type類型以及l(fā)ength字段的值(存放到payload中),然后將pl指向真正的data數(shù)據(jù)。
Step3.
/* 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;
悲劇開始上演了。沒有判斷請求記錄中的真正數(shù)據(jù)長度,直接用length字段的值來申請空間。對應(yīng)于測試一中的異常數(shù)據(jù)包的話,buffer申請的內(nèi)存大小就是8211byte。但是實(shí)際應(yīng)該申請的大小僅僅就幾個字節(jié)。
Step4.
/* Enter response type, length and copy payload */
*bp++ = TLS1_HB_RESPONSE;
s2n(payload, bp);
memcpy(bp, pl, payload);
bp += payload;
悲劇形成了。填充響應(yīng)記錄,第一個字節(jié)填充類型,第二、三個字節(jié)填充request記錄中l(wèi)ength的值,緊接著,將request的data填充為響應(yīng)的data數(shù)據(jù)。異常情況下,payload對應(yīng)的長度遠(yuǎn)遠(yuǎn)大于真正應(yīng)該使用的合法的data數(shù)據(jù)長度,這樣,就導(dǎo)致了非法越界訪問相鄰內(nèi)存空間的數(shù)據(jù)。
tls1_process_heartbeat函數(shù)的處理邏輯和dtls1_process_heartbeat一樣,此處就不再做詳細(xì)分析了。
附:ssl_server.c
編譯方式(請根據(jù)實(shí)際環(huán)境自行修改相關(guān)路徑)
該代碼是文中用于調(diào)試存在漏洞的libssl.so庫的server端,供對該漏洞感興趣的安全研究人員、安全愛好者們自行后續(xù)調(diào)試。希望這段獨(dú)立的代碼能讓大家意識到這個漏洞持續(xù)的高等級威脅:截至目前,心血漏洞僅僅是剛開始出血,避免這個漏洞引起互聯(lián)網(wǎng)業(yè)務(wù)大血崩此刻就要開始更多的行動了!
- #include<stdio.h>
- #include<stdlib.h>
- #include<string.h>
- #include<netinet/in.h>
- #include<sys/types.h>
- #include<sys/socket.h>
- #include“openssl/bio.h”
- #include“openssl/rsa.h”
- #include“openssl/crypto.h”
- #include“openssl/x509.h”
- #include“openssl/pem.h”
- #include“openssl/ssl.h”
- #include“openssl/err.h”
- #defineserver_cert“./server.crt”
- #defineserver_key“./server.key”
- #defineca_cert“./ca.crt”
- #definePORT9876
- #defineCHK_NULL(x)if((x)==NULL)exit(1)
- #defineCHK_ERR(err,s)if((err)==-1){perror(s);exit(1);}
- #defineCHK_SSL(err)if((err)==-1){ERR_print_errors_fp(stderr);exit(2);}
- intmain()
- {
- interr;
- intlisten_sd=-1;
- intsd=-1;
- structsockaddr_insa_serv;
- structsockaddr_insa_cli;
- intclient_len;
- SSL_CTX*ctx=NULL;
- SSL*ssl=NULL;
- X509*client_cert=NULL;
- char*str=NULL;
- charbuf[4096];
- SSL_METHOD*meth=NULL;
- SSL_library_init();
- SSL_load_error_strings();
- ERR_load_BIO_strings();
- OpenSSL_add_all_algorithms();
- meth=(SSL_METHOD*)SSLv23_server_method();
- ctx=SSL_CTX_new(meth);
- if(NULL==ctx){
- gotoout;
- }
- //SSL_CTX_set_verify(ctx,SSL_VERIFY_PEER,NULL);
- //SSL_CTX_load_verify_locations(ctx,ca_cert,NULL);
- if(SSL_CTX_use_certificate_file(ctx,server_cert,SSL_FILETYPE_PEM)<=0){
- gotoout;
- }
- if(SSL_CTX_use_PrivateKey_file(ctx,server_key,SSL_FILETYPE_PEM)<=0){
- gotoout;
- }
- if(!SSL_CTX_check_private_key(ctx)){
- printf(“Privatekeydoesnotmatchthecertificatepublickey\n”);
- gotoout;
- }
- listen_sd=socket(AF_INET,SOCK_STREAM,0);
- if(-1==listen_sd){
- gotoout;
- }
- memset(&sa_serv,‘\0′,sizeof(sa_serv));
- sa_serv.sin_family=AF_INET;
- sa_serv.sin_addr.s_addr=INADDR_ANY;
- sa_serv.sin_port=htons(PORT);
- err=bind(listen_sd,(structsockaddr*)&sa_serv,sizeof(sa_serv));
- if(-1==err){
- gotoout;
- }
- err=listen(listen_sd,5);
- if(-1==err){
- gotoout;
- }
- client_len=sizeof(sa_cli);
- sd=accept(listen_sd,(structsockaddr*)&sa_cli,&client_len);
- if(-1==err){
- gotoout;
- }
- printf(“Connectionfrom%d,port%d\n”,sa_cli.sin_addr.s_addr,sa_cli.sin_port);
- ssl=SSL_new(ctx);
- if(NULL==ssl){
- gotoout;
- }
- SSL_set_fd(ssl,sd);
- err=SSL_accept(ssl);
- if(NULL==ssl){
- gotoout;
- }
- /*
- printf(“SSLconnectionusing%s\n”,SSL_get_cipher(ssl));
- client_cert=SSL_get_peer_certificate(ssl);
- if(client_cert!=NULL){
- printf(“Clientcertificate:\n”);
- str=X509_NAME_oneline(X509_get_subject_name(client_cert),0,0);
- CHK_NULL(str);
- printf(“\tsubject:%s\n”,str);
- Free(str);
- str=X509_NAME_oneline(X509_get_issuer_name(client_cert),0,0);
- CHK_NULL(str);
- printf(“\tissuer:%s\n”,str);
- Free(str);
- X509_free(client_cert);
- }
- else
- printf(“Clientdoesnothavecertificate.\n”);
- */
- err=SSL_read(ssl,buf,sizeof(buf)–1);
- if(err==-1){
- gotoout;
- }
- buf[err]=‘\0′;
- printf(“Got%dchars:’%s’\n”,err,buf);
- err=SSL_write(ssl,“Ihearyou.”,strlen(“Ihearyou.”));
- CHK_SSL(err);
- out:
- if(-1!=sd){
- close(sd);
- }
- if(-1!=listen_sd){
- close(listen_sd);
- }
- if(ssl){
- SSL_free(ssl);
- }
- if(ctx){
- SSL_CTX_free(ctx);
- }
- return0;
- }
版權(quán)聲明:本站文章來源標(biāo)注為YINGSOO的內(nèi)容版權(quán)均為本站所有,歡迎引用、轉(zhuǎn)載,請保持原文完整并注明來源及原文鏈接。禁止復(fù)制或仿造本網(wǎng)站,禁止在非www.sddonglingsh.com所屬的服務(wù)器上建立鏡像,否則將依法追究法律責(zé)任。本站部分內(nèi)容來源于網(wǎng)友推薦、互聯(lián)網(wǎng)收集整理而來,僅供學(xué)習(xí)參考,不代表本站立場,如有內(nèi)容涉嫌侵權(quán),請聯(lián)系alex-e#qq.com處理。