Why EternalBlue worked
EternalBlue caused WannaCry and NotPetya, but the underlying bug is more interesting than the press coverage suggested. A type confusion between two SMB transaction structures, plus careful heap grooming.
EternalBlue is the SMB exploit Shadow Brokers leaked in April 2017, originally developed by the NSA's TAO group. It powered WannaCry the following month, NotPetya in June, and a long tail of cryptominers and ransomware that ran for years afterwards. Most people in security can describe the consequences. Fewer can describe the bug.
The technical detail is unusually instructive. EternalBlue is what happens when a protocol designed in the late eighties grows, by accretion, three different structures that all start with the same field, and a parser that picks which one to use based on a value computed from a different field altogether. With a heap allocator that mostly does what you ask. The result is a remote, pre-authentication, kernel-mode arbitrary write, which is approximately the worst kind of bug.
SMB transactions, briefly
SMBv1 is the original Server Message Block protocol, designed for OS/2 by the LAN Manager folks and carried forward by Microsoft with backwards-compatible additions ever since. By the 2000s it had grown a transaction system for grouping related commands and processing them atomically.
Three transaction subprotocols matter here: TRANS, TRANS2, and NT_TRANS. They differ in the size of their length fields. TRANS uses 16-bit, NT_TRANS uses 32-bit to support larger data, TRANS2 sits in the middle. All three exist for backwards compatibility. All three are parsed by a shared dispatch path inside the SMB driver.
The structures you need to track are FEA and NT FEA. FEA is the older encoding (File Extended Attributes, used to attach key-value pairs to file operations); NT FEA is the wider one. The two encodings differ in their length-field widths. The conversion routine that translates between them is where the bug lives.
The bug, in the form a kernel reviewer should have caught
The vulnerable function takes an FEA list and converts it to NT FEA format. To know how much memory to allocate for the destination, it needs to compute the destination size. The size computation reads the source list's length fields, walks the entries, and sums them.
The problem is that the size computation uses one type for its arithmetic, and the destination buffer write uses a different type, with the wrong width. Specifically, the size calculation uses a WORD (16-bit) length field where a DWORD (32-bit) one was needed. If you craft an FEA list whose total length fits in 32 bits but whose 16-bit truncation underflows the size calculation, you get a destination buffer too small for the data the writer is about to put into it.
The writer doesn't check. It writes the full 32-bit-length data into a buffer sized for the 16-bit-truncated calculation. The result is a heap overflow whose size and contents the attacker controls completely.
In schematic form:
attacker-controlled FEA list (fits in 32 bits, truncates in 16) | v ┌────────────────────────────────────────────┐ │ size_calc = sum of WORD length fields │ │ (under-counts by full 32-bit overflow) │ └────────────────────────────────────────────┘ | v ┌────────────────────────────────────────────┐ │ dest = SrvAllocate(size_calc) │ │ ← buffer too small │ └────────────────────────────────────────────┘ | v ┌────────────────────────────────────────────┐ │ for each FEA, write DWORD-length data │ │ → linear heap overflow into adjacent chunk │ └────────────────────────────────────────────┘That's the type confusion. Two structures (FEA and NT FEA) sharing a code path that wasn't audited carefully when the second one was bolted on.
Why a kernel heap overflow is easier to live with than you'd hope
A linear heap overflow into an unknown neighbour is, in isolation, hard to use. You don't know what's adjacent. You don't know how the allocator will lay things out. The kernel pool isn't a free-for-all; it has its own segregated lists, its own quotas, its own coalescing behaviour.
EternalBlue's authors solved the layout problem with an SMB feature most people had forgotten about. By sending session setup requests of varying sizes, you can shape the pool until you're confident an allocation of size X will land immediately before a chunk of attacker-controlled type Y.
The Y in EternalBlue is an SrvNet buffer. SrvNet is the kernel module that handles SMBv2 connections (yes, v2; one elegance of the exploit is that the bug is in v1 but the grooming uses v2). SrvNet buffers contain a function pointer at a known offset that gets dereferenced when an SMBv2 packet arrives.
So the chain is: groom the pool with SMBv2 connections so an SrvNet buffer sits next to where the FEA conversion will write, trigger the FEA overflow with attacker data including a chosen function pointer, send another SMBv2 packet, and the corrupted pointer gets called.
The grooming takes a few hundred packets. The whole chain runs in well under a second. The only authentication required is anonymous SMB access, which by default Windows servers and workstations accepted from anywhere on the same network segment.
Where the function pointer points
The corrupted SrvNet pointer points at attacker-controlled data inside the same pool, sprayed there during the same connection. That memory contains shellcode. The shellcode runs in kernel mode with full privileges.
What the public exploit does next is install a kernel-mode hook that intercepts subsequent SMB requests, looking for a magic identifier, and dispatches to a backdoor handler. This is DoublePulsar, the second tool in the leak. It gives you a stable command channel that survives reboots and doesn't show up in the file system or registry. Most "EternalBlue infections" were really DoublePulsar implants delivered through EternalBlue, then used by whichever crew showed up next to deploy ransomware.
Why patching was slow
Microsoft released MS17-010 in March 2017, a month before the Shadow Brokers leak. Patches existed. They didn't get applied at the rate they needed to.
Windows XP was a big part of the problem. Extended support had ended in 2014, the patch initially didn't cover it, and tens of millions of XP machines were still running in healthcare, manufacturing, and embedded settings. After WannaCry, Microsoft released an out-of-band XP patch. Many of those systems still didn't get patched, because nobody knew they were running Windows underneath. Hospital infusion pumps, factory floor controllers, point-of-sale terminals: XP shipped inside a lot of devices whose vendors had long since gone out of business.
SMBv1 itself was the second issue. A long tail of legacy applications and devices used it, and disabling SMBv1 broke connectivity to those devices. Many enterprises deferred the patch and the protocol disablement, hoping to address both as part of a migration that mostly didn't happen. Some organisations also simply didn't believe the patch was urgent — they had patched many SMB bugs over the years, none of which had become a global ransomware event. Then WannaCry happened.
The longer impact
WannaCry hit on May 12th, 2017. It encrypted around 200,000 hosts in 150 countries. The UK National Health Service was one of the hardest-hit institutions in the West, with thousands of appointments cancelled and several hospitals diverting ambulances. The kill switch a researcher discovered (the now-famous accidental sinkhole at iuqerfsodp9ifjaposdfjhgosurijfaewrwergwea.com) prevented the outbreak from being worse.
NotPetya arrived in June, used EternalBlue alongside other lateral movement primitives, and turned out not to be ransomware in any real sense; the encryption was destructive and irreversible. Maersk's worldwide IT was rebuilt from a single domain controller in Ghana that happened to be offline during the outbreak. Damages estimates run into the tens of billions, with insurance coverage still being litigated.
The longer-tail effect was a public reckoning with the policy of stockpiling vulnerabilities. The fact that an agency stockpile got breached and released into the wild made it harder to argue that "we will keep these safe" was a defensible position. The Vulnerabilities Equities Process got revised. The actual hold rate is classified, so we don't know if anything substantive changed.
The technical takeaway
EternalBlue compresses several bug categories into one chain. A type confusion as the primitive, a heap overflow as the exploitation, heap grooming for reliability, function pointer overwrite for control hijack. Each of those is a category in its own right; most exploits use one or two. EternalBlue uses all four, in a way that's documented in the leaked source. One of the worked examples that's hardest to skip if you want to understand modern exploitation.
Where this fits in
Module 90 (Vulnerability Discovery Case Studies) walks through the full exploit, from the original code review of the FEA conversion path to the heap grooming to the SrvNet pointer hijack. EternalBlue sits alongside a small set of other landmark bugs (Cloudbleed, Heartbleed, the Equifax Struts incident) as material for understanding what real-world vulnerability discovery and exploitation actually look like.