#Requires -Version 5.1 <# .SYNOPSIS Vector 1 - Ciclo encadenado en UN solo comando. .DESCRIPTION Encadena las fases del Vector 1 para poder disparar el ejercicio completo con una sola orden, tanto desde el activo como desde la GPO: Vector1Plantar = generar canarios + plantarlos (fase de siembra) Vector1Ciclo = generar + plantar + exfiltrar por HTTPS (demostracion de laboratorio) IMPORTANTE, y es la diferencia de fondo entre las dos: el ejercicio REAL necesita la siembra y la exfiltracion SEPARADAS en el tiempo. Si se exfiltra un canario que se ha creado dos segundos antes, no hay ventana de observacion y el ejercicio no mide nada. 'Vector1Ciclo' existe para el laboratorio y para demostrar la tuberia de extremo a extremo, y avisa de ello en su salida. Cada paso se ejecuta en un proceso hijo, igual que cuando los lanza el stager, y el ciclo se detiene en el primer fallo: no tiene sentido exfiltrar si el plantado fallo. .PARAMETER ScopePath Ruta al alcance ya descargado (scope.vector1.json). .PARAMETER SoloPlantar Solo generar y plantar. Es el modo correcto para el ejercicio real. .PARAMETER Execute Segunda llave, igual que en el resto del arnes. Sin ella, todo corre en simulacion. .EXAMPLE .\Invoke-Vector1Ciclo.ps1 -ScopePath .\scope.vector1.json -Execute #> [CmdletBinding()] param( [Parameter(Mandatory)][string]$ScopePath, [switch]$SoloPlantar, [switch]$Regenerar, [switch]$Execute ) $ErrorActionPreference = 'Stop' $hbin = $PSScriptRoot if (-not (Test-Path -LiteralPath $ScopePath)) { throw "No existe el alcance indicado: $ScopePath" } $pasos = @( @{ Nombre = 'Generar canarios'; Script = 'New-Canaries.ps1'; Args = @(); AceptaExecute = $false } @{ Nombre = 'Plantar canarios'; Script = 'Invoke-CanaryPlant.ps1'; Args = @(); AceptaExecute = $true } ) if (-not $SoloPlantar) { $pasos += @{ Nombre = 'Exfiltrar (HTTPS burst)'; Script = 'Invoke-ExfilSim.ps1'; Args = @('-Mode', 'https-burst'); AceptaExecute = $true } } Write-Host '' Write-Host '=== Vector 1: ciclo encadenado ===' -ForegroundColor Cyan Write-Host "Alcance: $ScopePath" Write-Host "Modo : $(if ($Execute) { 'EJECUCION REAL' } else { 'SIMULACION (falta -Execute)' })" if (-not $SoloPlantar) { Write-Host '' Write-Host 'AVISO: este ciclo comprime las fases. En el ejercicio real, la siembra y la' -ForegroundColor Yellow Write-Host 'exfiltracion se lanzan en momentos distintos para que exista ventana de observacion.' -ForegroundColor Yellow Write-Host 'Para la siembra sola, usa -SoloPlantar (accion Vector1Plantar).' -ForegroundColor Yellow } Write-Host '' # El paso de generacion significa "asegurar que existen", no "regenerar siempre". Si ya # hay un juego de canarios se reutiliza: regenerarlo crearia IDs y contenidos nuevos y # dejaria mezclados los antiguos, que siguen plantados en los activos. $saltarGeneracion = $false if (-not $Regenerar) { try { $sc = Get-Content -LiteralPath $ScopePath -Raw | ConvertFrom-Json $mr = [string]$sc.manifest_root if ($mr -and [System.IO.Path]::IsPathRooted($mr) -and (Test-Path -LiteralPath $mr)) { $ult = Get-ChildItem -LiteralPath $mr -Filter 'canaries-*.jsonl' -File -ErrorAction SilentlyContinue | Sort-Object LastWriteTime | Select-Object -Last 1 if ($ult) { $saltarGeneracion = $true } } } catch { } } $fallos = 0 foreach ($p in $pasos) { if (($p.Script -eq 'New-Canaries.ps1') -and $saltarGeneracion) { Write-Host ' (ya existe un juego de canarios: se reutiliza; usa -Regenerar para rehacerlo)' -ForegroundColor DarkGray continue } $scriptPath = Join-Path $hbin ([string]$p.Script) if (-not (Test-Path -LiteralPath $scriptPath)) { throw "Falta $($p.Script) en $hbin" } Write-Host ("--- {0} ({1})" -f $p.Nombre, $p.Script) -ForegroundColor Cyan $childArgs = @('-NoProfile', '-ExecutionPolicy', 'Bypass', '-File', $scriptPath, '-ScopePath', $ScopePath) + @($p.Args) # Solo se pasa -Execute a los scripts que lo declaran: New-Canaries.ps1 no lo tiene. if ($Execute -and ($p.AceptaExecute -ne $false)) { $childArgs += '-Execute' } & powershell.exe @childArgs if ($LASTEXITCODE -ne 0) { $fallos++ Write-Host (" FALLO en '{0}' (exit {1}): se detiene el ciclo" -f $p.Nombre, $LASTEXITCODE) -ForegroundColor Red break } Write-Host '' } Write-Host '===================================' -ForegroundColor Cyan if ($fallos -eq 0) { Write-Host 'Ciclo del Vector 1 completado sin errores.' -ForegroundColor Green } else { Write-Host 'Ciclo del Vector 1 detenido por un fallo.' -ForegroundColor Red exit 1 }