Firmar scripts PowerShell Link to heading
- [Parte 1 de 2]: Hardening en la política de ejecución
- [Parte 2 de 2]: Entidad de certificación CA (ADCS), despliegue de certificado vía GPO e integridad de firma
Por motivos de seguridad Windows PowerShell establece unas políticas de ejecución de scripts. Con el fin de evitar posibles ejecuciones de scripts no deseadas. Para poder ejecutar scripts en PowerShell sin problemas, se tendrá que cambiar la política de ejecución (ExecutionPolicy). Por defecto no están definidas y vienen deshabilitadas (Restricted) para todos los scopes.
En un escenario en el que formemos parte de un dominio y deseemos ejecutar scripts PowerShell para la realización de tareas en los endpoints o servidores del parque de equipos de la organización. En la mayoría de los casos me encuentro con la “solución” sencilla y poco idónea. Se trata de aplicar un GPO estableciendo la política de ejecución en modo Unrestricted en las máquinas afectadas. Esto deja vía libre a cualquier usuario para que pueda comprometer la máquina sin ningún tipo de restricción.
Aplicar un hardening en la política de ejecución de scripts PowerShell Link to heading
Lo más correcto en estos casos sería aplicar esta GPO en un modo AllSigned y firmar con un certificado de confianza todos los scripts que vayan a ser ejecutados aplicando así un hardening en la política de ejecución de scripts de forma que sean seguros y confiables en entornos corporativos.
Si disponemos de una PKI de una entidad de certificación ADCS (Active Directory Certificate Services) podremos generar un certificado específico para este fin y propagar este certificado a través de GPO.
Para los siguientes ejemplos usaré un certificado autofirmado.
Modos de la política de ejecución (ExecutionPolicy):
| Modo | Comportamiento |
|---|---|
| Restricted | Bloquea todos los scripts en PowerShell; las tareas deben ejecutarse de forma interactiva. Política por defecto en clientes Windows |
| Unrestricted | Ejecuta cualquier script sin restricciones. Muestra advertencia al ejecutar uno sin firmar |
| RemoteSigned | Permite ejecutar scripts locales sin firmar, pero los paquetes descargados deben estar firmados. Para ejecutar scripts descargados sin firmar es necesario Unblock-File. Política por defecto en Windows Server |
| AllSigned | Solo permite ejecutar paquetes y scripts firmados digitalmente por un publicador de confianza, incluidos los scripts locales |
| Bypass | Similar a Unrestricted pero sin alertas. Usado en integraciones de PowerShell con otras aplicaciones que tienen su propio modelo de seguridad |
| Undefined | No se establece explícitamente ninguna directiva. Por defecto se aplica Restricted |
| Default | Establece la política predeterminada: Restricted en clientes Windows, RemoteSigned en Windows Server |
Tipos de ámbitos de la política de ejecución (Scopes):
| Scope | Alcance |
|---|---|
| MachinePolicy | Establecido por GPO para todos los usuarios de la máquina |
| UserPolicy | Establecido por GPO para el usuario actual de la máquina |
| Process | Afecta solo a la sesión actual de PowerShell |
| CurrentUser | Afecta solo al usuario actual |
| LocalMachine | Alcance predeterminado: afecta a todos los usuarios de la máquina |
El bypass anula este hardening
Set-ExecutionPolicy Bypass -Scope Process,powershell -ExecutionPolicy Bypasso usarcmd /c powershell ...permiten saltarse cualquier policy configurada aquí. ExecutionPolicy es un freno para usuarios honestos, no un mecanismo de seguridad real. Para hardening efectivo, combínalo con AppLocker, WDAC o Constrained Language Mode.
Referencia: Get-ExecutionPolicy y Set-ExecutionPolicy
Get-ExecutionPolicy -List
Set-ExecutionPolicy AllSigned -scope LocalMachine -Force

Figura 1: Políticas de ejecución de scripts PowerShell.
Bypass de la política de ejecución de un solo script Link to heading
En el caso de que las políticas de ejecución estén en un modo Undefined y por lo tanto es como si estuvieran en Restricted. Si queremos ejecutar un script en esa misma sesión o contexto de ejecución podemos usar el modo Bypass.
PowerShell.exe -ExecutionPolicy Bypass -File \.MyScript.ps1
También sería lo mismo.
powershell -ep Bypass .\MyScript.ps1

Figura 2: Bypass para la ejecución de un solo script.
Firmar un script PowerShell Link to heading
Referencia: Set-AuthenticodeSignature
Firmar con un certificado del almacén de certificados local Link to heading
$cert = Get-ChildItem -Path Cert:\CurrentUser\My -CodeSigningCert
Set-AuthenticodeSignature -FilePath MyScript.ps1 -Certificate $cert

Figura 3: Firmar con un certificado del almacén local.
Firmar un script usando un certificado de un archivo PFX Link to heading
$cert = Get-PfxCertificate -FilePath C:\Certs\MySign.pfx
Set-AuthenticodeSignature -FilePath MyScript.ps1 -Certificate $cert

Figura 4: Firmar usando un certificado .pfx.
Agregar una firma que incluya la autoridad de certificación raíz (CA) Link to heading
$cert = Get-PfxCertificate -FilePath C:\Certs\MySign.pfx
Set-AuthenticodeSignature -FilePath MyScript.ps1 -Certificate $cert -IncludeChain All -TimestampServer "http://timestamp.globalsign.com/scripts/timstamp.dll"
- IncludeChain: Incluye todas las cadenas de confianza de la autoridad raíz.
- TimeStampServer: Agrega una marca de tiempo a la firma. Esto evita que el script falle cuando caduque el certificado.

Figura 5: Agregar una firma que incluya la autoridad raíz.
Obtener información de la firma de un script firmado Link to heading
Referencia: Get-AuthenticodeSignature
Get-AuthenticodeSignature .\MyScript.ps1 | Format-List *

Figura 6: Obtener información de la firma de un script firmado.
Crear un certificado autofirmado para realizar pruebas Link to heading
Referencia: New-SelfSignedCertificate
New-SelfSignedCertificate -FriendlyName "Zona System ejemplo firma de código" -CertStoreLocation Cert:\CurrentUser\My -Subject "Zona System" -Type CodeSigningCert

Figura 7: Crear certificado autofirmado para pruebas.
Ejemplo de ejecución de script firmado Link to heading
Estableciendo la política de ejecución de scripts de PowerShell en AllSigned.

Figura 8: Ejemplo de ejecución de script firmado.
Saludos!