CVE-2023-23397 - Microsoft Outlook Privilege Escalation / NTLM Relay Detection
April 1, 2026 ยท View on GitHub
Query Information
MITRE ATT&CK Technique(s)
| Technique ID | Title | Link |
|---|---|---|
| T1187 | Forced Authentication | Forced Authentication |
| T1078 | Valid Accounts | Valid Accounts |
Description
Detection queries for CVE-2023-23397, a critical Microsoft Outlook vulnerability where a specially crafted email triggers NTLM authentication to an attacker-controlled server. Detects rundll32 loading davclnt.dll with external IP connections.
Risk
CVE-2023-23397 is a zero-click vulnerability exploited by Russian APT28 (Fancy Bear) in attacks against European targets. It allows NTLM credential theft with no user interaction required.
Author
- Name: Gavin Knapp
- Github: https://github.com/m4nbat
- Twitter: https://twitter.com/knappresearchlb
- LinkedIn: https://www.linkedin.com/in/grjk83/
- Website:
References
- https://www.mdsec.co.uk/2023/03/exploiting-cve-2023-23397-microsoft-outlook-elevation-of-privilege-vulnerability/
- https://github.com/SigmaHQ/sigma/blob/master/rules/windows/process_creation/proc_creation_win_rundll32_webdav_client_susp_execution.yml
Defender For Endpoint
SecurityEvent | where EventID == 4688 | where (ParentProcessName endswith @'\svchost.exe' and NewProcessName endswith @'\rundll32.exe' and CommandLine contains @'C:\windows\system32\davclnt.dll,DavSetCookie' and CommandLine matches regex @'(?i)://\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}') and not (CommandLine has_any (@'://10.',@'://192.168.',@'://172.16.',@'://172.17.',@'://172.18.',@'://172.19.',@'://172.20.',@'://172.21.',@'://172.22.',@'://172.23.',@'://172.24.',@'://172.25.',@'://172.26.',@'://172.27.',@'://172.28.',@'://172.29.',@'://172.30.',@'://172.31.',@'://127.',@'://169.254.'))
//pseudocode
SecurityEvent
| where ((Process contains ("rundll32.exe") and CommandLine contains("davclnt.dll"))
| where not ((ParentProcessName contains ("cmd.exe"))
| project TimeGenerated, Computer, tostring(EventID), ParentProcessName, NewProcessName, CommandLine, SubjectUserName, SourceComputerId, processID=tolong(NewProcessId), parentProcessID=tolong(ProcessId), EventData
| order by TimeGenerated
DeviceProcessEvents | where (InitiatingProcessFolderPath endswith @'\svchost.exe' and FolderPath endswith @'\rundll32.exe' and ProcessCommandLine contains @'C:\windows\system32\davclnt.dll,DavSetCookie' and ProcessCommandLine matches regex @'(?i)://\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}') and not (ProcessCommandLine has_any (@'://10.',@'://192.168.',@'://172.16.',@'://172.17.',@'://172.18.',@'://172.19.',@'://172.20.',@'://172.21.',@'://172.22.',@'://172.23.',@'://172.24.',@'://172.25.',@'://172.26.',@'://172.27.',@'://172.28.',@'://172.29.',@'://172.30.',@'://172.31.',@'://127.',@'://169.254.'))
//playing with these at present
DeviceNetworkEvents
| extend f = extract(@'(?i)://(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})',1,InitiatingProcessCommandLine)
| where InitiatingProcessFileName =~ "rundll32.exe" and ipv4_is_private(RemoteIP) == false and isnotempty(f) //and not (RemoteIP has_any ("127.","169.254."))
| project TimeGenerated, ActionType, DeviceName, InitiatingProcessFileName, InitiatingProcessFolderPath, InitiatingProcessCommandLine, InitiatingProcessId, InitiatingProcessMD5, InitiatingProcessParentFileName, InitiatingProcessParentId, LocalIP, LocalPort, RemoteIP, RemotePort, RemoteUrl
//playing with these at present
DeviceNetworkEvents
| extend f = extract(@'(?i)://(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})',1,InitiatingProcessCommandLine)
| where InitiatingProcessFileName =~ "rundll32.exe" and ipv4_is_private(RemoteIP) == false and isnotempty(f) and not (RemoteIP has_any ("127.","169.254."))
| project TimeGenerated, ActionType, DeviceName, InitiatingProcessFileName, InitiatingProcessFolderPath, InitiatingProcessCommandLine, InitiatingProcessId, InitiatingProcessMD5, InitiatingProcessParentFileName, InitiatingProcessParentId, LocalIP, LocalPort, RemoteIP, RemotePort, RemoteUrl
DeviceTvmSoftwareVulnerabilities
| where CveId =~ "CVE-2023-23397"
| distinct DeviceName
//Identify outbound SMB connections to public IPs
DeviceNetworkEvents
| where RemotePort == 445 and ipv4_is_private(RemoteIP) == false and RemoteIP !~ "127.0.0.1" and RemoteIP !startswith "169.254."
Sentinel
SecurityEvent | where EventID == 4688 | where (ParentProcessName endswith @'\svchost.exe' and NewProcessName endswith @'\rundll32.exe' and CommandLine contains @'C:\windows\system32\davclnt.dll,DavSetCookie' and CommandLine matches regex @'(?i)://\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}') and not (CommandLine has_any (@'://10.',@'://192.168.',@'://172.16.',@'://172.17.',@'://172.18.',@'://172.19.',@'://172.20.',@'://172.21.',@'://172.22.',@'://172.23.',@'://172.24.',@'://172.25.',@'://172.26.',@'://172.27.',@'://172.28.',@'://172.29.',@'://172.30.',@'://172.31.',@'://127.',@'://169.254.'))
//pseudocode
SecurityEvent
| where ((Process contains ("rundll32.exe") and CommandLine contains("davclnt.dll"))
| where not ((ParentProcessName contains ("cmd.exe"))
| project TimeGenerated, Computer, tostring(EventID), ParentProcessName, NewProcessName, CommandLine, SubjectUserName, SourceComputerId, processID=tolong(NewProcessId), parentProcessID=tolong(ProcessId), EventData
| order by TimeGenerated
DeviceProcessEvents | where (InitiatingProcessFolderPath endswith @'\svchost.exe' and FolderPath endswith @'\rundll32.exe' and ProcessCommandLine contains @'C:\windows\system32\davclnt.dll,DavSetCookie' and ProcessCommandLine matches regex @'(?i)://\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}') and not (ProcessCommandLine has_any (@'://10.',@'://192.168.',@'://172.16.',@'://172.17.',@'://172.18.',@'://172.19.',@'://172.20.',@'://172.21.',@'://172.22.',@'://172.23.',@'://172.24.',@'://172.25.',@'://172.26.',@'://172.27.',@'://172.28.',@'://172.29.',@'://172.30.',@'://172.31.',@'://127.',@'://169.254.'))
//playing with these at present
DeviceNetworkEvents
| extend f = extract(@'(?i)://(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})',1,InitiatingProcessCommandLine)
| where InitiatingProcessFileName =~ "rundll32.exe" and ipv4_is_private(RemoteIP) == false and isnotempty(f) //and not (RemoteIP has_any ("127.","169.254."))
| project TimeGenerated, ActionType, DeviceName, InitiatingProcessFileName, InitiatingProcessFolderPath, InitiatingProcessCommandLine, InitiatingProcessId, InitiatingProcessMD5, InitiatingProcessParentFileName, InitiatingProcessParentId, LocalIP, LocalPort, RemoteIP, RemotePort, RemoteUrl
//playing with these at present
DeviceNetworkEvents
| extend f = extract(@'(?i)://(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})',1,InitiatingProcessCommandLine)
| where InitiatingProcessFileName =~ "rundll32.exe" and ipv4_is_private(RemoteIP) == false and isnotempty(f) and not (RemoteIP has_any ("127.","169.254."))
| project TimeGenerated, ActionType, DeviceName, InitiatingProcessFileName, InitiatingProcessFolderPath, InitiatingProcessCommandLine, InitiatingProcessId, InitiatingProcessMD5, InitiatingProcessParentFileName, InitiatingProcessParentId, LocalIP, LocalPort, RemoteIP, RemotePort, RemoteUrl
DeviceTvmSoftwareVulnerabilities
| where CveId =~ "CVE-2023-23397"
| distinct DeviceName
//Identify outbound SMB connections to public IPs
DeviceNetworkEvents
| where RemotePort == 445 and ipv4_is_private(RemoteIP) == false and RemoteIP !~ "127.0.0.1" and RemoteIP !startswith "169.254."