I had a recent project to pentest a Microsoft Office 365 (O365) environment. When researching, I found that Microsoft implemented changes towards the end of 2019 to help mitigate user enumeration issues. With those changes, many documented techniques and automated tooling that previously leaked that information either no longer worked or returned mixed results. Based on my testing, I used some modified techniques that aided me to obtain valid O365 user accounts.
Site Enumeration:
Covering the basics, I performed a DNS query to determine the contents of the target organization’s MX record. If the MX record contained protection.outlook.com, it’s pretty safe to assume that the organization was using the O365 platform for email.
Continuing, I opened a browser and navigated to https://login.microsoftonline.com/getuserrealm.srf?login=username@{Domain Name}.com&xml=1 in order to test for an O365 instance of the target’s domain name; replace the {} and text with a domain name.
Reviewing the output of Figure 2, the NameSpaceType tag returned the value of Unknown. Meaning, the instance of the domain name could not be found within the O365 platform.
With regards to Figure 3, a returned value of Managed, for the NameSpaceType tag, indicated that the domain name was a valid instance on the O365 platform. Further inspection revealed that the IsFederatedNS tag of false indicated that an on-prem LDAP solution was probably used to authenticate credentials.
User List:
Using some basic OSINT, I was able to recover a few email addresses. However, I wanted to be able to harvest additional employee names and/or email addresses for user account enumeration. So, I was able to find a Burp Suite Extension of GatherContacts.jar that would aid in obtaining the data needed to build a user list. The author (Carrie Roberts) provided a detailed installation and configuration document.
After I installed the extension, I enabled it and then launched a browser and performed a Google-Dork (using Google and Bing) against LinkedIn; while searching for the target company’s name. I continued to the next page of the returned results until the search pages were exhausted. All of the results were saved to the configured file that was specified within the GatherContact Output settings.
As a side note, Burp Suite Proxy Intercept should be off when gathering contacts.
I tried a few other tools, but their results provided limited data. So, I used the captured data from GatherContacts and performed some manual OSINT. My hope was to find laxed LinkedIn privacy settings that would provide public information regarding recent contacts as well as contact lists.
I was able to review a few accounts prior to LinkedIn requesting a login. To circumvent the login, I decided to use a browser plugin named ZenMate. The plugin allowed me to change my browser connection to different countries; which I was able to gather additional data without being requested to login to LinkedIn.
Account Validation:
To validate user accounts, I browsed to the login portal for Microsoft. Once connected, I attempted to login with a found email address (from enumeration) as well as an email address that I did not think existed. This data provided me enough information to be able to determine the email account format.
Taking it a step further, I used Burp Suite to capture the login process and sent it to the Repeater. I did this to help better understand the request/response transaction and to help identify any false positives.
When reviewing the transaction, the IfExistsResult value was key for account validation. This value should return the following possible results:
· 0 = Valid Email Address
· 1 = Invalid Email Address; does not exist in hosted O365 domain
· 5 = Valid Email Address
· 6 = Valid Email Address
Note: no credentials were passed while testing the account validation.
Once I validated the email format, I initially used the Excel instructions from the GatherContacts GitHub to finalize the user list. However, I wasn’t overly thrilled having to manipulate the data within Excel. Although, I did find a Bash script, but decided to create my own Python script (needing the practice) of parseBGC.py to automate the process.
Account Enumeration:
With the email account validation completed, I decided to use Burp Suite Intruder to automate the enumeration of the user list. In addition, I setup a Grep Match option for “IfExistsResult”:0. However, I noticed when using a large user list that the majority of my results matched the grep value of 0; even with the account that I knew was not valid.
Further investigation revealed that the ThrottleStatus increased from 0 (during the attack) to 1; thus, providing a false-positive result. So, I believe that my IP Address might have been in “Microsoft Jail” due to the speed and volume of the requests sent.
Note: one method to avoid false-positives would be to use a pass-through proxy with a smaller user list and alternating IP Addresses.
There are a few other tools that I have tested, but many of them required spraying passwords. However, I discovered that msspray.py not only sprayed passwords, but it provided an option to enumerate users. In addition, it also had the capability of using a passthrough-proxy.
Note: it may be worthwhile to randomize the user list to help bypass the added Microsoft security measures.
Next Steps:
At this point, I had a validated user list and could move forward with password spraying. There are several different passwords spraying scripts available. My password spraying script of choice would be MSSOLSpray, but I also like to use msspray as well.
Keep in mind that if password spraying is not successful, enumerate, enumerate, enumerate…
References:
https://www.gremwell.com/blog/office365-user-enumeration
https://www.trustedsec.com/blog/owning-o365-through-better-brute-forcing/
https://www.redsiege.com/blog/2020/03/user-enumeration-part-2-microsoft-office-365/
https://github.com/clr2of8/GatherContacts
https://github.com/0xZDH/msspray
Disclaimer:
This article is made available for educational purposes only!!! In addition, this article provides general information on cyber security topics used for “Ethical Hacking”.
Persons accessing this information assume full responsibility for the use and agree to not use this content for any illegal purpose. Furthermore, the author is not liable for any direct or indirect damages or expense incurred which may result from the use of the information covered within this article.
Information within this article is “as is”, without warranty of any sort.