
İlk seride(Modern Bir Zafiyetin Anatomisi Vol. I) elimizden geldiği kadar açıklamalar ve mevzunun mahiyeti hakkında bilgiler sunmaya çalıştık şimdi seriye statik kod analizi ile devam edeceğiz. Bahse konu zafiyetin nasıl oluştuğu konusunda teknik olarak aslında bir bilgimiz var ve ona ‘taşma’ diyoruz. Aslında bu SSL yapısında ‘key exchange’ dediğimiz mevzu meydana gelirken ‘alloc-dealloc’ işleminden dolayı bir taşma meydana geliyor. Yük sahibi data hedefine vardığında, hedef geriye hata mesajı olarak “memory leak(hafıza sızıntısı)” içeriği gönderiyor, böylelikle hafızada tutulan bilgilerinde açığa çıkması sağlanıyor. Zafiyetin herkesin anlayabileceği şekilde meali böyle, peki bu hafıza sızıntısı nereden kaynaklanıyor ve sebepleri nelerdir onlar üzerine konuşmakta fayda var.
C kodu üzere tanımladığımız ssl.h kütüphanesi ile birlikte zafiyet gösteren yapıları sömürgeçimiz üzere göreceğiz. Kütüphanede mevcut olan SSL yapısına bakalım;
aşğıdaki kod parçacığımızda SSL3_STATE için *s3 işaretçisi tanımlanmıştır aynı şekilde SSL_CTX ise *ctx işaretçisi olarak tanımlanmıştır.
Kod:
struct SSL {
SSL_CTX *ctx;
SSL3_STATE *s3;
}
Kod:
struct SSL_CTX {
SSL3_BUF_FREELIST wbuf_freelist;
SSL3_BUF_FREELIST rbuf_freelist;
}
struct SSL3_STATE {
SSL3_BUFFER rbuf; /* read IO goes into here */
SSL3_BUFFER wbuf; /* write IO goes into here */
SSL3_RECORD rrec; /* each decoded record goes in here */
SSL3_RECORD wrec; /* goes out from here */
}
Kod:
struct SSL3_BUF_FREELIST {
size_t chunklen;
unsigned int len;
SSL3_BUF_FREELIST_ENTRY *head;
}
Kod:
struct SSL3_BUFFER {
unsigned char *buf; /* at least SSL3_RT_MAX_PACKET_SIZE bytes,
* see ssl3_setup_buffers() */
size_t len; /* buffer size */
int offset; /* where to 'copy from' */
int left; /* how many bytes left */
}
Kod:
struct SSL3_RECORD {
/*r */ int type; /* type of record */
/*rw*/ unsigned int length; /* How many bytes available */
/*r */ unsigned int off; /* read/write offset into 'buf' */
/*rw*/ unsigned char *data; /* pointer to the record data */
/*rw*/ unsigned char *input; /* where the decode bytes are */
/*r */ unsigned char *comp; /* only used with decompression - malloc()ed */
}

ek bilgi:
kafa karıştıcı olmasın sadece memcpy fonksiyonunun kullanım şekli konumuz tam hız devam ediyor, hafıza üstünde bir aktarım yapacağız 2616. satırda kaynak olarak pl işaretçisi hedef olarak ise bp işaretçisi gösteriliyor ek olarak yukarıda bahsettiğimiz gibi uzunluk değeri ise payload olarak görünüyor.SYNOPSIS
#include <string.h>
Kod:void * memcpy(void *restrict dst, const void *restrict src, size_t n);
Kod:
2584 tls1_process_heartbeat(SSL *s)
2585 {
2586 unsigned char *p = &s->s3->rrec.data[0], *pl;
2587 unsigned short hbtype;
2588 unsigned int payload;
2589 unsigned int padding = 16; /* Use minimum padding */
2590
2591 /* Read type and payload length first */
2592 hbtype = *p++;
2593 n2s(p, payload);
2594 pl = p;
2595
2596 if (s->msg_callback)
2597 s->msg_callback(0, s->version, TLS1_RT_HEARTBEAT,
2598 &s->s3->rrec.data[0], s->s3->rrec.length,
2599 s, s->msg_callback_arg);
2600
2601 if (hbtype == TLS1_HB_REQUEST)
2602 {
2603 unsigned char *buffer, *bp;
2604 int r;
2605
2606 /* Allocate memory for the response, size is 1 bytes
2607 * message type, plus 2 bytes payload length, plus
2608 * payload, plus padding
2609 */
2610 buffer = OPENSSL_malloc(1 + 2 + payload + padding);
2611 bp = buffer;
2612
2613 /* Enter response type, length and copy payload */
2614 *bp++ = TLS1_HB_RESPONSE;
2615 s2n(payload, bp);
2616 memcpy(bp, pl, payload);
2617 bp += payload;
2618 /* Random padding */
2619 RAND_pseudo_bytes(bp, padding);
2620
2621 r = ssl3_write_bytes(s, TLS1_RT_HEARTBEAT, buffer, 3 + payload + padding);
Bahse konu fonksiyonumuz (OPENSSL_malloc) mem.c dosya kaynaklı CRYPTO_malloc fonksiyonuna ait bir makro olarak görünüyor. CRYPTO_malloc ise farklı bir konfigürasyona sahip OPENSSL tarafından yapılandırılmış malloc_ex_func fonksiyonu ile işlev görür. Yukarıda belirttiğimiz gibi, performans odaklı bir hamle bu.
Kod:
static void *(*malloc_func)(size_t) = malloc;
static void *default_malloc_ex(size_t num, const char *file, int line) {
return malloc_func(num); }
static void *(*malloc_ex_func)(size_t, const char *file, int line) = default_malloc_ex;
Leafsr Kaynak
Kod:
1677 SSL_CTX *SSL_CTX_new(const SSL_METHOD *meth)
1678 {
...
1827 #ifndef OPENSSL_NO_BUF_FREELISTS
1828 ret->freelist_max_len = SSL_MAX_BUF_FREELIST_LEN_DEFAULT;
1829 ret->rbuf_freelist = OPENSSL_malloc(sizeof(SSL3_BUF_FREELIST));
1830 if (!ret->rbuf_freelist)
1831 goto err;
1832 ret->rbuf_freelist->chunklen = 0;
1833 ret->rbuf_freelist->len = 0;
1834 ret->rbuf_freelist->head = NULL;
1835 ret->wbuf_freelist = OPENSSL_malloc(sizeof(SSL3_BUF_FREELIST));
1836 if (!ret->wbuf_freelist)
1837 {
1838 OPENSSL_free(ret->rbuf_freelist);
1839 goto err;
1840 }
1841 ret->wbuf_freelist->chunklen = 0;
1842 ret->wbuf_freelist->len = 0;
1843 ret->wbuf_freelist->head = NULL;
Kod:
678 static void *
679 freelist_extract(SSL_CTX *ctx, int for_read, int sz)
680 {
681 SSL3_BUF_FREELIST *list;
682 SSL3_BUF_FREELIST_ENTRY *ent = NULL;
683 void *result = NULL;
684
685 CRYPTO_w_lock(CRYPTO_LOCK_SSL_CTX);
686 list = for_read ? ctx->rbuf_freelist : ctx->wbuf_freelist;
687 if (list != NULL && sz == (int)list->chunklen)
688 ent = list->head;
689 if (ent != NULL)
690 {
691 list->head = ent->next;
692 result = ent;
693 if (--list->len == 0)
694 list->chunklen = 0;
695 }
696 CRYPTO_w_unlock(CRYPTO_LOCK_SSL_CTX);
697 if (!result)
698 result = OPENSSL_malloc(sz);
699 return result;
700 }
Kod:
702 static void
703 freelist_insert(SSL_CTX *ctx, int for_read, size_t sz, void *mem)
704 {
705 SSL3_BUF_FREELIST *list;
706 SSL3_BUF_FREELIST_ENTRY *ent;
707
708 CRYPTO_w_lock(CRYPTO_LOCK_SSL_CTX);
709 list = for_read ? ctx->rbuf_freelist : ctx->wbuf_freelist;
710 if (list != NULL &&
711 (sz == list->chunklen || list->chunklen == 0) &&
712 list->len < ctx->freelist_max_len &&
713 sz >= sizeof(*ent))
714 {
715 list->chunklen = sz;
716 ent = mem;
717 ent->next = list->head;
718 list->head = ent;
719 ++list->len;
720 mem = NULL;
721 }
722
723 CRYPTO_w_unlock(CRYPTO_LOCK_SSL_CTX);
724 if (mem)
725 OPENSSL_free(mem);
726 }
Hackers realize, kiddies memorize
Kaynaklar:
My heart is ok, but my eyes are bleeding | Leaf Security Research
Anatomy of OpenSSL's Heartbleed: Just four bytes trigger horror bug • The Register
CVE-2014-0160 Heartbleed Attack POC and Mass Scanner . - Blogs - Garage4hackers Forum
https://45h15h.files.wordpress.com/2014/07/heartbleed-poc-demo-by-0xashish.pdf
From Missingno to Heartbleed: Buffer Exploits and Buffer Overflows - YouTube
Heartbleed - Wikipedia
https://blog.cloudflare.com/answeri...an-you-get-private-ssl-keys-using-heartbleed/
Heartbleed Open SSL Bug FAQ & Advisory - Checkmate
*Heartbleed 漏洞分析 | 0x4C43's Blog
Buffer Overflow (BOF) Examples
Heartbleed and Static Analysis – Embedded in Academia
xkcd: Heartbleed Explanation