Query Details

Living Off Trusted Sites

LOTS Usage

Query

// THIS QUERY IS ONLY FOR HUNTING, NOT FOR DETECTION. IT WILL GENERATE TO MUCH FPs.
// The query levarages the Living Off Trusted Sites from: https://lots-project.com/
let LOTS = externaldata(Data:string )[@"https://raw.githubusercontent.com/Bert-JanP/Hunting-Queries-Detection-Rules/main/Defender%20For%20Endpoint/Living%20Off%20The%20Land/lots-project.txt"] with (format="txt", ignoreFirstRecord=True);
// To finetune your hunt the whitelist below can be used. Use lowercase for the has_any to work.
let WhitelistedDomains = dynamic(['yourdomain.com', 'yoursharepoint.sharepoint.com']);
// Parse Input into Fields
let LotsParsed = LOTS
| where not(Data startswith "#")
| extend Fields = split(Data, ",")
| extend Website = Fields[0], Tags = Fields[1], ServiceProvider = Fields[2];
// Collect all unique domains for better performance.
let LotsDomains = LotsParsed
// Parse Websites to Lower to ensure that has_any can be used.
| extend WebsiteToLower = tolower(tostring(Website))
| distinct WebsiteToLower;
DeviceNetworkEvents
| where RemoteUrl has_any (LotsDomains)
// Filter whitelist.
| where not(RemoteUrl has_any (WhitelistedDomains))
// All upcomming lines below are used to create results which can be valueble. There is some explanation, but limited. If you want more info send me a message.
// The lines below are used to extract the domain -> <domain>.<tld> for good statistics.
// Method 1:
// Parse URL to get the host, if this can be parsed. Otherwise method 2 is used.
| extend ParseURL = parse_url(RemoteUrl)
| extend DomainParseURL = tostring(parse_json(ParseURL).Host)
// Method 2:
// for all domains that could not be parsed via the parseURL
| extend SplitUrl = split(RemoteUrl, ".")
// Combine splitted results and merge results from method one into the domain field.
| extend DomainParsed = iff(isempty(DomainParseURL), tostring(strcat( SplitUrl[array_length(SplitUrl) - 2] , ".", SplitUrl[array_length(SplitUrl) -1])), "na")
| extend SplitDomainParseURL = split(DomainParseURL, ".")
| extend Domain = iff(DomainParsed == "na", tostring(strcat( SplitDomainParseURL[array_length(SplitDomainParseURL) - 2] , ".", SplitDomainParseURL[array_length(SplitDomainParseURL) -1])), DomainParsed)
// Normal query continues, parsing is over.
// Summarize results. Based on the summarize you can investigate further.
| summarize TotalCount = count(), URLs = make_set(RemoteUrl), Devices = make_set(DeviceName), RemotePorts = make_set(RemotePort), InitiatingFiles = make_set(InitiatingProcessFileName) by Domain
// Some additional field for statistics
| extend TotalDevices = array_length(Devices), UniqueURLs = array_length(URLs), TotalInitiatingFiles = array_length(InitiatingFiles)
| sort by TotalCount
// Project all fields
| project Domain, TotalCount, UniqueURLs, TotalDevices, TotalInitiatingFiles, RemotePorts, URLs, Devices, InitiatingFiles

About this query

Explanation

This query is designed for threat hunting, specifically to identify suspicious activity involving the use of legitimate websites by attackers. The concept is known as "Living Off Trusted Sites" (LOTS), where attackers use well-known, legitimate domains for malicious activities like phishing or data exfiltration to avoid detection.

Here's a simplified breakdown of the query:

  1. Data Source: The query uses a list of domains from a text file hosted on GitHub, which originates from the LOTS project. This list includes domains that attackers might exploit.

  2. Whitelisting: You can specify domains that are safe and should be ignored by the query to reduce false positives.

  3. Domain Parsing: The query processes network events to extract domain names from URLs. It uses two methods to ensure accurate domain extraction, even if the URL format varies.

  4. Filtering: It filters out any network events involving whitelisted domains and focuses on rare or unusual domains within your organization.

  5. Summarization: The query summarizes the data by counting occurrences of each domain, listing the URLs, devices, ports, and initiating files involved. This helps in identifying patterns or anomalies that may warrant further investigation.

  6. Output: The results include statistics like the number of unique URLs, devices, and initiating files associated with each domain. This information can be used to prioritize further investigation.

Overall, this query helps identify potentially malicious use of legitimate domains within your network, but it is not meant to be used as a detection rule due to the high likelihood of false positives. Instead, it serves as a starting point for deeper threat hunting activities.

Details

Bert-Jan Pals profile picture

Bert-Jan Pals

Released: December 1, 2024

Tables

DeviceNetworkEvents

Keywords

DataDevicesDomainInitiatingFilesRemotePortsURLsWebsite

Operators

externaldatawithletdynamicwherenotstartswithextendsplittostringtolowerdistincthas_anyparse_urlparse_jsoniffisemptystrcatarray_lengthsummarizecountmake_setsortproject

Actions

GitHub