Skip to main content

Microsoft Unified Audit Log (UAL): What You Come To Learn The Hard Way

·1956 words·10 mins
Table of Contents

Disclaimer
#

Obligatory disclaimer that English is not my first language and I wrote this blog post in one go with no QA (re-reading) afterwards. So if you spot any kind of mistakes, typos, etc. (HI Ann Fam!) feel free to DM me on Twitter (or X as it’s called now).

Also, the kind of BECs I’m talking about here are your run-of-the-mill BECs that ended up in financial fraud of some kind, or the threat actor leveraging his access to send phishing emails (internally and externally). Not really dealing with APTs here.

Premise
#

The idea, or content if I can say, for this blog post mostly comes from a tweet EricaZelic posted earlier today.

Since I had just spent the whole day going through two (2) huge UAL for two (2) Business Email Compromise (BEC) I had been working on, and took some time to update my (numerous) parsing and analysis scripts, the ̶r̶a̶g̶e̶ insights were still fresh in my mind.

Therefore, this blog post will highlight a few things you should know about UAL and in some situations, how you can deal with them.

So Many IP Addresses (But Not Always)
#

If you’re like me and like to tell clients that in the UAL, every event is linked to an IP address so that’s how you can identify events generated by an authorized third-party, well, welcome to the liar’s circle.

The truth is that not every event in the UAL has an IP address associated with it. And you can see this in two (2) ways: some events simply do not have a field holding IP address information, while some do have a field for ClientIP (or else) but it’s simply empty (you can’t imagine how hard I’m holding back writing this line).

And for these events that have an IP address, you can actually have multiple JSON fields representing that IP. The most common ones are: ClientIP, ClientIPAddress and ActorIPAddress. So depending on the Operation type, the field holding the IP address information may change. More information about this can be found in the Microsoft Learn page for the Office 365 Management Activity API Schema:

Office 365 Management Activity API schema
_The Office 365 Management Activity API schema is provided as a data service in two layers - Common schema and…_learn.microsoft.com

Not All IP Addresses Are Equal
#

From there, if you’re lucky enough to have a UAL with load of IP addresses, you’ll face your 2nd hurdle: their variety. Within a full UAL for a user (may it be for 30, 60, 90 days, etc.) you can get the following kind of IPs for all sort of Operations:

  • Local (RFC1918) IPv4
  • Localhost/Loopback IPv6 (::1)
  • Link-Local IPv6 (fe80::)
  • IPv4 (e.g.: 20.30.40\[.\]50)
  • IPv6 (you all know what an IPv6 looks like)
  • IPv4 with port (e.g.: 20.30.40\[.\]50:12345)
  • IPv4 with the last octet missing (e.g: 20.30.40.x)

So right off the bat, remember that statement about being able to identify events from an unauthorized party by looking for events with “sus” IP addresses? Good luck with that.

But anyway, you have IP addresses, great! They are just random numbers that means absolutely nothing until you enrich them obviously. Only from there would you be able to determine if they’re truly “sus” or not (and even there, more about this later in this post).

So fire up your favorite IP enrichment API and pass it that list of unique IP addresses to get the information you need. Spur.us is a GREAT product when it comes to identifying IP addresses associated with anonymization solutions and/or products (read: VPN). Or you can also flag them based on ASNs that are known to have a bad reputation, are abused by threat actors and/or are just outright known to be associated with VPN providers. Something like IPinfo.io with their free tier can definitely assist with that.

It’s Always Microsoft
#

Another issue you’re going to face when identifying these IP addresses is trying to identify the ones that are related to Microsoft-related services, may it be Office or Azure. Luckily for us, Microsoft has two (2) files you can use to help see if an IP is part of a Office and/or Azure IP range.

The Microsoft Public IP Space:

https://www.microsoft.com/en-us/download/details.aspx?id=53602

The Microsoft Azure IP Ranges and Service Tags — Public Cloud:

https://www.microsoft.com/en-us/download/details.aspx?id=56519

The first one is a CSV file and the second one a JSON because … Because? Yeah, why? At this point I don’t care, all you need to know is that whatever automation you’re planning on building to handle the lookup, you’ll have to handle both CSV and JSON files.

Now that you identified which IPs are associated with Microsoft and marked the UAL events associated with them as such, you think you’re good to go, right? Do you really think I would go through the trouble of writing a blog post at 10 PM on a Monday night if it was the case? Of course not. After doing this exercise, you’ll realize that Microsoft has a lot, and by that I mean, A LOT, of IP addresses that are undocumented (as I call them). By that I mean they aren’t IP addresses that fit in any of the prefixes from the two (2) previous files. So you’re basically back to IP address enrichment (OrgName, ASN, etc.) to try and filter out these remaining offenders. Because nothing is ever easy with Microsoft.

The Inconsistency is Real
#

Now that you’ve identified all your IP addresses and flagged suspicious and/or malicious events, you think that all is well that ends well, right? Well, not quite.

Now you basically need to dig into these UAL events one-by-one (literally, or not, depending on which road you go down) to try and identify what exactly happened and what are the implications.

To do so, you need to dig into the AuditData field (if you exported the UAL as a CSV) which is just a big JSON blob with all the information related to an event. You’ll start dissecting some events and notice interesting fields such as ApplicationId, SessionId, ClientAppId…? AppAccessContentAPIId? AppAccessContentClientAppId? Why do some of these fields feel like they’re the same, but with a different name?

Because this is exactly what this is. At least, based on my research into two (2) UAL files today which I finally took the time to do. Some of these fields hold the exact same kind of information/value but depending on the Operation type, the fields that are present, used and populated will differ. From what I can see at the very least:

  • ApplicationId, ClientAppId and AppAccessContextClientAppId will either have one of these field populated, but if more than one is, it’ll be the same value
  • AppAccessContextAADSessionId and SessionId don’t seem to have an overlap, it’s either one or the other. But the values you get basically covers the “same” sessions. So for instance, you can have events where the AppAccessContextAADSessionId is set and others where that value is in the SessionId field

At some point (read: when I stop being lazy), I’ll post a small comparation table into these different Operation types and fields on my Github so you can see for yourself. The result isn’t pretty obviously.

Correlation Goes A Long Way
#

Now, remember that statement where if you filter out events from Microsoft IPs, you’re “good-to-go”? Well, I’m going to confuse you even more.

What I often see in my BECs is the threat actor logging in to the account through either OfficeHome (which is portal

\[.\]

office

\[.\]

com) or Office 365 Exchange Online (which should be outlook

\[.\]

office

\[.\]

com). In instances where the AppId points to OfficeHome, you may also get FilePreviewed and FileAccessed events. Which, from what I remember in my previous testing, would be because of these “last modified”, “last accessed”, etc. files that are displayed in your Office portal when you log in. You’ll notice that these events are actually associated with Microsoft-related IPs. However, if you look at the CreationDate for those, and the User-Agent, you can actually associate them with UserLoggedIn events for the OfficeHome AppId.

So a good strategy in identifying those, because I should at least give some tips and tricks here and not just baseless hate, is having your filters set for the AzureActiveDirectoryStsLogon record types (UserLoggedIn is part of it) and the SharePointFileOperation (which FilePreviewed and FileAccessed are part of). From there, order the events in a chronological order and if you see any login events with the same CreationDate as FilePreviewed and FileAccessed events, confirm that the User-Agent field is the same for these 2–3 Operation type of events. And if they are, you can cluster these events in the batch generated by the threat actor.

And some obviously bad events, such as the threat actor “installing” (read: consenting) to an application in Azure (e.g.: eM Client, PERFECTDATA, etc.), actually comes from Microsoft-related IP addresses, when they have one. One of the UAL I looked at today just don’t have any IP address associated with these. So if your analysis is based on event identification through IP address enrichment, you’ll end up missing those.

Ah, and don’t forget these events from IPv4 addresses with port (20.30.40

\[.\]

50:12345) … you don’t want to miss those either.

Okay, UAL is Crap. Now What?
#

Despite everything, and because of everything, the UAL still remains honestly the best source of information you can have when investigating BECs. Assuming:

  • They are enabled (look at this post from NathanMcNulty on his website: https://blog.nathanmcnulty.com/azure-automation-advanced-auditing/)
  • The proper auditing configuration is in place (refer to Nathan’s blog post above as well and/or his tweets)
  • You’re ready to spend a̶ ̶h̶u̶g̶e̶ ̶a̶m̶o̶u̶n̶t̶ ̶o̶f̶ ̶t̶i̶m̶e̶ small amount of time parsing it, enriching it and reviewing it

For everything else, or if you don’t have the time nor resources to do the above, the best combo you can use right now is the Microsoft-Extractor-Suite from Invictus Incident Response.

GitHub - invictus-ir/Microsoft-Extractor-Suite: A PowerShell module for acquisition of data from…
_A PowerShell module for acquisition of data from Microsoft 365 and Azure for Incident Response and Cyber Security…_github.com

And the Microsoft-Analyzer-Suite (which uses MES UAL output) from evil3ad79 (https://x.com/Evild3ad79):

GitHub - evild3ad/Microsoft-Analyzer-Suite: A collection of PowerShell scripts for analyzing data…
_A collection of PowerShell scripts for analyzing data from Microsoft 365 and Microsoft Entra ID …_github.com

If you are a SMB, an organization with little to no resources for dealing with BEC or even an Analyst with not a lot of time to pour into investigating this, the MES and MAS combo can basically save you a whole lot of time.

Obviously, if your investigations requires more analysis in order to fully identify and understand what happen, you’ll still have to dig into the UAL, it can’t be avoided.

/Rant
#

And that’s the end of my rant for tonight. Special thanks to DylanInfoSec (https://x.com/DylanInfosec) who actually pushed me to write this blog post. Give him a follow, alongside everyone else I tagged and/or mentioned in this post. They’re all awesome human beings, amazing at what they do and I promise you’ll learn so much from their posts it’s crazy.

https://x.com/DylanInfosec/status/1868848348876448043

Joking aside for a moment, I wouldn’t be able to investigate BECs properly without the UAL and I learn something new about them every single time. So if you have the time and curiosity, I highly suggest you start digging into the UAL and do research of your own. The more UALs you go through, the better you’ll get at reviewing them and the faster you’ll become as well. As with pretty much everything in life I guess. Grunt work is best work!

PS: I may be doing more blog posts about the UAL in the future so … stay tuned?