{"id":303,"date":"2026-03-17T09:00:00","date_gmt":"2026-03-17T09:00:00","guid":{"rendered":"http:\/\/justruss.tech\/index.php\/2025\/04\/15\/living-off-the-land-at-scale-hunting-attackers-who-blend-into-your-own-tools-2\/"},"modified":"2026-05-15T10:34:55","modified_gmt":"2026-05-15T10:34:55","slug":"living-off-the-land-at-scale-hunting-attackers-who-blend-into-your-own-tools-2","status":"publish","type":"post","link":"https:\/\/justruss.tech\/index.php\/2026\/03\/17\/living-off-the-land-at-scale-hunting-attackers-who-blend-into-your-own-tools-2\/","title":{"rendered":"Living Off the Land at Scale: Hunting Attackers Who Blend Into Your Own Tools"},"content":{"rendered":"<p>The 2025 CrowdStrike Threat Hunting Report found that 81% of interactive intrusions used no malware at all. Attackers use tools already present on every Windows system, PowerShell, WMI, PsExec, net.exe, nltest.exe, certutil.exe, to move through the environment. The challenge for defenders is that these tools run thousands of times per day for completely legitimate reasons. Finding the malicious use requires understanding context, sequence, and baseline rather than just looking for the tool name.<\/p>\n<p>This technique is called Living off the Land (LOTL) and it is the primary reason that signature-based detection fails against sophisticated operators.<\/p>\n<h3>Why LOTL is so hard to detect<\/h3>\n<p>When an attacker runs nltest.exe \/domain_trusts to enumerate trust relationships, the event log shows nltest.exe with the \/domain_trusts argument. When a legitimate domain administrator runs the same command to troubleshoot a trust issue, the event log shows exactly the same thing. The bytes, the process name, the arguments, identical. Detection requires answering: who ran it, from what machine, at what time, in what sequence, and is that combination normal for this environment?<\/p>\n<pre>\/\/ Common LOTL reconnaissance sequence (attacker perspective for detection context)\n\/\/ Phase 1: Domain enumeration\nnltest.exe \/domain_trusts \/\/ enumerate domain trusts\nnet group \"Domain Admins\" \/domain \/\/ list domain admin members\nnet group \"Enterprise Admins\" \/domain \/\/ list enterprise admin members\nwhoami \/all \/\/ current privileges\nipconfig \/all \/\/ network configuration\n\n\/\/ Phase 2: Host enumeration\nnet view \/domain \/\/ list machines in domain\narp -a \/\/ local ARP cache (nearby hosts)\nGet-ADComputer -Filter * -Properties * \/\/ full AD computer enumeration\n\n\/\/ Phase 3: Credential access preparation\nquery user \/\/ find logged-in users\ntasklist \/v \/\/ look for AV\/EDR processes\nreg query HKLM\\SOFTWARE\\Microsoft\\... \/\/ enumerate installed software\n\n\/\/ Each of these individually is normal\n\/\/ ALL of them from the same account in a 10-minute window is an attacker<\/pre>\n<h3>Detection approach 1: command sequence correlation<\/h3>\n<pre>\/\/ Splunk: find accounts running multiple recon commands in a short window\nindex=wineventlog EventCode=4688 earliest=-2h\n| eval recon_command=case(\n match(Process_Command_Line, \"(?i)nltest.*domain_trusts\"), \"domain_trust_enum\",\n match(Process_Command_Line, \"(?i)net.*group.*domain.admin\"), \"domain_admin_enum\",\n match(Process_Command_Line, \"(?i)net.*group.*enterprise.admin\"), \"enterprise_admin_enum\",\n match(Process_Command_Line, \"(?i)whoami.*\/all\"), \"whoami_privs\",\n match(Process_Command_Line, \"(?i)net\\s+view\"), \"network_enum\",\n match(Process_Command_Line, \"(?i)arp\\s+-a\"), \"arp_enum\",\n match(Process_Command_Line, \"(?i)Get-ADComputer\"), \"ad_computer_enum\",\n match(Process_Command_Line, \"(?i)Get-ADUser.*Filter.*\\*\"), \"ad_user_enum\",\n match(Process_Command_Line, \"(?i)tasklist.*\\\/v\"), \"process_list\",\n true(), null()\n)\n| where isnotnull(recon_command)\n| bin _time span=10m\n| stats\n dc(recon_command) AS distinct_recon_types,\n values(recon_command) AS commands_used,\n values(ComputerName) AS source_hosts\n by _time, Account_Name\n| where distinct_recon_types &gt;= 3\n| sort -distinct_recon_types<\/pre>\n<h3>Detection approach 2: unusual LOLBin usage patterns<\/h3>\n<pre>\/\/ certutil.exe is used by attackers to download files\n\/\/ Legitimate use: certificate management, no external URLs\nindex=sysmon EventCode=1 earliest=-24h\n Image=\"*\\\\certutil.exe\"\n| eval is_suspicious=if(\n match(CommandLine, \"(?i)(-urlcache|-decode|-encode).*http\"),\n \"HIGH\",\n if(match(CommandLine, \"(?i)-decode\"), \"MEDIUM\", \"LOW\")\n)\n| where is_suspicious != \"LOW\"\n| table _time, ComputerName, Account_Name, CommandLine, is_suspicious<\/pre>\n<pre>\/\/ mshta.exe should never load external URLs in a healthy environment\nindex=sysmon EventCode=1\n Image=\"*\\\\mshta.exe\"\n CommandLine=\"*http*\"\n| table _time, ComputerName, Account_Name, CommandLine\n\n\/\/ regsvr32.exe used with \/s \/u \/i for COM scriptlet execution\n\/\/ The \"squiblydoo\" technique uses external URLs\nindex=sysmon EventCode=1\n Image=\"*\\\\regsvr32.exe\"\n (CommandLine=\"*scrobj*\" OR CommandLine=\"*http*\")\n| table _time, ComputerName, Account_Name, CommandLine<\/pre>\n<h3>Detection approach 3: parent-child process context<\/h3>\n<pre>\/\/ WMI spawning network tools is a classic lateral movement pattern\n\/\/ WmiPrvSE.exe should not spawn cmd.exe with net.exe commands\nindex=sysmon EventCode=1 earliest=-24h\n| eval ParentName=lower(mvindex(split(ParentImage, \"\\\\\"), -1))\n| eval ChildName=lower(mvindex(split(Image, \"\\\\\"), -1))\n| where ParentName=\"wmiprvse.exe\" AND\n ChildName IN (\"cmd.exe\",\"powershell.exe\",\"net.exe\",\"nltest.exe\",\n \"ping.exe\",\"whoami.exe\",\"ipconfig.exe\")\n| table _time, ComputerName, Account_Name, ParentImage, Image, CommandLine<\/pre>\n<pre>\/\/ PsExec lateral movement signature\n\/\/ PsExec creates a specific named pipe and service\nindex=sysmon (EventCode=17 OR EventCode=18) earliest=-24h\n PipeName=\"\\PSEXESVC\"\n| table _time, ComputerName, Image, PipeName\n\n\/\/ Also watch for the PSEXESVC service being created\nindex=wineventlog EventCode=7045\n Service_Name=\"PSEXESVC\"\n| table _time, ComputerName, Service_File_Name<\/pre>\n<h3>Detection approach 4: BloodHound-style enumeration patterns<\/h3>\n<pre>\/\/ BloodHound\/SharpHound generates specific LDAP query patterns\n\/\/ It queries for ALL users, ALL computers, ALL groups, ALL trusts in rapid succession\n\/\/ This is visible as a burst of LDAP activity in network logs\n\n\/\/ Zeek ldap.log (if you have LDAP logging enabled)\ncat \/opt\/zeek\/logs\/current\/*.log | grep -i \"ldap\" | \\\n python3 -c \"\nimport sys, json\nfrom collections import defaultdict\nqueries = defaultdict(list)\nfor line in sys.stdin:\n try:\n rec = json.loads(line)\n if 'base_object' in rec:\n queries[rec.get('id.orig_h', '')].append(rec.get('filter', ''))\n except:\n pass\nfor src, q_list in queries.items():\n if len(q_list) &gt; 20:\n print(f'{src}: {len(q_list)} LDAP queries in window')\n for q in q_list[:5]:\n print(f' {q}')\n\"<\/pre>\n<pre>\/\/ Windows Event ID 4662: LDAP queries against sensitive AD attributes\n\/\/ BloodHound queries for specific properties that generate 4662 events\nindex=wineventlog EventCode=4662 earliest=-1h\n| rex field=_raw \"Properties:\\s+(?P&lt;props&gt;[^\\r\\n]+)\"\n| eval bloodhound_indicator=if(\n \/\/ SID History, AdminCount, servicePrincipalName - all BloodHound targets\n match(props, \"bf967aba|bf967a9c|f3a64788|028ebdfa\"),\n \"potential_bloodhound\", null()\n)\n| where isnotnull(bloodhound_indicator)\n| bin _time span=5m\n| stats count AS ldap_ops, dc(ObjectName) AS unique_objects\n by _time, SubjectUserName, IpAddress\n| where ldap_ops &gt; 50\n| sort -ldap_ops<\/pre>\n<h3>Building a LOTL baseline for your environment<\/h3>\n<pre>\/\/ The most important thing you can do: build a 30-day baseline\n\/\/ of every LOLBin execution in your environment\n\n\/\/ Step 1: collect all process creation events for 30 days\n\/\/ Step 2: for each LOLBin, document:\n\/\/ - which accounts run it\n\/\/ - from which machines\n\/\/ - at what hours\n\/\/ - with what parent processes\n\/\/ - with what argument patterns\n\n\/\/ Step 3: any deviation from baseline is an anomaly worth investigating\n\npython3 &lt;&lt; EOF\n# Example: analyse your Sysmon CSV export for LOLBin patterns\nimport csv\nfrom collections import defaultdict\n\nlolbins = [\"certutil.exe\",\"mshta.exe\",\"regsvr32.exe\",\"wscript.exe\",\n \"cscript.exe\",\"msiexec.exe\",\"rundll32.exe\",\"nltest.exe\",\n \"net.exe\",\"net1.exe\",\"whoami.exe\",\"ipconfig.exe\"]\n\npatterns = defaultdict(list)\n\nwith open(\"sysmon_proc_create.csv\") as f:\n for row in csv.DictReader(f):\n exe = row.get(\"Image\",\"\").lower().split(\"\\\\\")[-1]\n if exe in lolbins:\n key = (exe, row.get(\"Account_Name\",\"\"), row.get(\"ParentImage\",\"\"))\n patterns[key].append(row.get(\"CommandLine\",\"\"))\n\nprint(\"LOLBin patterns in your environment (baseline):\")\nfor (exe, account, parent), cmds in sorted(patterns.items(), key=lambda x: -len(x[1])):\n print(f\"\\n{exe} | Account: {account} | Parent: {parent.split('\\\\\\\\')[-1]}\")\n print(f\" Occurrences: {len(cmds)}\")\n print(f\" Sample commands: {cmds[0][:100]}\")\nEOF<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>81% of interactive intrusions in 2025 involved no malware. Attackers use your own administrative tools against you. Detecting this requires knowing what normal looks like well enough to spot the subtle differences. This is how to build that detection.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[13],"tags":[],"class_list":["post-303","post","type-post","status-publish","format-standard","hentry","category-threat-hunting"],"_links":{"self":[{"href":"https:\/\/justruss.tech\/index.php\/wp-json\/wp\/v2\/posts\/303","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/justruss.tech\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/justruss.tech\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/justruss.tech\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/justruss.tech\/index.php\/wp-json\/wp\/v2\/comments?post=303"}],"version-history":[{"count":1,"href":"https:\/\/justruss.tech\/index.php\/wp-json\/wp\/v2\/posts\/303\/revisions"}],"predecessor-version":[{"id":321,"href":"https:\/\/justruss.tech\/index.php\/wp-json\/wp\/v2\/posts\/303\/revisions\/321"}],"wp:attachment":[{"href":"https:\/\/justruss.tech\/index.php\/wp-json\/wp\/v2\/media?parent=303"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/justruss.tech\/index.php\/wp-json\/wp\/v2\/categories?post=303"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/justruss.tech\/index.php\/wp-json\/wp\/v2\/tags?post=303"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}