
The Heartbleed bug `CVE-2014-0160` is a severe implementation flaw in the OpenSSL library, which enables attackers to steal data from the memory of the victim server. The contents of the stolen data depend on what is there in the memory of the server. It could potentially contain private keys, TLS session keys, usernames, passwords, credit cards, etc. The vulnerability is in the implementation of the Heartbeat protocol, which is used by SSL/TLS to keep the connection alive.
Heartbleed बग CVE-2014-0160 OpenSSL लाइब्रेरी में एक गंभीर कार्यान्वयन दोष है, जो हमलावरों को पीड़ित सर्वर की मेमोरी से डेटा चुराने में सक्षम बनाता है। चुराए गए डेटा की सामग्री इस पर निर्भर करती है कि सर्वर की मेमोरी में क्या है। इसमें संभावित रूप से निजी कुंजियाँ, TLS सत्र कुंजियाँ, उपयोगकर्ता नाम, पासवर्ड, क्रेडिट कार्ड आदि शामिल हो सकते हैं। यह कमज़ोरी Heartbeat प्रोटोकॉल के कार्यान्वयन में है, जिसका उपयोग SSL/TLS द्वारा कनेक्शन को सक्रिय रखने के लिए किया जाता है।
प्रभावित OpenSSL संस्करण सीमा 1.0.1 से 1.0.1f तक है। Ubuntu VM में संस्करण 1.0.1 है।
Heartbleed हमला Heartbeat अनुरोध पर आधारित है। यह अनुरोध सर्वर को कुछ डेटा भेजता है, और सर्वर डेटा को अपने प्रतिक्रिया पैकेट में कॉपी कर लेता है, ताकि सभी डेटा वापस प्रतिध्वनित हो जाएँ। सामान्य स्थिति में, मान लीजिए कि अनुरोध में 3 बाइट डेटा "ABC" है, तो लंबाई फ़ील्ड का मान 3 होगा। सर्वर डेटा को मेमोरी में रखेगा, और डेटा की शुरुआत से 3 बाइट्स को अपने प्रतिक्रिया पैकेट में कॉपी करेगा। हमले के परिदृश्य में, अनुरोध में 3 बाइट डेटा हो सकता है, लेकिन लंबाई फ़ील्ड 1003 कह सकती है। जब सर्वर अपना प्रतिक्रिया पैकेट बनाता है, तो वह डेटा की शुरुआत (अर्थात "ABC") से कॉपी करता है, लेकिन वह 3 बाइट के बजाय 1003 बाइट कॉपी करता है। ये अतिरिक्त 1000 बाइट स्पष्ट रूप से अनुरोध पैकेट से नहीं आते; वे सर्वर की निजी मेमोरी से आते हैं, और उनमें अन्य उपयोगकर्ताओं की जानकारी, गुप्त कुंजियाँ, पासवर्ड आदि हो सकते हैं।
अब, अनुरोध के लंबाई फ़ील्ड को बदलें। पहले, आइए समझें कि ऊपर दिए गए चित्र से Heartbeat प्रतिक्रिया पैकेट कैसे बनता है। जब Heartbeat अनुरोध पैकेट आता है, तो सर्वर पैकेट को पार्स करके payload और Payload_length मान (जो ऊपर हाइलाइट किया गया है) प्राप्त करेगा। यहाँ, payload केवल 3-बाइट स्ट्रिंग "ABC" है और Payload_length मान बिल्कुल 3 है। सर्वर प्रोग्राम इस लंबाई मान को अनुरोध पैकेट से आँख मूंदकर लेगा। फिर यह "ABC" संग्रहीत करने वाले मेमोरी स्थान पर इंगित करके और Payload_length बाइट्स को प्रतिक्रिया payload में कॉपी करके प्रतिक्रिया पैकेट बनाता है। इस प्रकार, प्रतिक्रिया पैकेट में 3-बाइट स्ट्रिंग "ABC" होगी।
अब, Heartbleed हमले को उस प्रकार लॉन्च करें जैसा कि नीचे दिए गए चित्र में दिखाया गया है। payload को समान रखें (3 बाइट), लेकिन Payload_length फ़ील्ड को 1003 पर सेट करें। सर्वर प्रतिक्रिया पैकेट बनाते समय फिर से आँख मूंदकर इस Payload_length मान को लेगा। इस बार, सर्वर प्रोग्राम स्ट्रिंग "ABC" पर इंगित करेगा और मेमोरी से 1003 बाइट्स को प्रतिक्रिया पैकेट में payload के रूप में कॉपी करेगा। स्ट्रिंग "ABC" के अलावा, अतिरिक्त 1000 बाइट्स प्रतिक्रिया पैकेट में कॉपी हो जाते हैं, जो मेमोरी से कुछ भी हो सकते हैं, जैसे गुप्त गतिविधि, लॉगिंग जानकारी, पासवर्ड इत्यादि।
हमला कोड Payload_length मान को बदलने की अनुमति देता है। डिफ़ॉल्ट रूप से, मान काफी बड़ा (0x4000) सेट किया जाता है, लेकिन इसे कम किया जा सकता है।
Heartbleed कमज़ोरी को ठीक करने का सबसे आसान तरीका OpenSSL लाइब्रेरी को नवीनतम संस्करण में अपडेट करना है। हालाँकि, उद्देश्य स्रोत कोड के माध्यम से कमज़ोरी को पैच करना है।
Heartbeat अनुरोध/प्रतिक्रिया पैकेट का प्रारूप
struct {
HeartbeatMessageType type; // 1 byte: request or the response
uint16 payload_length; // 2 byte: the length of the payload
opaque payload[HeartbeatMessage.payload_length];
opaque padding[padding_length];
} HeartbeatMessage;
पैकेट का पहला फ़ील्ड (1 बाइट) प्रकार की जानकारी है, और दूसरा फ़ील्ड (2 बाइट) payload लंबाई है, जिसके बाद वास्तविक payload और पैडिंग आती है। payload का आकार payload लंबाई फ़ील्ड में मान के समान होना चाहिए, लेकिन हमले के परिदृश्य में, payload लंबाई को एक अलग मान पर सेट किया जा सकता है। नीचे दिया गया कोड स्निपेट दिखाता है कि सर्वर अनुरोध पैकेट से डेटा को प्रतिक्रिया पैकेट में कैसे कॉपी करता है।
Heartbeat अनुरोध पैकेट की प्रक्रिया और प्रतिक्रिया पैकेट उत्पन्न करना
/* Allocate memory for the response, size is 1 byte
* message type, plus 2 bytes payload length, plus
* payload, plus padding
*/
unsigned int payload;
unsigned int padding = 16; /* Use minimum padding */
// Read from type field first
hbtype = *p++; /* After this instruction, the pointer
* p will point to the payload_length field */
// Read from the payload_length field from the request packet
n2s(p, payload); /* Function n2s(p, payload) reads 16 bits
* from pointer p and store the value
* in the INT variable "payload". */
pl = p; // pl points to the beginning of the payload content
if (hbtype == TLS1_HB_REQUEST)
{
unsigned char *buffer, *bp;
int r;
/* 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;
// Enter response type, length and copy payload *bp++ = TLS1_HB_RESPONSE;
s2n(payload, bp);
// copy payload
memcpy(bp, pl, payload); /* pl is the pointer which
* points to the beginning
* of the payload content */
bp += payload;
// Random padding
RAND_pseudo_bytes(bp, padding);
// this function will copy the 3+payload+padding bytes
// from the buffer and put them into the heartbeat response
// packet to send back to the request client side.
OPENSSL_free(buffer);
r = ssl3_write_bytes(s, TLS1_RT_HEARTBEAT, buffer, 3 + payload + padding);
}
कमज़ोरी यहाँ है
// copy payload
memcpy(bp, pl, payload);
यह जाँच नहीं है कि pl मान्य है या नहीं। इसलिए, मेमोरी उल्लंघन हो सकता है।
पैच:
memcpy() निष्पादित होने से पहले बाउंड जाँचVM में पैच किए गए थे लेकिन इस रेपो में नहीं दिखाए गए हैं।
आपकी रुचि के लिए धन्यवाद, यह परियोजना मज़ेदार और ज्ञानवर्धक थी!