Threat Hunting for AppData Installations
Has it ever occurred to you when installing software why you didn't get prompted for administrator privileges? Many people live under a guise that to install software, they 'need' a privileged account. This isn't always the case. In fact, one of the worlds most popular browsers, Google Chrome (and therefore most of it's Chromium brothers) do not need any special privileges to install.
Why? User-based installations can install to a folder that every user in Windows has: AppData. Software vendors use this because it's a near-guaranteed place that a user will be able to write files to. Not needing any privileges makes it easier to install software, but can come at the cost of security. Adversaries can take advantage of this too.
I mentioned Google Chrome earlier for a specific reason. There is a rise in its derivative - Chromium - being used as a base for writing Potentially Unwanted Applications (PUA). These seem to come modified with extensions pre-installed and while I can't definitively tell you the end goal of these PUA's, I can estimate that tracking user web browsing is likely to be valuable data.
Sadly, it's not only ease of installation that makes the barrier of entry low either. In casual internet browsing, I was able to see Google Ads display one of these PUA's to me:
Hunting for AppData Installations
I ended up clicking on the above advert and installing the associated PUA. Due to its similarity with the Chromium code base, I was not surprised to find Defender allowed the install... a 2 click install I might add. However, the good news is that we now have valuable telemetry.
In the above example, the link prompted me to install a PUA named 'OneStart[.]ai'.
Start with assumptions
By assuming that something is going to get written to AppData for installation, we can start with some rough KQL:
DeviceFileEvents
| where ActionType == "FileCreated"
| where FolderPath contains "AppData" and FolderPath contains "OneStart"
| project FolderPath, FileName
| take 1
Great, we now have a folder structure:
Users\<Username>\AppData\Local\<VendorName>\<SoftwareName>\....
Readers of my blog will know I love using regular expressions (regex), so let's hop over to regex101.com to develop something that matches this pattern and extract useful information:
Above, we can see our capture groups:
We break down by software and vendor name because a vendor may write multiple pieces of software and therefore have subfolders within their root vendor folder.
Yes - we could use KQL string splitting with a combination of other conditions instead of regex; I prefer to see the visualisation in Regex101
Extrapolating useful regex groups into the KQL query:
| extend FolderInfomation=extract_all(@"\\Users\\(.+)\\AppData\\Local\\([^\\]+)\\([^\\]+)", FolderPath) // the regex
| where isnotempty(FolderInfomation)
| extend AppDataUser=tostring(FolderInfomation[0][0])
| extend AppDataVendor=tostring(FolderInfomation[0][1])
| extend AppDataSoftwareName=tostring(FolderInfomation[0][2])
| extend AppDataCombinedPath=strcat(AppDataVendor,":",AppDataSoftwareName)
Building the detection for new AppData installations
Software installations are not commonly composed of one single file. They often need graphics, DLL's and configuration files to support their function. As such, it's possible for us to assume that multiple files are going to be written during an installation.
We can also say with a degree of confidence, that at least one of them will be a '.exe' file. To support our investigation, lets add a column for listing the file extension(s) being written:
| extend FileExtension=tostring(split(FileName, ".")[-1])
Split the file by '.', take the last value and convert it to a string
Tie it all together
| summarize Extensions=make_set(FileExtension), FileWriteCount=count() by DeviceName, AppDataUser, AppDataKey,InitiatingProcessVersionInfoCompanyName, bin(Timestamp, 2m)
| where FileWriteCount > 10
'summarize' is really powerful, as it allows us to aggregate the activity seen. This KQL statement does the following:
BY
The statement after summarize filters to where 10 files have been written within that 2 minute period. - may require fine tuning -
Success?
Our query results show that we've been able to catch potential PUA AppData installations! It also captures legitimate installations:
To tune this, we can focus on AppDataKey or the company name (InitiatingProcessVersionInfoCompanyName) writing the files. I opted for the latter and added the following to the end of my query:
| where InitiatingProcessVersionInfoCompanyName !in~ ('Microsoft Corporation', 'NVIDIA Corporation', 'Google LLC', 'Logitech, Inc.') // add as required
Closing thoughts
The above results show there is a maintenance piece in identifying legitimate software installations, which may not make this KQL viable for a detection. This will be heavily influenced by complexities within an organisations software stack. The detection also relies upon software being installed using the 'assumed' folder structure that we look for within our regular expression.
Using this KQL should be done with the mindset that for as long as users can self-install to AppData, organisations will always have risk. Use this query to support implementing better security controls, such as AppLocker or folder restrictions!
Query:
DeviceFileEvents
| where ActionType == "FileCreated"
| extend FolderInfomation=extract_all(@"\\Users\\(.+)\\AppData\\Local\\([^\\]+)\\([^\\]+)", FolderPath)
| where isnotempty(FolderInfomation)
| extend AppDataUser=tostring(FolderInfomation[0][0])
| extend AppDataVendor=tostring(FolderInfomation[0][1])
| extend AppDataSoftwareName=tostring(FolderInfomation[0][2])
| extend AppDataKey=strcat(AppDataVendor,":",AppDataSoftwareName)
| extend FileExtension=tostring(split(FileName, ".")[-1])
// detection start
| summarize Extensions=make_set(FileExtension), FileWriteCount=count() by DeviceName, AppDataUser, AppDataKey,InitiatingProcessVersionInfoCompanyName, bin(Timestamp, 2m)
| where FileWriteCount > 10
// tuning
| where InitiatingProcessVersionInfoCompanyName !in~ ('Microsoft Corporation', 'NVIDIA Corporation', 'Google LLC', 'Logitech, Inc.')