Forensics

Hunting Living-off-the-Land Binaries on Windows with KQL

Por Equipe Basilisk ·

Production-ready KQL queries for Microsoft Defender and Sentinel to hunt LOLBin abuse from rundll32, mshta, and certutil in real environments.

A capable attacker does not need to drop a Microsoft-signed binary on the victim's disk: they use what is already there. Rundll32, mshta, certutil, bitsadmin, and regsvr32 are legitimate tools Windows ships signed by Microsoft itself, which leads many EDRs to treat their executions as noise. The Basilisk team spent the last six months reviewing 47 incidents across enterprise customers, and 31 of them had at least one LOLBin somewhere in the kill chain. This post delivers the KQL queries we run in Microsoft Defender for Endpoint and Sentinel to turn those executions into actionable detections without drowning the SOC in false positives.

Before writing any rule, you must understand the environment baseline. We run a broad hunt against DeviceProcessEvents grouping by FileName and counting executions over 30 days per host, surfacing what is normal in that fleet. At a retail customer with 8,200 endpoints, mshta.exe showed up on just 0.4% of machines, all marketing boxes running a legacy report. That means any mshta execution outside that group earns a P2 alert. This statistical-rarity approach is the bedrock of modern hunting and lines up with what we cover in Threat Hunting with Sigma and Elastic: From Indicator to Detection Rule, where we walk from raw indicator to Git-versioned Sigma rule.

The base query we recommend for rundll32 with suspicious command line is: DeviceProcessEvents | where FileName =~ 'rundll32.exe' | where ProcessCommandLine has_any ('javascript:', 'shell32.dll,Control_RunDLL', 'mshtml,RunHTMLApplication', '.cpl,', 'url.dll,OpenURL') | where InitiatingProcessFileName !in~ ('explorer.exe', 'svchost.exe') | project Timestamp, DeviceName, AccountName, ProcessCommandLine, InitiatingProcessFileName. Tested against MITRE ATT&CK T1218.011, it caught 9 of 10 Cobalt Strike beacon executions in SMB pivot mode. Fine tuning comes from excluding legitimate parent processes per department, something we document in Adversary Emulation with Caldera and MITRE ATT&CK in a Corporate Lab.

Certutil deserves its own chapter. It is the attacker's Swiss Army knife because it downloads files (-urlcache), decodes base64 (-decode), and computes hashes. Our hunting query is: DeviceProcessEvents | where FileName =~ 'certutil.exe' | where ProcessCommandLine has_any ('-urlcache', '-decode', '-decodehex', '-ping', 'http://', 'https://') | where ProcessCommandLine !contains 'CertificateServices' | extend Stage = case(ProcessCommandLine has '-decode', 'staging', ProcessCommandLine has 'http', 'download', 'recon'). Through 2025 we saw certutil used as a second stage in campaigns starting with macro phishing, a flow described from the offensive side in Simulated Initial Access: Macros, LNK and ISO in an Isolated Windows 11 Lab that blue teams must correlate against AD event 4688.

For mshta and regsvr32 (remote scriptlets, T1218.010) the logic shifts. Mshta executing a URL is almost always malicious outside help systems, so DeviceProcessEvents | where FileName =~ 'mshta.exe' | where ProcessCommandLine matches regex @'https?://|\\\\[A-Za-z0-9.-]+\\' yields a false positive rate below 2% in most fleets we measured. Combine it with DeviceNetworkEvents in the same 60-second window joining on DeviceId and ReportId to confirm the connection actually came from the suspicious process. This kind of multi-table correlation separates hunting from log mining and connects to Lateral Movement in the Lab: SMB, WMI and WinRM with a Detection Focus, where attackers chain LOLBins through remote WMI.

Bitsadmin, msiexec /i http, and remote wmic format are the trio that most often slips past default rules. For msiexec, our favorite heuristic uses ProcessVersionInfoOriginalFileName to detect renamed binaries, something tools like Sliver do by default. See the discussion in Building C2 Infra with Sliver in an Isolated Lab for Defensive Research for the operator perspective. In Sentinel, we materialize these hunts as Analytics Rules with entity mapping on Account and Host, 5-minute frequency, and 1-hour per-entity suppression, which keeps the noise tractable. We always export the logic to Sigma for SIEM portability, the same philosophy from Purple Team in Practice: Building a Red vs Blue Feedback Loop.

Closing with immediate practice: run this in your tenant today: DeviceProcessEvents | where Timestamp > ago(30d) | where FileName in~ ('rundll32.exe','mshta.exe','certutil.exe','regsvr32.exe','bitsadmin.exe','msiexec.exe') | summarize Total=count(), Hosts=dcount(DeviceName) by FileName, bin(Timestamp, 1d) | order by Timestamp desc. The output is your baseline map. Anything that breaks that pattern by 3 standard deviations becomes a rule candidate. You do not eliminate a LOLBin, you observe it with discipline, and teams that treat the baseline as a living product detect intrusions in hours instead of months.

Nenhum comentário ainda

Seja o primeiro a comentar.

Deixe seu comentário

Entre com sua conta Canverly para comentar. Você pode usar a mesma conta em qualquer site da rede.

Entrar com Canverly