Friday, January 21, 2022

How we hacked your billion-dollar company for forty-two bucks

by Jamie Riden



subvert (v) : 3. To cause to serve a purpose other than the original or established one; commandeer or redirect: - freedictionary.com

Why did one straw break the camel's back?
Here's the secret
The million other straws underneath it
- Mos Def, Mathematics


The basic idea of this blog post is that most organizations’ Internet perimeters are permeable. Weaknesses in outward-facing services are rarely independent of one another, and leveraging several together can often result in some sort of user-level access to internal systems.

A lot of traffic goes in and out of a normal company’s Internet perimeter: email comes in and goes out, web traffic from customers or potential customers comes in, web traffic for internal users goes out, and lots of necessary services create traffic, such as Citrix remote desktop, web authentication (especially password resets), helpdesk services, file exchange and more. The question is, can we make use of combinations of seemingly minor problems to access internal systems? The answer is mostly, yes.

To substantiate the admittedly clickbait-y title (it was delivered as a talk at B-Sides London), we spent eight dollars a month on a Linux VPS and occasionally bought a .com domain for 10 bucks. In fact, the biggest single expenditure was on coffee.

All domain names have been anonymized below; if the ones I have given exist, they are not the entity I am describing. Obviously, all of this was done at the request of the particular entity, in order to find weaknesses so they could be fixed.

Definitions


‘Username enumeration’ is the term used when a function confirms whether a username is valid or not. For example, password reset processes that tell you a username doesn’t exist. A difference in response time will also do, if consistent enough—it doesn’t have to be explicit. However, office.com logins tell you clearly: “This username may be incorrect … “

‘Password spraying’ refers to checking one password against lots and lots of users, so that by the time you come back to a user to try a new password, any account lockout counters have been reset. For example, trying “Spring2022!” against jeff@example.com and dave@example.com, etc. Of course, there may be rate limits on guesses, as well as account lockout policies, and if so, we will need to deal with that.

 

Tahi.com


Initially, we used an OSINT tool called FOCA (https://www.elevenpaths.com/innovation-labs/technologies/foca) to find any metadata in published documents. FOCA will search and download files like PDFs and Word docs, and look for properties like ‘author’ or ‘operating system’ or anything that may be of interest to an attacker. This didn’t result in much, apart from a few things that might be user IDs of the form ‘ID01234567’.

On the perimeter, we noticed the helpdesk web page allowed user enumeration, but this was pretty slow and would need special scripting to exploit in bulk. It helped confirm that the information we’d found were user IDs, but it wasn’t ideal for large-scale harvesting.

As the target exposed OWA, we used MailSniper (https://github.com/dafthack/MailSniper), and in particular, Invoke-UsernameHarvestOWA to confirm valid user IDs in a large block surrounding the IDs we had found with FOCA. This resulted in a couple of thousand users in the particular range, and from there, we moved on to using Invoke-PasswordSprayOWA from the same package.

PS MailSniper> Invoke-PasswordSprayOWA -ExchHostname mail.tahi.com -UserList .\userlist.txt -Password Spring2021! -Threads 5 -OutFile sprayed-owa-creds.txt

We started using MailSniper to enumerate on 16th of the month, kept it running pretty much continuously doing one thing or another, and by the 22nd we had obtained passwords for two users.

OWA did not have two-factor authentication (2FA) enabled, so we had access to two email accounts, and internal mail filtering is a lot less restrictive than for mail coming in from outside. That means we can do something like send a custom implant in reply to a real email and ask the victim to run it.

In this case, the problems were: having guessable usernames and guessable passwords at the same time and not enforcing 2FA for all services.

 

Rua.com


Again, we used FOCA to establish a few examples, in this case, some combination of first and last name, like “jsmith.” We downloaded common US surnames (https://americansurnames.us/top-surnames) and made a list of likely candidates with common first initials and last names. This can be done with a simple bash one-liner.

MSOLSpray.py (https://github.com/MartinIngesen/MSOLSpray) is a Python implementation of a tool called MSOLSpray (https://github.com/dafthack/MSOLSpray) implemented in PowerShell. As I prefer using Python tooling, I picked this one to try out the various candidate usernames against the Microsoft Online login—the same thing you authenticate to when logging in to office.com, for example. In this case, we also used a tool called Fireprox (https://github.com/ustayready/fireprox) to rotate the source IP address and evade any rate-limiting controls based on source IP.

Some manual checks of the initial results showed that it was not a straightforward login once a username had been correctly guessed; there was then a web redirect to an on-premise Identity Provider (IdP). In this case, MSOLSpray.py (and I think the original MSOLSpray) determines the existence correctly but does not confirm the correct password. So we needed to figure out how to fix that.

People who do any sort of work testing websites may have come across a tool called Selenium (https://selenium-python.readthedocs.io/)–this enables a script written in Python, for example, to drive the browser through a set process and allows the script to query information back from the web pages. After some hours of scripting, it was possible to get Selenium/Python/Chrome to walk through the login process from start to finish and distinguish between valid users with the correct password, valid users with the wrong password, and users that do not exist. The whole thing took maybe 30 seconds per try on average, so while not quick, it was eminently feasible—and remember, MSOLSpray.py had at least confirmed which usernames existed.




Figure 1 - using Selenium's WebDriver to enter information into web pages

Using Selenium, we got correct passwords for around 10 users. 2FA had been enabled with registration on first login, but the nature of business meant a lot of staff had never logged in and thus had not registered their own 2FA tokens.

We registered our own 2FA token against some of these accounts and logged in to a Citrix desktop. From there, we could deploy a custom implant directly, as well as query AD for configuration weaknesses with tools such as BloodHound.

Again, having guessable passwords combined with not having fully configured 2FA for everyone allowed us to gain access.

 

Toru.com


We had already guessed two sets of credentials for toru.com but needed more privileges.

Exploring the perimeter led to the discovery of a website where people book time off from work, which seemed to have an open URL redirect; that is, it did not validate the url parameter correctly for redirecting after a successful login.

We hosted a cloned page, but with a “wrong password” error already on it. The phishing email we sent gave a legitimate page address but with ?url=<phishing site>:

https://pto.toru.com/login?url=https://pto-toru.com/phishing   

Users would get “[EXTERNAL]” in the subject line, but the link was obviously to their own site.

The real site took the username and password and would redirect to the cloned page on successful login. The cloned site reported “wrong creds, please retry”, and then redirected back to the original, valid logged-in session that had been established.

No one even noticed they’d been phished.

Despite the fact that IT had blocked the URL on the corporate proxy (thanks to a service that looked out for domain typo-squatting), we still got 10 or so sets of credentials from people using their own devices at home.

Again, toru.com did not use 2FA for OWA, so we could access more email accounts and find a good reason for someone to execute our implant, attached to an internal only email.

 

Rima.com


Rima.com used hybrid AD, so again we could do password spraying against Microsoft Online with MSOLSpray.py and Fireprox.

User IDs were also numeric (i.e. “A01234567”).

We found a few passwords (in the form MonthYear or SeasonYear!), but it initially looked like everything required 2FA; however, the very useful MFASweep tool (https://github.com/dafthack/MFASweep) discovered the ActiveSync mail protocol was an exception.

Once we knew this, we could use Windows 10 Mail to send emails from a compromised user to another user - including executable attachments.

 

Key Takeaways


In all four cases, we managed to get some way of executing code inside the perimeter - and then could proceed to the "normal" red team activities of dropping Cobalt Strike implants and exploring inside the organisation.

A combination of “minor” issues can be very serious indeed. Remember that CVSS2 does not consider interactions between different issues, so a CVSS "medium" like open URL redirect might need an urgent fix.

User enumeration exists in a lot of different places on most perimeters; any instance of it will do for an attacker.

Red Team

Password spraying is a numbers game; aim for a thousand usernames if you can, but the more the better.

Bigger and/or older companies can actually be easier targets because they have larger attack surfaces.

Although a red team is by no means an audit, such an exercise is certainly a worthwhile avenue of attack, and at worst, it's something to leave running in the background while you do the cool Cobalt Strike implant stuff.

Blue Team


Log everything. Monitor everything. It will come in useful at some point.

Weak passwords need to be changed proactively.

Aim to use 2FA across all services. No exceptions.

Keeping an inventory of all hosts and turning off obsolete services is a really good idea.

While I don’t normally recommend expiring passwords, it can help if you are strengthening your password policy, as weaker passwords will age out. Obviously, just the standard Windows policy of 'at least 3 of 4 character classes' will not do, because "Summer2022!" meets it; try to stop people setting passwords based on dictionary words and keyboard patterns.

“Honeypots” can be quite useful. For example, you can create a VM which has RDP privileges for everyone—BloodHound will pick this up. You know any logins to that VM are, at best, unnecessary and, at worst, an attacker probing for AD weaknesses. Equally, you can create a service account with an SPN so that the password hash can be recovered via kerberoasting. If no one should be using it, any time anyone logs in to the account, it is likely bad news.