Microsoft 365 sotto sorveglianza: un monitor fatto in casa dopo un phishing
Dopo un phishing arrivato da un fornitore compromesso ho costruito un monitor di sicurezza per il tenant Microsoft 365: headless, sola lettura, e con un trucco per leggere i log di accesso senza pagare la licenza Entra P1.
L'innesco è stato un phishing che non sembrava un phishing: arrivava da un fornitore vero, il cui account era stato compromesso, con un link a un documento "condiviso" ospitato su un servizio Microsoft legittimo usato come civetta. Classico attacco AiTM, dove la pagina-esca intercetta credenziali e token di sessione. Dopo averlo contenuto mi sono accorto del problema vero: non avevo nessuna visibilità continua su cosa succedeva nel tenant.
Così ho costruito un monitor che gira ogni sei ore, headless e in sola lettura, con un token applicativo. Controlla, su tutte le caselle, i segnali che contano davvero per una compromissione: nuovi consensi OAuth, regole di posta con inoltro esterno, credenziali aggiunte di nascosto a un'app (la backdoor silenziosa che quasi nessuno guarda), nuovi amministratori, nuovi metodi di autenticazione, invii anomali. In più un controllo locale sul server.
Il pezzo di cui vado più fiero è come leggo gli accessi senza spendere. I sign-in ricchi di Graph richiedono la licenza Entra P1, che qui non c'è:
# GET https://graph.microsoft.com/v1.0/auditLogs/signIns -> 403 senza Entra P1
# Stessi eventi di login, gratis, dall'Unified Audit Log:
# POST https://manage.office.com/.../subscriptions/start?contentType=Audit.AzureActiveDirectory
# GET .../subscriptions/content?contentType=Audit.AzureActiveDirectory
L'Office 365 Management Activity API espone gli stessi eventi, gratis e in modo headless. Il "no" della licenza diventa un "sì" cambiando porta d'ingresso.
Per i falsi positivi ho evitato di hardcodare filtri, che fanno perdere segnale. Ogni rilievo ha un'impronta: marco una volta il rumore noto come "a posto", e solo le novità vere fanno scattare l'allarme. La rilevazione resta larga, il rumore sparisce.
Due scelte di metodo che rifarei. I segreti non li ho messi dentro l'eseguibile (sarebbe sicurezza finta: bastano strings o un decompilatore, e un binario rubato se li porta dietro); stanno cifrati con DPAPI, legati a quella macchina. E ogni azione distruttiva resta manuale e con conferma: si revoca una sessione, che è reversibile, non si disabilita un account al buio.
La parte più istruttiva è stata tarare il rumore: la mia stessa attività di amministrazione veniva segnalata come sospetta. Il valore non era nel codice, ma nel decidere cosa lasciar fare in automatico e cosa no.