Office 365 User Enumeration - Metasploit


This page contains detailed information about how to use the auxiliary/gather/office365userenum metasploit module. For list of all metasploit modules, visit the Metasploit Module Library.

Module Overview


Name: Office 365 User Enumeration
Module: auxiliary/gather/office365userenum
Source code: modules/auxiliary/gather/office365userenum.py
Disclosure date: 2018-09-05
Last modification time: 2021-09-03 19:58:46 +0000
Supported architecture(s): -
Supported platform(s): -
Target service / protocol: -
Target network port(s): 443
List of CVEs: -

Enumerate valid usernames (email addresses) from Office 365 using ActiveSync. Differences in the HTTP Response code and HTTP Headers can be used to differentiate between: - Valid Username (Response code 401) - Valid Username and Password without 2FA (Response Code 200) - Valid Username and Password with 2FA (Response Code 403) - Invalid Username (Response code 404 with Header X-CasErrorCode: UserNotFound) Note this behaviour appears to be limited to Office365, MS Exchange does not appear to be affected. Microsoft Security Response Center stated on 2017-06-28 that this issue does not "meet the bar for security servicing". As such it is not expected to be fixed any time soon.

Module Ranking and Traits


Module Ranking:

  • normal: The exploit is otherwise reliable, but depends on a specific version and can't (or doesn't) reliably autodetect. More information about ranking can be found here.

Basic Usage


This module is a scanner module, and is capable of testing against multiple hosts.

msf > use auxiliary/gather/office365userenum
msf auxiliary(office365userenum) > show options
    ... show and set options ...
msf auxiliary(office365userenum) > set RHOSTS ip-range
msf auxiliary(office365userenum) > exploit

Other examples of setting the RHOSTS option:

Example 1:

msf auxiliary(office365userenum) > set RHOSTS 192.168.1.3-192.168.1.200 

Example 2:

msf auxiliary(office365userenum) > set RHOSTS 192.168.1.1/24

Example 3:

msf auxiliary(office365userenum) > set RHOSTS file:/tmp/ip_list.txt

Required Options


  • RHOSTS: The target host(s), see https://github.com/rapid7/metasploit-framework/wiki/Using-Metasploit

  • USERS: Potential usernames file, one username per line

Knowledge Base


Vulnerable Application


External python module compatible with v2 and v3.

Enumerate valid usernames (email addresses) from Office 365 using ActiveSync. Differences in the HTTP Response code and HTTP Headers can be used to differentiate between:

  • Valid Username (Response code 401)
  • Valid Username and Password without 2FA (Response Code 200)
  • Valid Username and Password with 2FA (Response Code 403)
  • Invalid Username (Response code 404 with Header X-CasErrorCode: UserNotFound)

Note this behaviour appears to be limited to Office365, MS Exchange does not appear to be affected.

Microsoft Security Response Center stated on 2017-06-28 that this issue does not "meet the bar for security servicing". As such it is not expected to be fixed any time soon.

This script is maintaing the ability to run independently of MSF.

Office365's implementation of ActiveSync is vulnerable.

Verification Steps


  1. Create a file containing candidate usernames (aka email addresses), one per line.
  2. Do: use auxiliary/gather/office365userenum
  3. Do: set users [USER_FILE] with the file you created.
  4. Do: run
  5. Valid and Invalid usernames will be printed out to the screen.

Options


LOGFILE = Output file to use for verbose logging. OUTPUT = Output file for results. PASSWORD = Password to use during enumeration. Note this must exist but does not necessarily need to be valid. If it is found to be valid for an account it will be reported. THREADS = Number of concurrent requests to use during enumeration. TIMEOUT = HTTP request timeout to use during enumeration. URL = URL of Office365 ActiveSync service. USERS = Input fie containing candidate usernames, one per line. VERBOSE = Enable/Disable DEBUG logging

Scenarios


The following demonstrates basic usage, using the supplied users wordlist and default options.

msf5 auxiliary(gather/office365userenum) > set users /home/msfdev/users
users => /home/msfdev/users
msf5 auxiliary(gather/office365userenum) > run

[*] 

.       .1111...          | Title: office365userenum.py
    .10000000000011.   .. | Author: Oliver Morton (Sec-1 Ltd)
 .00              000...  | Email: [email protected]
1                  01..   | Description:
                    ..    | Enumerate valid usernames from Office 365 using
                   ..     | ActiveSync.
GrimHacker        ..      | Requires: Python 2.7 or 3.6, python-requests
                 ..       |
grimhacker.com  ..        |
@grimhacker    ..         |
----------------------------------------------------------------------------
    This program comes with ABSOLUTELY NO WARRANTY.
    This is free software, and you are welcome to redistribute it
    under certain conditions. See GPLv2 License.
----------------------------------------------------------------------------

[+] 401 VALID_USER [email protected]:Password1
[-] 404 INVALID_USER [email protected]:Password1
[*] Scanned 1 of 1 hosts (100% complete)
[*] Auxiliary module execution completed

Go back to menu.

Msfconsole Usage


Here is how the gather/office365userenum auxiliary module looks in the msfconsole:

msf6 > use auxiliary/gather/office365userenum

msf6 auxiliary(gather/office365userenum) > show info

       Name: Office 365 User Enumeration
     Module: auxiliary/gather/office365userenum
    License: GNU Public License v2.0
       Rank: Normal
  Disclosed: 2018-09-05

Provided by:
  Oliver Morton (GrimHacker) <[email protected]>

Check supported:
  No

Basic options:
  Name      Current Setting                               Required  Description
  ----      ---------------                               --------  -----------
  LOGFILE                                                 no        Log file
  OUTPUT                                                  no        Output file (will be appended to)
  PASSWORD  Password1                                     yes       Password to use during enumeration.
  RHOSTS                                                  yes       The target host(s), see https://github.com/rapid7/metasploit-framework/wiki/Usin
                                                                    g-Metasploit
  RPORT     443                                           no        IGNORE ME!
  THREADS   10                                            yes       Maximum threads
  TIMEOUT   30                                            yes       HTTP Timeout
  URL       https://outlook.office365.com/Microsoft-Serv  yes       ActiveSync URL
            er-ActiveSync
  USERS                                                   yes       Potential usernames file, one username per line
  VERBOSE   false                                         yes       Debug logging

Description:
  Enumerate valid usernames (email addresses) from Office 365 using 
  ActiveSync. Differences in the HTTP Response code and HTTP Headers 
  can be used to differentiate between: - Valid Username (Response 
  code 401) - Valid Username and Password without 2FA (Response Code 
  200) - Valid Username and Password with 2FA (Response Code 403) - 
  Invalid Username (Response code 404 with Header X-CasErrorCode: 
  UserNotFound) Note this behaviour appears to be limited to 
  Office365, MS Exchange does not appear to be affected. Microsoft 
  Security Response Center stated on 2017-06-28 that this issue does 
  not "meet the bar for security servicing". As such it is not 
  expected to be fixed any time soon.

References:
  https://grimhacker.com/2017/07/24/office365-activesync-username-enumeration/

Module Options


This is a complete list of options available in the gather/office365userenum auxiliary module:

msf6 auxiliary(gather/office365userenum) > show options

Module options (auxiliary/gather/office365userenum):

   Name      Current Setting                              Required  Description
   ----      ---------------                              --------  -----------
   LOGFILE                                                no        Log file
   OUTPUT                                                 no        Output file (will be appended to)
   PASSWORD  Password1                                    yes       Password to use during enumeration.
   RHOSTS                                                 yes       The target host(s), see https://github.com/rapid7/metasploit-framework/wiki/Usin
                                                                    g-Metasploit
   RPORT     443                                          no        IGNORE ME!
   THREADS   10                                           yes       Maximum threads
   TIMEOUT   30                                           yes       HTTP Timeout
   URL       https://outlook.office365.com/Microsoft-Ser  yes       ActiveSync URL
             ver-ActiveSync
   USERS                                                  yes       Potential usernames file, one username per line
   VERBOSE   false                                        yes       Debug logging

Advanced Options


Here is a complete list of advanced options supported by the gather/office365userenum auxiliary module:

msf6 auxiliary(gather/office365userenum) > show advanced

Module advanced options (auxiliary/gather/office365userenum):

   Name                 Current Setting  Required  Description
   ----                 ---------------  --------  -----------
   ShowProgress         true             yes       Display progress messages during a scan
   ShowProgressPercent  10               yes       The interval in percent that progress should be shown
   WORKSPACE                             no        Specify the workspace for this module

Auxiliary Actions


This is a list of all auxiliary actions that the gather/office365userenum module can do:

msf6 auxiliary(gather/office365userenum) > show actions

Auxiliary actions:

   Name  Description
   ----  -----------

Evasion Options


Here is the full list of possible evasion options supported by the gather/office365userenum auxiliary module in order to evade defenses (e.g. Antivirus, EDR, Firewall, NIDS etc.):

msf6 auxiliary(gather/office365userenum) > show evasion

Module evasion options:

   Name  Current Setting  Required  Description
   ----  ---------------  --------  -----------

Go back to menu.

Error Messages


This module may fail with the following error messages:

Check for the possible causes from the code snippets below found in the module source code. This can often times help in identifying the root cause of the problem.

error checking {} : {}


Here is a relevant code snippet related to the "error checking {} : {}" error message:

165:	    headers = {"MS-ASProtocolVersion": "14.0"}
166:	    auth = (user, password)
167:	    try:
168:	        r = requests.options(url, headers=headers, auth=auth, timeout=timeout)
169:	    except Exception as e:
170:	        msg = "error checking {} : {}".format(user, e)
171:	        if MSF:
172:	            module.log(msg, "error")
173:	        else:
174:	            logging.error(msg)
175:	        return user, UNKNOWN, None

error


Here is a relevant code snippet related to the "error" error message:

167:	    try:
168:	        r = requests.options(url, headers=headers, auth=auth, timeout=timeout)
169:	    except Exception as e:
170:	        msg = "error checking {} : {}".format(user, e)
171:	        if MSF:
172:	            module.log(msg, "error")
173:	        else:
174:	            logging.error(msg)
175:	        return user, UNKNOWN, None
176:	    status = r.status_code
177:	    if status == 401:

X-CasErrorCode


Here is a relevant code snippet related to the "X-CasErrorCode" error message:

175:	        return user, UNKNOWN, None
176:	    status = r.status_code
177:	    if status == 401:
178:	        return user, password, VALID_USER, r
179:	    elif status == 404:
180:	        if r.headers.get("X-CasErrorCode") == "UserNotFound":
181:	            return user, password, INVALID_USER, r
182:	    elif status == 403:
183:	        return user, VALID_PASSWD_2FA, r
184:	    elif status == 200:
185:	        return user, password, VALID_LOGIN, r

Error checking {} : {}


Here is a relevant code snippet related to the "Error checking {} : {}" error message:

214:	            else:
215:	                logging.debug(msg)
216:	            try:
217:	                result = check_user(url, user, password, timeout)
218:	            except Exception as e:
219:	                msg = "Error checking {} : {}".format(user, e)
220:	                if MSF:
221:	                    module.log(msg, "error")
222:	                else:
223:	                    logging.error(msg)
224:	                in_q.task_done()

error


Here is a relevant code snippet related to the "error" error message:

216:	            try:
217:	                result = check_user(url, user, password, timeout)
218:	            except Exception as e:
219:	                msg = "Error checking {} : {}".format(user, e)
220:	                if MSF:
221:	                    module.log(msg, "error")
222:	                else:
223:	                    logging.error(msg)
224:	                in_q.task_done()
225:	                continue
226:	            msg = "{}".format(result)

error


Here is a relevant code snippet related to the "error" error message:

299:	                if msf_reporter is not None:
300:	                    msf_reporter(user, password)
301:	                if valid in [VALID_LOGIN, VALID_PASSWD_2FA, VALID_USER]:
302:	                    module.log(msf_output, "good")
303:	                else:
304:	                    module.log(msf_output, "error")
305:	            else:
306:	                logging.info(output)
307:	            if output_file:
308:	                with open(output_file, "a", 1) as f:
309:	                    f.write("{}\n".format(output))

Go back to menu.


References


See Also


Check also the following modules related to this module:

Authors


Version


This page has been produced using Metasploit Framework version 6.1.27-dev. For more modules, visit the Metasploit Module Library.

Go back to menu.