[P2604] Fase 15: Optimización IA e integración de herramienta candados. Sincronización de bitácoras y actualización de planes de proyecto.

This commit is contained in:
Ricardo Monla
2026-03-19 09:52:29 -03:00
parent 183dbf6fb6
commit 5aa37e7221
138 changed files with 8777 additions and 464 deletions
@@ -0,0 +1,60 @@
# 🧟 W-Zombi: Toolkit de Inyección Lateral para Windows VMs
> Técnica documentada en la bitácora del [25/02/2026](../../bitacoras/2026-02-25.md) (Hito DB01).
## Problema
La consola HTML5/VNC de Proxmox **no soporta copiar/pegar** texto. Esto impide provisionar comandos complejos en VMs Windows recién creadas que aún no tienen SSH.
## Solución
Arquitectura C2 liviana que sortea la limitación:
```
srv-ns8 (10.0.10.8) VM Windows (VNC)
┌──────────────────────┐ ┌──────────────────────┐
│ servidor.rb │ ← HTTP :8000 ── │ zombi.ps1 (loop) │
│ (Ruby / WEBrick) │ │ Consulta activo.ps1 │
│ │ ── payload ────→ │ cada 10 seg │
│ payloads/activo.ps1 │ │ Ejecuta y reporta │
│ (hot-swap por IA) │ ← POST /log ── │ telemetría al server │
└──────────────────────┘ └──────────────────────┘
```
## Uso
### 1. En srv-ns8 (la IA o el operador):
```bash
ruby tools/w-zombi/servidor.rb
```
### 2. En la VM Windows (tipear manualmente en VNC — PowerShell Admin):
```powershell
iwr 10.0.10.8:8000/zombi.ps1 -useb|iex
```
### 3. Cambiar payload activo:
```bash
# Copiar un payload pre-armado
cp tools/w-zombi/payloads/install_ssh.ps1 tools/w-zombi/payloads/activo.ps1
# O la IA modifica activo.ps1 directamente
```
## Estructura
```
tools/w-zombi/
├── servidor.rb ← Servidor HTTP Ruby (WEBrick)
├── README.md ← Este archivo
└── payloads/
├── activo.ps1 ← Payload que ejecuta la VM (hot-swap)
├── install_ssh.ps1 ← Instalar OpenSSH Server nativo
└── sonda.ps1 ← Diagnóstico y relevamiento del sistema
```
## Seguridad
- Servidor **efímero** — solo se levanta durante la operación.
- Solo escucha en la red interna (`10.0.10.x` / `10.0.100.x`).
- Una vez instalado SSH, este mecanismo deja de ser necesario.
+43
View File
@@ -0,0 +1,43 @@
#!/usr/bin/env ruby
require_relative '../lib/wzombi/config'
require_relative '../lib/wzombi/server'
require_relative '../lib/wzombi/command_store'
base = File.expand_path("..", __dir__)
config = WZombi::Config.new(base_path: base)
def help
puts <<~HELP
Uso:
w-zombi start
w-zombi cmd "<comando>"
w-zombi ayuda | -h | -help
Ejemplo ADN:
adn tools w-zombi cmd "ipconfig"
HELP
end
cmd = ARGV[0]
case cmd
when "start"
WZombi::Server.new(config).start
when "cmd"
command = ARGV[1]
if command.nil?
puts "Falta comando"
exit
end
store = WZombi::CommandStore.new(config.cmd_path)
store.update(command)
puts "Comando actualizado: #{command}"
when "ayuda", "-h", "-help", nil
help
else
puts "Comando desconocido"
help
end
@@ -0,0 +1 @@
{"id":"1773805876","cmd":"whoami","status":"pending"}
@@ -0,0 +1 @@
NO_CMD
@@ -0,0 +1 @@
{"id":0,"cmd":""}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,25 @@
require 'json'
module WZombi
class CommandStore
def initialize(path)
@path = path
init_file
end
def init_file
File.write(@path, { id: 0, cmd: "" }.to_json) unless File.exist?(@path)
end
def current
JSON.parse(File.read(@path))
end
def update(cmd)
data = current
data["id"] += 1
data["cmd"] = cmd
File.write(@path, data.to_json)
end
end
end
@@ -0,0 +1,22 @@
module WZombi
class Config
attr_reader :puerto, :base_path
def initialize(base_path:)
@base_path = base_path
@puerto = ENV.fetch("WZ_PORT", 8000).to_i
end
def log_path
File.join(base_path, "data/telemetria.log")
end
def cmd_path
File.join(base_path, "data/cmd.json")
end
def payloads_path
File.join(base_path, "payloads")
end
end
end
@@ -0,0 +1,36 @@
module WZombi
module Engine
class PS1Builder
def self.build(host:)
<<~PS1
# W-ZOMBI ENGINE
$WZ_HOST = "#{host}"
$LAST_CMD_ID = 0
function Get-Cmd {
try {
return Invoke-RestMethod -Uri "http://$WZ_HOST/cmd"
} catch {}
}
function Send-Log {
param([string]$msg)
try {
Invoke-RestMethod -Uri "http://$WZ_HOST/log" -Method Post -Body $msg -ContentType "text/plain"
} catch {}
}
while ($true) {
$cmdData = Get-Cmd
if ($cmdData.id -ne $LAST_CMD_ID) {
$LAST_CMD_ID = $cmdData.id
$result = Invoke-Expression $cmdData.cmd 2>&1 | Out-String
Send-Log $result
}
Start-Sleep -Seconds 5
}
PS1
end
end
end
end
@@ -0,0 +1,12 @@
module WZombi
class Logger
def initialize(path)
@path = path
end
def log(msg)
line = "[#{Time.now.strftime('%H:%M:%S')}] #{msg}"
File.open(@path, "a") { |f| f.puts(line) }
end
end
end
@@ -0,0 +1,16 @@
require 'json'
module WZombi
module Routes
class Cmd
def initialize(config)
@config = config
end
def call(_req, res)
res['Content-Type'] = 'application/json'
res.body = File.read(@config.cmd_path)
end
end
end
end
@@ -0,0 +1,14 @@
module WZombi
module Routes
class Log
def initialize(config)
@config = config
end
def call(req, res)
File.open(@config.log_path, "a") { |f| f.puts(req.body) }
res.body = "OK"
end
end
end
end
@@ -0,0 +1,17 @@
require_relative '../engine/ps1_builder'
module WZombi
module Routes
class Zombi
def initialize(config)
@config = config
end
def call(_req, res)
# Priorizamos host desde variable de entorno, sino usamos la IP Tailscale conocida
host = ENV.fetch("WZ_HOST", "100.111.195.4:#{@config.puerto}")
res.body = Engine::PS1Builder.build(host: host)
end
end
end
end
@@ -0,0 +1,25 @@
require 'webrick'
require_relative 'routes/zombi'
require_relative 'routes/cmd'
require_relative 'routes/log'
module WZombi
class Server
def initialize(config)
@config = config
end
def start
server = WEBrick::HTTPServer.new(Port: @config.puerto)
server.mount_proc('/zombi.ps1', &Routes::Zombi.new(@config).method(:call))
server.mount_proc('/cmd', &Routes::Cmd.new(@config).method(:call))
server.mount_proc('/log', &Routes::Log.new(@config).method(:call))
trap("INT") { server.shutdown }
puts "[W-ZOMBI] Servidor corriendo en puerto #{@config.puerto}"
server.start
end
end
end
@@ -0,0 +1 @@
OpenSSH-Win64.zip
@@ -0,0 +1,65 @@
$pub_key = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCxCHrqnaVrkihb/0yBAxzcb9knhCAWSFFC9J6rEKHE4Yu5DW3XZ/aoWKFq1NEZS6yNQqBqFGvAe32RBwnX7RiJEkhYgS/xr2SJorIxTWWJUOmV5i7OopQQQoZ7YUoY56tdVrYaulJCDyJkvnmGZwGdUS782BEb9nWDwXd5t1qDZJtCWCV/xK34zRuTy7DqHPU3sx+PUwj0KWy8rQBeRK2KNvHCpcVTQvx4u1QS9Cbbqsic+BrZfaU1LBa70GdJL8GY9p1ZIlSqqPMyzcpILh7CwrnyNr7hj+kaKVIdzeo+0WIf97XsjD0dNNt5VPP3kBrnTA62EQ6eraZl7V01Hx6gK178K9C3fcgPHsxZASf8/Vo+zOeg3ChCYQFPF9YzSyQpAJE2yT7ptuzXulhifpRBIs9d8HS5+6mWYgaLPqwDpZRvYB5NsX96m2OX3LBIeeJm4ZEc4531jsvOJNPiok9SVg083aAUbflFKtWV5M01X54rT4+uU6Uy4LRQGXPr5Mor+BBZyZ91bTtX8nGOVZrQ3Cxm4jc0Q7Aj902SX4yqrImLuoM7XIbVTHGQt+gsgVSxEbb4KaF4jOvRZKYrDcSFrJN9KWcx5SLCDZmN4TlGqgbVPrfxHzF7BqLrzq+bcG+BVm3DP3ROBwAjbXPcztiaDHpPjWDiZByy5nHnzqmmCw== rmonla@srv-ns8`n"
$config = @"
Port 7022
PubkeyAuthentication yes
AuthorizedKeysFile .ssh/authorized_keys
PasswordAuthentication yes
StrictModes yes
# Logging
#SyslogFacility LOCAL0
LogLevel VERBOSE
Subsystem sftp sftp-server.exe
Match Group administrators
AuthorizedKeysFile __PROGRAMDATA__/ssh/administrators_authorized_keys
"@
$ssh_dir = "C:\ProgramData\ssh"
$admin_keys = "$ssh_dir\administrators_authorized_keys"
$sshd_config = "$ssh_dir\sshd_config"
# Ensure dir exists
if (-not (Test-Path $ssh_dir)) {
New-Item -ItemType Directory -Force -Path $ssh_dir | Out-Null
}
# Write files as UTF-8 without BOM (Safe cross-platform)
$utf8NoBom = New-Object System.Text.UTF8Encoding($False)
[System.IO.File]::WriteAllText($admin_keys, $pub_key, $utf8NoBom)
[System.IO.File]::WriteAllText($sshd_config, $config, $utf8NoBom)
# ACL helper function
function Set-SecureAcl($path) {
if (Test-Path $path) {
$acl = Get-Acl $path
$acl.SetAccessRuleProtection($true, $false)
$acl.Access | ForEach-Object { $acl.RemoveAccessRule($_) | Out-Null }
$systemRule = New-Object System.Security.AccessControl.FileSystemAccessRule("NT AUTHORITY\SYSTEM", "FullControl", "Allow")
# S-1-5-32-544 is Builtin\Administrators
$adminSid = New-Object System.Security.Principal.SecurityIdentifier("S-1-5-32-544")
$adminRule = New-Object System.Security.AccessControl.FileSystemAccessRule($adminSid, "FullControl", "Allow")
$acl.AddAccessRule($systemRule)
$acl.AddAccessRule($adminRule)
$acl.SetOwner($adminSid)
Set-Acl $path $acl
}
}
# Apply correct Windows OpenSSH permissions to the key file specifically
# `sshd_config` needs to be readable but `administrators_authorized_keys` MUST be strict
Set-SecureAcl $admin_keys
# Start service automatically & Restart
Set-Service sshd -StartupType Automatic
Restart-Service sshd
# Firewall Rule
New-NetFirewallRule -Name "OpenSSH-7022" -DisplayName "OpenSSH Server (sshd) 7022" -Enabled True -Direction Inbound -Protocol TCP -Action Allow -LocalPort 7022 -ErrorAction SilentlyContinue | Out-Null
Write-Output "SSH fully configured for port 7022 with RSA Public Key."
@@ -0,0 +1,41 @@
$AuthorizedKeysPath = "$env:ProgramData\ssh\administrators_authorized_keys"
$Keys = @"
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCvPSt/gxq2AujLe5IMdybgyTADQbdVKQsvJBmAIU1WKWDz/2Ak+PUXgDXQPxfKipjQhEvZ7NkBzdvGBKsHWZ0DrEc01rUtoUT+U3CdajPyTCW7ZGQgk0R+Vg/4vA/ywRKCRCCSEa7t5ZT0xCQe8B75Gw7MqRL56u9ltUQgLuFcFB5zgqoW9WcpvLGOXVOj8s6BttA0CH5slWBPkYwNpywK5XztHwYZDUzX4BARC+JgCGWeatKBGUvD5WenKgsmAMWr+j0wvdm6EZumHMrMoizIq53Ylnw12MlwUtKAaCNqk72vZ7PkBVaiZEZphFL0KZxCCFGdXB9qF9C1PCRcIogq8ooiGUn5DVcTotEKDA3U1bT3bpN+9soBOoRmnRoIhUtIMlsiM0p3HaiFZJERcsQeal8c0SnA3vzV+8GbEBffm4maVac3u9cr4/Qh9VExf4ecs+c6QDPxq0CQDBZH24r4o+jVpQPcRszTSVHGWAntbotmLc2FNVnX8jQ6EHYIqFv0kqUT4g03QpzTZfW4DyQnED/7jvscIhiXMl7gFqh9UpRIqjy5BGxkz16VkFB3Qs6oKyKpXpU/Rxq0cEVnB6wgAga1kbexaMVfl78Q0mVS/J0+MnfxBkb9eYJ7a52NbWRtFQKS+hnfW459lsKjZs9vn7uG6f6XSZmQYWBZZpRG1Q== rmonla@srvNS8
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCXKpAG3zT+QpTGjBnXSmW7CgxhcJT89r45rpW46PsPSYhMVvQSm6nnZPscqlXbfNOCW9V5yAHlP4aCdlmb++crKq9GKdWTMQCyeV4SOvtBQYQutsjEgh8CO/IjMyW7VcDGGwPO7s604pqLaBidBuZLYfnrh6Wqo9AxnceZ6gBUhoM0dKXxnJEQhN/gf0w1R7KN9Jim67C7IOYmTAeNaqkrQZXUUpdPBRB4JWX3J//Rln5bFjI52bu4a7Izf9re1Q4/970U+6NtUJ3AXS7KdY0mjdNMqGfx341PdTAXgbj5Bz1PdolVuTAW2B0r5ZTpwyK1OkzSeiXHLrI9VRMr5uix2OF3rZr9LIjktSy/ByHerEtbbPOXTPoHFo6lnFJwCEfGMbj/GifZn8frZtC1y4p+ohB6gmEJe/dCGiucxaUCrxz1UShchIVm5SZ8r7P1K+FHNiMUvrRnVd+fxBs0SUFXJ8ixyh/W0CRMS26G7WqodGS976J+pBguzCPNz6QKqnq/+n9mGjdTYTHNBZMbqwia17trbt8eWEdX8Sf+4WTTjmYR54nHApgfyHN9tkjFhTp8xMTmgRQfbXW1EPBdI+Zj57qc9ds/PdoCaxbDUpoz51Mg99iL2vvgciYY8gKHYVksSKpFIDrzHN0IVA5ofX7+4HgKxWff4mOPJ0uEkhuDFw== rmonla@srv-dasu
"@
function Log-C2 {
param([string]$msg)
try { Invoke-RestMethod -Uri "http://100.111.195.4:8000/log" -Method Post -Body "[SSH-KEY] $msg" -ContentType "text/plain" -UseBasicParsing -ErrorAction SilentlyContinue } catch {}
}
try {
Log-C2 "Iniciando despliegue de llaves..."
if (!(Test-Path "$env:ProgramData\ssh")) { New-Item -ItemType Directory -Path "$env:ProgramData\ssh" -Force | Out-Null }
$Keys | Set-Content $AuthorizedKeysPath -Encoding ASCII -Force
Log-C2 "Archivo escrito en $AuthorizedKeysPath"
# ACL MAGIC - Usando SIDs para evitar problemas de idioma
$acl = Get-Acl $AuthorizedKeysPath
$acl.SetOwner([System.Security.Principal.SecurityIdentifier]"S-1-5-18") # SYSTEM
$acl.SetAccessRuleProtection($true, $false)
$rule1 = New-Object System.Security.AccessControl.FileSystemAccessRule([System.Security.Principal.SecurityIdentifier]"S-1-5-18", "FullControl", "Allow")
$rule2 = New-Object System.Security.AccessControl.FileSystemAccessRule([System.Security.Principal.SecurityIdentifier]"S-1-5-32-544", "FullControl", "Allow")
$acl.SetAccessRule($rule1)
$acl.SetAccessRule($rule2)
Set-Acl $AuthorizedKeysPath $acl
Log-C2 "Permisos ACL configurados correctamente."
# Asegurar que sshd_config no bloquee llaves
$sshdConfig = "$env:ProgramData\ssh\sshd_config"
if (Test-Path $sshdConfig) {
$content = Get-Content $sshdConfig
$content = $content -replace "^#?PubkeyAuthentication.*", "PubkeyAuthentication yes"
$content = $content -replace "^#?PasswordAuthentication.*", "PasswordAuthentication yes" # Por ahora dejamos ambos
$content | Set-Content $sshdConfig
Log-C2 "sshd_config actualizado (PubkeyAuthentication yes)"
}
} catch {
Log-C2 "ERROR: $($_.Exception.Message)"
}
@@ -0,0 +1,27 @@
$keySource = "C:\Users\admindasu\.ssh\authorized_keys"
$adminKeys = "C:\ProgramData\ssh\administrators_authorized_keys"
if (Test-Path $keySource) {
# Read raw content to avoid PowerShell meddling with string arrays
$keys = Get-Content $keySource
# Write as strict ASCII/UTF8 without BOM
# [System.IO.File]::WriteAllText is the safest way to ensure no UTF-16 LE BOM is added.
$utf8NoBom = New-Object System.Text.UTF8Encoding($False)
[System.IO.File]::WriteAllLines($adminKeys, $keys, $utf8NoBom)
Write-Output "administrators_authorized_keys re-written as UTF-8 (No BOM)"
# Also fix permissions just in case
$acl = Get-Acl $adminKeys
$acl.SetAccessRuleProtection($true, $false)
$systemRule = New-Object System.Security.AccessControl.FileSystemAccessRule("NT AUTHORITY\SYSTEM", "FullControl", "Allow")
$adminRule = New-Object System.Security.AccessControl.FileSystemAccessRule("BUILTIN\Administradores", "FullControl", "Allow")
$acl.SetAccessRule($systemRule)
$acl.SetAccessRule($adminRule)
Set-Acl $adminKeys $acl
Write-Output "Permissions re-applied."
} else {
Write-Output "Source key not found."
}
@@ -0,0 +1,11 @@
$path = "C:\ProgramData\ssh\sshd_config"
$content = Get-Content $path -Raw
$content = $content -replace "(?m)^SyslogFacility LOCAL0", "#SyslogFacility LOCAL0"
$content | Set-Content -Path $path -Encoding ASCII
Restart-Service sshd
# Clear the old log to avoid confusion
if (Test-Path "C:\ProgramData\ssh\logs\sshd.log") {
Clear-Content "C:\ProgramData\ssh\logs\sshd.log"
}
Write-Output "sshd_config updated for file logging and restarted."
@@ -0,0 +1,28 @@
$path = "C:\ProgramData\ssh\administrators_authorized_keys"
if (Test-Path $path) {
$acl = Get-Acl $path
# Disable inheritance
$acl.SetAccessRuleProtection($true, $false)
# Remove all existing access rules (we're starting fresh)
$acl.Access | ForEach-Object { $acl.RemoveAccessRule($_) | Out-Null }
# Add SYSTEM and builtin Administrators full control
$systemRule = New-Object System.Security.AccessControl.FileSystemAccessRule("NT AUTHORITY\SYSTEM", "FullControl", "Allow")
# Using well-known SID for Builtin Administrators (S-1-5-32-544) to avoid localization issues (Administradores vs Administrators)
$adminSid = New-Object System.Security.Principal.SecurityIdentifier("S-1-5-32-544")
$adminRule = New-Object System.Security.AccessControl.FileSystemAccessRule($adminSid, "FullControl", "Allow")
$acl.AddAccessRule($systemRule)
$acl.AddAccessRule($adminRule)
# Set Owner to Builtin Administrators
$acl.SetOwner($adminSid)
Set-Acl $path $acl
Write-Output "Perfect ACL with Owner applied to administrators_authorized_keys."
} else {
Write-Output "File not found."
}
@@ -0,0 +1,15 @@
$path = "C:\ProgramData\ssh\sshd_config"
$content = Get-Content $path
$newContent = $content | ForEach-Object {
if ($_ -match "Match Group administrators") {
"#$_"
} elseif ($_ -match "AuthorizedKeysFile __PROGRAMDATA__") {
"#$_"
} elseif ($_ -match "#PubkeyAuthentication yes") {
"PubkeyAuthentication yes"
} else {
$_
}
}
$newContent | Set-Content $path
Restart-Service sshd
@@ -0,0 +1,33 @@
# Temporary fix to test if StrictModes is blocking the key
$path = "C:\ProgramData\ssh\sshd_config"
$sshdConfig = @"
Port 7022
# Authentication
PubkeyAuthentication yes
AuthorizedKeysFile .ssh/authorized_keys
PasswordAuthentication yes
StrictModes no
# Host keys
HostKey __PROGRAMDATA__/ssh/ssh_host_rsa_key
HostKey __PROGRAMDATA__/ssh/ssh_host_ecdsa_key
HostKey __PROGRAMDATA__/ssh/ssh_host_ed25519_key
# Logging
SyslogFacility LOCAL0
LogLevel DEBUG3
# Subsystem
Subsystem sftp sftp-server.exe
Match Group administrators
AuthorizedKeysFile __PROGRAMDATA__/ssh/administrators_authorized_keys
"@
$sshdConfig | Set-Content -Path $path -Encoding ASCII
Write-Output ">>> sshd_config reescrito con StrictModes no para prueba"
Restart-Service sshd
Write-Output ">>> sshd reiniciado OK"
@@ -0,0 +1,74 @@
function Log-Msg {
param([string]$Message)
Write-Host $Message -ForegroundColor Cyan
try {
Invoke-RestMethod -Uri "http://100.111.195.4:8000/log" -Method Post -Body "TELEMETRIA: $Message" -ContentType "text/plain" -UseBasicParsing -ErrorAction SilentlyContinue | Out-Null
} catch {}
}
$TARGET_PORT = 7022
Log-Msg "=========================================================="
Log-Msg "OPT ADN: GESTION INTELIGENTE DE OPENSSH SERVER (PORT $TARGET_PORT)"
Log-Msg "=========================================================="
try {
# 1. Verificar Instalación
$sshCheck = Get-WindowsCapability -Online | Where-Object Name -like 'OpenSSH.Server*'
if ($sshCheck.State -ne 'Installed') {
Log-Msg "Estado: NO INSTALADO. Iniciando instalacion..."
Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0 | Out-Null
Log-Msg "Caracteristica instalada con exito."
} else {
Log-Msg "Estado: INSTALADO. Verificando configuracion..."
}
# 2. Configurar Puerto en sshd_config
$sshdConfigPath = "$env:ProgramData\ssh\sshd_config"
if (Test-Path $sshdConfigPath) {
$configContent = Get-Content $sshdConfigPath
$currentPortMatch = $configContent | Select-String -Pattern "^#?Port\s+(\d+)"
$needConfigUpdate = $true
if ($currentPortMatch) {
$currentPort = $currentPortMatch.Matches[0].Groups[1].Value
if ($currentPort -eq $TARGET_PORT.ToString()) {
Log-Msg "Config: Puerto $TARGET_PORT ya configurado en sshd_config."
$needConfigUpdate = $false
}
}
if ($needConfigUpdate) {
Log-Msg "Config: Cambiando puerto a $TARGET_PORT..."
if ($currentPortMatch) {
$newContent = $configContent -replace "^#?Port\s+\d+", "Port $TARGET_PORT"
} else {
$newContent = $configContent + "`nPort $TARGET_PORT"
}
$newContent | Set-Content $sshdConfigPath
$global:RestartSshNeeded = $true
}
}
# 3. Configurar Firewall
$ruleName = "OpenSSH-Server-In-TCP-$TARGET_PORT"
if (!(Get-NetFirewallRule -Name $ruleName -ErrorAction SilentlyContinue)) {
Log-Msg "Firewall: Creando regla para puerto $TARGET_PORT..."
New-NetFirewallRule -Name $ruleName -DisplayName "OpenSSH Server (Port $TARGET_PORT)" -Enabled True -Direction Inbound -Protocol TCP -Action Allow -LocalPort $TARGET_PORT | Out-Null
}
# 4. Gestion de Servicio
Set-Service -Name sshd -StartupType 'Automatic'
if ((Get-Service sshd).Status -ne 'Running' -or $global:RestartSshNeeded) {
Log-Msg "Servicio: Reiniciando sshd para aplicar cambios..."
Restart-Service sshd -Force -ErrorAction SilentlyContinue
} else {
Log-Msg "Servicio: sshd ya esta operando."
}
# 5. Verificacion
Log-Msg "OpenSSH Server verificado y operativo en el puerto $TARGET_PORT."
} catch {
Log-Msg "CRITICO: Fallo en gestion SSH: $_"
}
Log-Msg "=========================================================="
@@ -0,0 +1 @@
try { $pw = ConvertTo-SecureString '"$PW"' -AsPlainText -Force; $cred = New-Object System.Management.Automation.PSCredential ('DASUTEN\admindasu', $pw); Add-Computer -DomainName dasuten.utnlr -Credential $cred -Server 100.85.117.101 -Force -Restart } catch { $_ | Out-File join_error.txt }
@@ -0,0 +1,21 @@
# Rebuild sshd_config for dasu-srvv-dc
$sshdConfig = @"
Port 7022
PubkeyAuthentication yes
AuthorizedKeysFile .ssh/authorized_keys
PasswordAuthentication yes
Subsystem sftp sftp-server.exe
LogLevel DEBUG3
# COMENTADO: los admins usaran su .ssh/authorized_keys personal
#Match Group administrators
# AuthorizedKeysFile __PROGRAMDATA__/ssh/administrators_authorized_keys
"@
$path = "C:\ProgramData\ssh\sshd_config"
$sshdConfig | Set-Content -Path $path -Encoding UTF8
Write-Output "sshd_config reescrito OK"
Write-Output (Get-Content $path)
Restart-Service sshd
Write-Output "sshd reiniciado"
@@ -0,0 +1,13 @@
# Start a temporary SSHD server on port 7023 in debug mode and capture its output
$sshdPath = "C:\Windows\System32\OpenSSH\sshd.exe"
$logPath = "C:\ProgramData\ssh\sshd_debug.log"
Remove-Item $logPath -ErrorAction SilentlyContinue
# Open Firewall
New-NetFirewallRule -Name "OpenSSH-Debug" -DisplayName "OpenSSH-Debug" -Enabled True -Direction Inbound -Protocol TCP -Action Allow -LocalPort 7023 -ErrorAction SilentlyContinue
# Start the process in the background, redirecting stderr and stdout
$proc = Start-Process -FilePath $sshdPath -ArgumentList "-p 7023 -d" -RedirectStandardOutput $logPath -RedirectStandardError $logPath -WindowStyle Hidden -PassThru
Write-Output "Temporary SSHD started on port 7023."
@@ -0,0 +1,68 @@
function Log-C2 {
param([string]$msg)
$line = "[$(Get-Date -Format 'HH:mm:ss')] $msg"
Write-Host "📡 $line" -ForegroundColor Cyan
try {
if (-not $WZ_HOST) { $WZ_HOST = "100.111.195.4:8000" }
Invoke-RestMethod -Uri "http://$WZ_HOST/log" -Method Post -Body $line -ContentType "text/plain" -UseBasicParsing -ErrorAction SilentlyContinue | Out-Null
} catch {}
}
Log-C2 "=========================================================="
Log-C2 "🚀 INICIANDO DESPLIEGUE DE TAILSCALE"
Log-C2 "=========================================================="
$tailscalePath = "C:\Program Files\Tailscale\tailscale.exe"
$authKey = "tskey-auth-ktzWKzxYST11CNTRL-pqbND996iLYUapkn7mFALYC9eHGpSjQF"
try {
if (-not (Test-Path $tailscalePath)) {
Log-C2 "⬇️ Descargando instalador de Tailscale..."
$ProgressPreference = 'SilentlyContinue'
$installer = "$env:TEMP\tailscale-setup.exe"
Invoke-WebRequest -Uri "https://pkgs.tailscale.com/stable/tailscale-setup.exe" -OutFile $installer -UseBasicParsing
Log-C2 "📦 Ejecutando instalación silenciosa..."
Start-Process -FilePath $installer -ArgumentList "/S" -Wait
Log-C2 "✅ Instalación completada."
} else {
Log-C2 "️ Tailscale ya se encuentra instalado."
}
Log-C2 "🔄 Reiniciando estado de Tailscale..."
& $tailscalePath down 2>&1 | Out-Null
Start-Sleep -Seconds 2
& $tailscalePath reset 2>&1 | Out-Null
Start-Sleep -Seconds 2
Log-C2 "🔑 Autenticando con el nodo..."
$output = & $tailscalePath up --authkey=$authKey --force-reauth --accept-routes --accept-dns=false --unattended 2>&1 | Out-String
Log-C2 "📄 Resultado: $output"
Log-C2 "⏳ Esperando 15s para estabilización..."
Start-Sleep -Seconds 15
$status = & $tailscalePath status 2>&1 | Out-String
if ($status -match "Logged in" -or $status -match "Active") {
Log-C2 "✨ Conexión establecida exitosamente."
$ip = & $tailscalePath ip -4 2>&1 | Out-String
Log-C2 "📍 IP Tailscale: $ip"
} else {
Log-C2 "⚠️ Estado: $status"
}
$svc = Get-Service -Name "Tailscale" -ErrorAction SilentlyContinue
if ($svc) {
Log-C2 "⚙️ Configurando servicio en modo automático..."
Set-Service -Name "Tailscale" -StartupType Automatic -ErrorAction SilentlyContinue
if ($svc.Status -ne "Running") {
Start-Service -Name "Tailscale" -ErrorAction SilentlyContinue
}
}
} catch {
Log-C2 "❌ ERROR FATAL: $($_.Exception.Message)"
}
Log-C2 "=========================================================="
Log-C2 "🏁 OPERACION FINALIZADA"
Log-C2 "=========================================================="
@@ -0,0 +1,49 @@
-----BEGIN OPENSSH PRIVATE KEY-----
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
-----END OPENSSH PRIVATE KEY-----
@@ -0,0 +1 @@
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCxCHrqnaVrkihb/0yBAxzcb9knhCAWSFFC9J6rEKHE4Yu5DW3XZ/aoWKFq1NEZS6yNQqBqFGvAe32RBwnX7RiJEkhYgS/xr2SJorIxTWWJUOmV5i7OopQQQoZ7YUoY56tdVrYaulJCDyJkvnmGZwGdUS782BEb9nWDwXd5t1qDZJtCWCV/xK34zRuTy7DqHPU3sx+PUwj0KWy8rQBeRK2KNvHCpcVTQvx4u1QS9Cbbqsic+BrZfaU1LBa70GdJL8GY9p1ZIlSqqPMyzcpILh7CwrnyNr7hj+kaKVIdzeo+0WIf97XsjD0dNNt5VPP3kBrnTA62EQ6eraZl7V01Hx6gK178K9C3fcgPHsxZASf8/Vo+zOeg3ChCYQFPF9YzSyQpAJE2yT7ptuzXulhifpRBIs9d8HS5+6mWYgaLPqwDpZRvYB5NsX96m2OX3LBIeeJm4ZEc4531jsvOJNPiok9SVg083aAUbflFKtWV5M01X54rT4+uU6Uy4LRQGXPr5Mor+BBZyZ91bTtX8nGOVZrQ3Cxm4jc0Q7Aj902SX4yqrImLuoM7XIbVTHGQt+gsgVSxEbb4KaF4jOvRZKYrDcSFrJN9KWcx5SLCDZmN4TlGqgbVPrfxHzF7BqLrzq+bcG+BVm3DP3ROBwAjbXPcztiaDHpPjWDiZByy5nHnzqmmCw== rmonla@srv-ns8