Netwrix 1Secure offre visibilità unificata su dati e identità - gratuito per 14 giorni con accesso completo.Inizia una prova gratuita

Centro risorseBlog

Il codice di errore è l'indizio

Il codice di errore è l'indizio

Oct 2, 2026

Proofpoint ha documentato due campagne quest’anno che convalidano credenziali rubate contro Entra ID senza mai produrre un accesso riuscito. La tecnica è abbastanza semplice da spiegare in una frase: invia una password all’endpoint del token con un client ID che non corrisponde a nessuna applicazione registrata e leggi l’errore che ricevi. Questi codici di errore sono importanti, ma la perdita maggiore è dove ogni codice si colloca nella sequenza di autenticazione.

Tre codici, tre significati diversi

Le richieste vanno all’endpoint OAuth 2.0 Resource Owner Password Credentials (ROPC): un POST che trasporta username, password e client_id. Questa tecnica è specificamente limitata a ROPC, e la sua restrizione è tra le mitigazioni.

Tre risposte contano:

  • AADSTS50034 (UserAccountNotFound): L'account non è nella directory.
  • AADSTS50126 (InvalidUserNameOrPassword): Documentato come un errore generico che copre ogni tipo di fallimento.
  • AADSTS700016: L'identificativo dell'applicazione non è stato trovato nella directory.

AADSTS50126 non dovrebbe discriminare tra un nome utente errato e una password errata, ma il comportamento osservato li separa. Un tentativo fallito contro un nome utente inesistente non viene scritto affatto nel registro di accesso, perché Entra scrive una riga di log solo dopo aver risolto un nome utente come valido. Entra restituisce 50034 per account assenti e 50126 per account presenti con password errata, una distinzione comportamentale osservata che la documentazione Microsoft sfuma. Anche l'ambito è importante. Queste osservazioni si applicano ai tenant gestiti al token endpoint. I tenant federati convalidano le password on-premise tramite Pass-through Authentication (PTA) o ADFS, quindi il percorso di errore è diverso.

I log dimostrano le differenze nella gestione:

Request

Log row written?

What the attacker learns

Account not in directory (50034)

No

This username doesn't exist

Account exists, wrong password (50126)

Yes, failed sign-in

This username exists

Account exists, correct password (700016)

Yes, failed sign-in

This credential pair works

AADSTS700016 indica che una registrazione dell'app è danneggiata. Osservato dopo una serie di tentativi di autenticazione con client ID sconosciuti, conferma che l'attaccante possiede una password funzionante.

Le due campagne

UNK_pyreq2323 ha esaurito l'infrastruttura AWS dal 14 gennaio 2026 a inizio marzo. Ha generato oltre 700.000 ID client contraffatti randomizzando le ultime sei cifre di un identificatore di applicazione legittimo di prima parte di Exchange Online (ad esempio, 00000002-0000-0ff1-ce00-000000XXXXXX). Ha preso di mira più di un milione di account in circa 4.000 tenant e ha riutilizzato ogni ID contraffatto su non più di 12 account prima di scartarlo. Un ID di applicazione Microsoft di prima parte è pre-consentito in ogni tenant, quindi gli ID che mantengono quel prefisso sembrano appartenere piuttosto che essere rumore.

UNK_OutFlareAZ è apparso a dicembre 2025 ed è tornato a febbraio e marzo 2026, operando attraverso l'infrastruttura Cloudflare contro più di 2 milioni di utenti con 3,7 milioni di ID applicazione contraffatti.

I due hanno usato metodi di generazione diversi, e la differenza è importante per il rilevamento. Mentre pyreq2323 manteneva un prefisso reale e riutilizzava ogni ID fino a 12 volte, OutFlareAZ generava un nuovo UUIDv4 casuale per ogni richiesta, un utente per ID, quindi qualsiasi euristica basata sul riutilizzo lo perde.

(Proofpoint traccia entrambe le campagne sotto la sua designazione UNK_, che identifica cluster non attribuiti anziché attori nominati.)

Rilevamento

I difensori vedevano i fallimenti e i blocchi, ma non riuscivano a capire quali di quei fallimenti fossero conferme di credenziali. Il segnale era lì, insieme a ogni utente che aveva digitato male la password quella mattina, ma era illeggibile senza sapere quale codice di errore isolare. La metà davvero invisibile è l'enumerazione. I nomi utente inesistenti non producono alcuna riga di log, quindi il riconoscimento che precede tutto il resto non lascia tracce in nessun tenant.

Ognuna di queste richieste viene registrata nei log di accesso interattivi. Questo deriva dalla definizione di Microsoft: IsInteractive copre gli accessi in cui l’utente fornisce un fattore di autenticazione, la definizione nomina esplicitamente le password e ROPC invia una password.

La firma è un nome dell'applicazione vuoto:

Client ID in request

AppId

AppDisplayName

Real registered app

populated

populated

Well-formed UUID, unregistered

populated

blank

Malformed client ID

blank

blank

La riga due è ciò che stai cercando. Abbina isnotempty(AppId) con isempty(AppDisplayName) per isolare il caso ben formato ma non registrato invece di includere anche dati malformati.

La query che conta restituisce compromissioni di credenziali confermate:

      SigninLogs
| where TimeGenerated > ago(30d)
| where ResultType == "700016"
| where isnotempty(AppId) and isempty(AppDisplayName)
| project TimeGenerated, UserPrincipalName, AppId, IPAddress,
          UserAgent, AuthenticationProtocol, ResultDescription
| order by TimeGenerated asc
      

Ogni riga è una coppia di credenziali validate da Entra, quindi considera l'output come una lista di reset password e revoca sessioni. Non è un ticket di registrazione app, e l'errore più grave qui è indirizzare i 700016 accessi a chi possiede le registrazioni delle applicazioni.

Per il rilevamento delle campagne, pivotare sulla fonte anziché sull'ID cliente:

      SigninLogs
| where TimeGenerated > ago(7d)
| where isnotempty(AppId) and isempty(AppDisplayName)
| summarize
    DistinctAppIds = dcount(AppId),
    TargetedUsers  = dcount(UserPrincipalName),
    ConfirmedCreds = countif(ResultType == "700016"),
    WrongPassword  = countif(ResultType == "50126"),
    Lockouts       = countif(ResultType == "50053"),
    UserAgents     = make_set(UserAgent, 10)
  by IPAddress, bin(TimeGenerated, 1h)
| where DistinctAppIds > 10
| order by DistinctAppIds desc
      

Fare pivot su IPAddress è deliberato. Qualsiasi euristica basata sul limite di riutilizzo di 12 account identifica pyreq2323 e ignora completamente OutFlareAZ, perché il secondo non riutilizza mai un ID. Entrambe le campagne appaiono uguali dalla fonte: un'origine che presenta un gran numero di ID client che non risolvono nulla. Mantenere ConfirmedCreds e Lockouts nella stessa riga mostra il rumore accanto alle vere compromissioni.

Cosa che la correzione copre e non copre

Limitare ROPC tramite Conditional Access è la scelta giusta e Proofpoint lo consiglia. Ma voglio essere chiaro su cosa comporta.

Non influisce sull'enumerazione. AADSTS50034 viene restituito quando Entra risolve il nome utente, prima di qualsiasi convalida delle credenziali e due passaggi prima della valutazione della policy. Nessuna policy di Conditional Access può intercettare una risposta emessa prima che la policy venga consultata, e nessuna riga di log viene scritta indipendentemente dalla configurazione del tenant. L'enumerazione dei nomi utente contro la tua directory sopravvive a ogni controllo lato tenant, incluso un blocco rigido dell'autenticazione legacy.

Una policy che blocca l'autenticazione legacy restituisce AADSTS53003, BlockedByConditionalAccess. Con la stessa logica di ordinamento, 53003 è raggiungibile solo dopo che la password è stata convalidata, quindi il messaggio di errore dell'attaccante diventa 50126 invece di 53003. Codice diverso, stessa informazione.


Riferimenti

Condividi su

Scopri di più

Informazioni sull'autore

Ritratto di darryl baker

Darryl Baker

Ricercatore Senior di Sicurezza

Darryl G. Baker è un Senior Staff Security Researcher presso Netwrix e un’autorità riconosciuta nella sicurezza di Identity e Active Directory. Con oltre un decennio di esperienza nei sistemi di identità, ha guidato valutazioni di sicurezza aziendale, formazione sulla sicurezza dell’identità e emulazioni di minacce focalizzate su Active Directory, Entra ID e ambienti Azure. Darryl ha tenuto corsi e dimostrazioni molto apprezzati a BlueTeamCon, BSidesCT, The Experts Conference e Wild Wild West Hackin’ Fest. È l’architetto di numerosi laboratori pratici di emulazione di attacchi, sfruttando gli strumenti attuali di red team e blue team per aiutare i difensori a padroneggiare tutto, dall’analisi dei percorsi di attacco alla caccia alle minacce. Nelle sue sessioni, Darryl unisce una profonda conoscenza tecnica a casi di studio reali, permettendo ai professionisti del blue team di rafforzare la loro postura di sicurezza dell’identità e difendersi dalle tecniche avversarie in evoluzione.