Network and transport

Heartbleed in a PCAP: three bytes ask for sixteen kilobytes

Updated

File
sslheartbleed.pcap
Format
pcap, ether
Size
19.84 KB
Packets
30
Duration
under 1 s
Captured (UTC)
2014-04-09 20:06:36
SHA-256
c8521ce4fc568b59f16f315e6a42dec0070867b7a60229d5348309d84edb568b

In frame 9 of this Heartbleed PCAP, 192.168.11.1 sends a heartbeat message three bytes long that claims a 16,384-byte payload, and 192.168.11.128 answers with a 16 KB record of its own memory, all within 22 milliseconds and 30 packets. Heartbleed, CVE-2014-0160, is one of the most consequential vulnerabilities ever found, and the exploit for it fits in that single packet. A-Packets flags the session from the capture, so the vulnerability that defined 2014 is readable without decoding anything by hand. It remains the clearest example of how a missing length check can leak a server's secrets.

The attack needs no credentials and no prior access; a single crafted heartbeat extracts whatever happens to be in the server's memory next to the heartbeat buffer, which can include private keys, session tokens and other users' data. Seeing exactly where the capture shows the attack, and how the impossible request length and the returned bytes prove the disclosure, is a compact lesson in reading a memory-disclosure flaw off the wire.

SSL/TLS view of the Heartbleed PCAP in A-Packets. The TLS session details flag a HEARTBLEED ATTEMPT between 192.168.11.1 and 192.168.11.128:443; the byte counts are explained below.
The TLS session details flag a HEARTBLEED ATTEMPT between 192.168.11.1 and 192.168.11.128:443; the byte counts are explained below.

A three-byte request that asks for sixteen kilobytes

The client starts a TLS handshake and sends a malformed heartbeat before completing it. The heartbeat extension asks a peer to echo back a payload the sender supplies, with a two-byte field stating its length. In frame 9 the whole heartbeat message is three bytes: a one-byte request type and a two-byte value declaring 16,384 bytes, with no payload and no padding behind it. A correct implementation rejects that impossible length; the vulnerable server instead copies 16 KB out of its memory and sends it back. A-Packets marks the session as a Heartbleed attempt, and the raw record shows why.

Server nameServerVersion and cipherCertificate
Heartbleed (none)192.168.11.128:443TLS 1.1O=Internet Widgits Pty Ltd, ST=Some-State, C=AU expired self-signedissued by O=Internet Widgits Pty Ltd, ST=Some-State, C=AUvalid 2014-04-09 to 2015-04-09

Open the SSL/TLS view →

Under RFC 6520 a valid heartbeat needs room for its payload and at least sixteen bytes of padding, so a three-byte message cannot be legitimate whatever it claims. In Wireshark, tls.heartbeat_message selects the decoded heartbeat records and tls.heartbeat_message.payload_length shows the claim. The response spans many TCP segments, so measure it on the reassembled TLS record rather than on any one frame.

What the certificate adds to the picture

The certificate on this session is self-signed, issuer and subject both reading the OpenSSL default "Internet Widgits Pty Ltd": the identity of a test server, which is where teaching captures like this come from. It is valid from 9 April 2014 to 9 April 2015 and the packets are from 9 April 2014, so the "expired" label in the SSL/TLS view reflects today's date, not the day of the exchange. The more important point is that the certificate and the vulnerability are independent. A server with a perfect, valid certificate from a trusted authority was just as exploitable by Heartbleed if it ran a vulnerable OpenSSL version; the certificate authenticates a key, it says nothing about whether the heartbeat handler is safe. The cert details here are a side observation, while the heartbeat mismatch is the finding.

Why Heartbleed still matters as a pattern

Heartbleed itself is old, and patched OpenSSL has been standard for a decade, but the class of flaw it taught is permanent: a protocol that trusts a client-supplied length to size a copy out of memory. The detection pattern, a response disproportionate to its request, generalises to other memory-disclosure and buffer-over-read bugs, and the response pattern, assume anything in memory may have leaked, applies whenever such a flaw is confirmed. This trace makes the mismatch concrete: a declared length with nothing behind it, and a response full of bytes the client never sent. Embedded and unsupported systems are where such flaws linger longest, so verify their versions rather than assume they were patched.

Counting the bytes in this specific over-read

The requester is 192.168.11.1 and the responding TLS endpoint is 192.168.11.128:443. Frame 9 carries eight TCP payload bytes: five for the TLS record header and three for the malformed heartbeat. The record header declares a three-byte body, while the heartbeat inside it declares a 16,384-byte payload; subtract the heartbeat's own header and zero bytes are left to echo. That is the decisive inconsistency, readable in two fields.

Heartbleed length mismatch: a three-byte request declares a 16,384-byte payload, causing the vulnerable peer to return memory beyond the request.
Heartbleed length mismatch: a three-byte request declares a 16,384-byte payload, causing the vulnerable peer to return memory beyond the request.

The server begins replying in frame 10, and Wireshark finishes reassembling that TLS record at frame 26: 16,384 bytes of record body, so 16,381 bytes of server memory after the three-byte response header. The response's own length field claims 16,384 bytes of payload, more than the record holds, so what the capture contains is the server's memory cut off at the record boundary. Every one of those bytes is data the request never supplied. What they represent, process data, zeros or repeated regions, takes a look at the hex; this page does not publish them.

Why these heartbeat bytes are readable without session keys

This trace holds the Client Hello, the server's handshake messages and the malformed heartbeat, but the handshake never reaches protected application traffic before the request. Its TLS record version is 1.1, and the heartbeat travels before any encryption is in place, which is why a passive analyst can read the offending length here without a key log. In a session that had finished its handshake, the same heartbeat would be encrypted and a sensor would see only its size: still a useful signal, since a response 77 times larger than the request is hard to explain, but not the readable length field this capture shows.

That size signal is what kept network detection of Heartbleed practical in 2014: intrusion-detection rules flagged heartbeat records whose responses dwarfed their requests, which works whether or not the fields inside are readable. A-Packets marks this session from the request itself, a heartbeat whose declared payload is longer than the record that carries it, which is the bug's own fingerprint.

Why one packet mattered so much in 2014

The reason Heartbleed became a landmark rather than a routine CVE is the combination this capture shows: the exploit is trivial, it needs no authentication, it leaves the server running normally, and it can be repeated indefinitely. An attacker could send the oversized heartbeat again and again, collecting a fresh fragment of memory each time, quietly, with nothing in the application logs to show it happened, because the request never reached the application. Over many requests the leaked fragments could include the server's private key, which allows impersonation and, for sessions without forward secrecy, decryption of recorded traffic, along with session cookies, passwords and other users' data that happened to be in memory.

That is why the response in 2014 was not just "patch" but "patch, then rotate every key and credential that server held", and why this single-exchange capture is still used to teach the pattern. The thirty packets here contain one request and one response, but in the wild the same exchange repeated thousands of times was a slow, silent exfiltration of whatever the server kept in memory.

Responding to a confirmed Heartbleed exposure

The fix is to run a patched TLS library, which closes the bug. The original OpenSSL advisory names the affected releases, 1.0.1 through 1.0.1f and 1.0.2-beta1. Today, verify the vendor build actually in use, since distributions backport fixes without changing the version number, and restart every service that loads the library, because an updated package leaves the old code mapped in a running process. Patching is not the end of the response for any server that was exposed, because you cannot know what leaked while it was vulnerable: rotate the server's private keys, reissue and revoke its certificates, and invalidate every active session, on the assumption that the tokens and credentials in memory were disclosed. Treating a confirmed Heartbleed as a key compromise, not just a software bug to patch, is the lesson the original incident taught.

On the network, the markers are the two this capture shows: a heartbeat request whose declared length exceeds what it carries, which A-Packets flags, and a response far larger than its request, which an intrusion-detection system can alert on. In MITRE ATT&CK terms the exploitation is T1190, Exploit Public-Facing Application, and the data it returns maps to credential access or collection depending on what the leaked memory held. A-Packets flags the session; to read what leaked, open the record in Wireshark.

For reading TLS in captures more generally, including what server names and certificates reveal when the payloads stay encrypted, see how to analyze encrypted traffic in a PCAP, or upload a capture of your own to inspect its TLS sessions.

More sample reports